xref: /illumos-gate/usr/src/common/ficl/loader.c (revision 495ee6847d0d3e288f47ba026d98a830e51cbc06)
1 /*
2  * Copyright (c) 2000 Daniel Capo Sobral
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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.
13  *
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
24  * SUCH DAMAGE.
25  *
26  *	$FreeBSD$
27  */
28 
29 /*
30  * l o a d e r . c
31  * Additional FICL words designed for FreeBSD's loader
32  */
33 
34 #ifndef STAND
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <dirent.h>
38 #include <fcntl.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <unistd.h>
42 #include <strings.h>
43 #include <termios.h>
44 #else
45 #include <stand.h>
46 #ifdef __i386__
47 #include <machine/cpufunc.h>
48 #endif
49 #include "bootstrap.h"
50 #endif
51 #ifdef STAND
52 #include <uuid.h>
53 #else
54 #include <uuid/uuid.h>
55 #endif
56 #include <string.h>
57 #include "ficl.h"
58 
59 /*
60  *		FreeBSD's loader interaction words and extras
61  *
62  *		setenv      ( value n name n' -- )
63  *		setenv?     ( value n name n' flag -- )
64  *		getenv      ( addr n -- addr' n' | -1 )
65  *		unsetenv    ( addr n -- )
66  *		copyin      ( addr addr' len -- )
67  *		copyout     ( addr addr' len -- )
68  *		findfile    ( name len type len' -- addr )
69  *		ccall       ( [[...[p10] p9] ... p1] n addr -- result )
70  *		uuid-from-string ( addr n -- addr' )
71  *		uuid-to-string ( addr' -- addr n | -1 )
72  *		.#	    ( value -- )
73  */
74 
75 void
76 ficlSetenv(ficlVm *pVM)
77 {
78 	char *name, *value;
79 	char *namep, *valuep;
80 	int names, values;
81 
82 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 0);
83 
84 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
85 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
86 	values = ficlStackPopInteger(ficlVmGetDataStack(pVM));
87 	valuep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
88 
89 	name = (char *)ficlMalloc(names+1);
90 	if (!name)
91 		ficlVmThrowError(pVM, "Error: out of memory");
92 	strncpy(name, namep, names);
93 	name[names] = '\0';
94 	value = (char *)ficlMalloc(values+1);
95 	if (!value)
96 		ficlVmThrowError(pVM, "Error: out of memory");
97 	strncpy(value, valuep, values);
98 	value[values] = '\0';
99 
100 	setenv(name, value, 1);
101 	ficlFree(name);
102 	ficlFree(value);
103 }
104 
105 void
106 ficlSetenvq(ficlVm *pVM)
107 {
108 	char *name, *value;
109 	char *namep, *valuep;
110 	int names, values, overwrite;
111 
112 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 5, 0);
113 
114 	overwrite = ficlStackPopInteger(ficlVmGetDataStack(pVM));
115 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
116 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
117 	values = ficlStackPopInteger(ficlVmGetDataStack(pVM));
118 	valuep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
119 
120 	name = (char *)ficlMalloc(names+1);
121 	if (!name)
122 		ficlVmThrowError(pVM, "Error: out of memory");
123 	strncpy(name, namep, names);
124 	name[names] = '\0';
125 	value = (char *)ficlMalloc(values+1);
126 	if (!value)
127 		ficlVmThrowError(pVM, "Error: out of memory");
128 	strncpy(value, valuep, values);
129 	value[values] = '\0';
130 
131 	setenv(name, value, overwrite);
132 	ficlFree(name);
133 	ficlFree(value);
134 }
135 
136 void
137 ficlGetenv(ficlVm *pVM)
138 {
139 	char *name, *value;
140 	char *namep;
141 	int names;
142 
143 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 2);
144 
145 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
146 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
147 
148 	name = (char *)ficlMalloc(names+1);
149 	if (!name)
150 		ficlVmThrowError(pVM, "Error: out of memory");
151 	strncpy(name, namep, names);
152 	name[names] = '\0';
153 
154 	value = getenv(name);
155 	ficlFree(name);
156 
157 	if (value != NULL) {
158 		ficlStackPushPointer(ficlVmGetDataStack(pVM), value);
159 		ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(value));
160 	} else
161 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
162 }
163 
164 void
165 ficlUnsetenv(ficlVm *pVM)
166 {
167 	char *name;
168 	char *namep;
169 	int names;
170 
171 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
172 
173 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
174 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
175 
176 	name = (char *)ficlMalloc(names+1);
177 	if (!name)
178 		ficlVmThrowError(pVM, "Error: out of memory");
179 	strncpy(name, namep, names);
180 	name[names] = '\0';
181 
182 	unsetenv(name);
183 	ficlFree(name);
184 }
185 
186 void
187 ficlCopyin(ficlVm *pVM)
188 {
189 #ifdef STAND
190 	void*		src;
191 	vm_offset_t	dest;
192 	size_t		len;
193 #endif
194 
195 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 0);
196 
197 #ifdef STAND
198 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
199 	dest = ficlStackPopInteger(ficlVmGetDataStack(pVM));
200 	src = ficlStackPopPointer(ficlVmGetDataStack(pVM));
201 	archsw.arch_copyin(src, dest, len);
202 #else
203 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
204 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
205 	(void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
206 #endif
207 }
208 
209 void
210 ficlCopyout(ficlVm *pVM)
211 {
212 #ifdef STAND
213 	void*		dest;
214 	vm_offset_t	src;
215 	size_t		len;
216 #endif
217 
218 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 0);
219 
220 #ifdef STAND
221 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
222 	dest = ficlStackPopPointer(ficlVmGetDataStack(pVM));
223 	src = ficlStackPopInteger(ficlVmGetDataStack(pVM));
224 	archsw.arch_copyout(src, dest, len);
225 #else
226 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
227 	(void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
228 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
229 #endif
230 }
231 
232 void
233 ficlFindfile(ficlVm *pVM)
234 {
235 #ifdef STAND
236 	char	*name, *type;
237 	char	*namep, *typep;
238 	int	names, types;
239 #endif
240 	struct	preloaded_file *fp;
241 
242 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 4, 1);
243 
244 #ifdef STAND
245 	types = ficlStackPopInteger(ficlVmGetDataStack(pVM));
246 	typep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
247 	names = ficlStackPopInteger(ficlVmGetDataStack(pVM));
248 	namep = (char *)ficlStackPopPointer(ficlVmGetDataStack(pVM));
249 
250 	name = (char *)ficlMalloc(names+1);
251 	if (!name)
252 		ficlVmThrowError(pVM, "Error: out of memory");
253 	strncpy(name, namep, names);
254 	name[names] = '\0';
255 	type = (char *)ficlMalloc(types+1);
256 	if (!type)
257 		ficlVmThrowError(pVM, "Error: out of memory");
258 	strncpy(type, typep, types);
259 	type[types] = '\0';
260 
261 	fp = file_findfile(name, type);
262 #else
263 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
264 	(void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
265 	(void) ficlStackPopInteger(ficlVmGetDataStack(pVM));
266 	(void) ficlStackPopPointer(ficlVmGetDataStack(pVM));
267 
268 	fp = NULL;
269 #endif
270 	ficlStackPushPointer(ficlVmGetDataStack(pVM), fp);
271 }
272 
273 void
274 ficlCcall(ficlVm *pVM)
275 {
276 	int (*func)(int, ...);
277 	int result, p[10];
278 	int nparam, i;
279 
280 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
281 
282 	func = (int (*)(int, ...))ficlStackPopPointer(ficlVmGetDataStack(pVM));
283 	nparam = ficlStackPopInteger(ficlVmGetDataStack(pVM));
284 
285 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), nparam, 1);
286 
287 	for (i = 0; i < nparam; i++)
288 		p[i] = ficlStackPopInteger(ficlVmGetDataStack(pVM));
289 
290 	result = func(p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
291 	    p[9]);
292 
293 	ficlStackPushInteger(ficlVmGetDataStack(pVM), result);
294 }
295 
296 void
297 ficlUuidFromString(ficlVm *pVM)
298 {
299 	char	*uuid;
300 	char	*uuid_ptr;
301 	int	uuid_size;
302 	uuid_t	*u;
303 #ifdef STAND
304 	uint32_t status;
305 #else
306 	int status;
307 #endif
308 
309 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 0);
310 
311 	uuid_size = ficlStackPopInteger(ficlVmGetDataStack(pVM));
312 	uuid_ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM));
313 
314 	uuid = ficlMalloc(uuid_size + 1);
315 	if (!uuid)
316 		ficlVmThrowError(pVM, "Error: out of memory");
317 	(void) memcpy(uuid, uuid_ptr, uuid_size);
318 	uuid[uuid_size] = '\0';
319 
320 	u = ficlMalloc(sizeof (*u));
321 #ifdef STAND
322 	uuid_from_string(uuid, u, &status);
323 	ficlFree(uuid);
324 	if (status != uuid_s_ok) {
325 		ficlFree(u);
326 		u = NULL;
327 	}
328 #else
329 	status = uuid_parse(uuid, *u);
330 	ficlFree(uuid);
331 	if (status != 0) {
332 		ficlFree(u);
333 		u = NULL;
334 	}
335 #endif
336 	ficlStackPushPointer(ficlVmGetDataStack(pVM), u);
337 }
338 
339 void
340 ficlUuidToString(ficlVm *pVM)
341 {
342 	char	*uuid;
343 	uuid_t	*u;
344 #ifdef STAND
345 	uint32_t status;
346 #endif
347 
348 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
349 
350 	u = ficlStackPopPointer(ficlVmGetDataStack(pVM));
351 #ifdef STAND
352 	uuid_to_string(u, &uuid, &status);
353 	if (status == uuid_s_ok) {
354 		ficlStackPushPointer(ficlVmGetDataStack(pVM), uuid);
355 		ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(uuid));
356 	} else
357 #else
358 	uuid = ficlMalloc(UUID_PRINTABLE_STRING_LENGTH);
359 	if (uuid != NULL) {
360 		uuid_unparse(*u, uuid);
361 		ficlStackPushPointer(ficlVmGetDataStack(pVM), uuid);
362 		ficlStackPushInteger(ficlVmGetDataStack(pVM), strlen(uuid));
363 	} else
364 #endif
365 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
366 }
367 
368 /*
369  * f i c l E x e c F D
370  * reads in text from file fd and passes it to ficlExec()
371  * returns FICL_VM_STATUS_OUT_OF_TEXT on success or the ficlExec() error
372  * code on failure.
373  */
374 #define	nLINEBUF	256
375 int
376 ficlExecFD(ficlVm *pVM, int fd)
377 {
378 	char cp[nLINEBUF];
379 	int nLine = 0, rval = FICL_VM_STATUS_OUT_OF_TEXT;
380 	char ch;
381 	ficlCell id;
382 	ficlString s;
383 
384 	id = pVM->sourceId;
385 	pVM->sourceId.i = fd+1; /* in loader we can get 0, there is no stdin */
386 
387 	/* feed each line to ficlExec */
388 	while (1) {
389 		int status, i;
390 
391 		i = 0;
392 		while ((status = read(fd, &ch, 1)) > 0 && ch != '\n')
393 			cp[i++] = ch;
394 		nLine++;
395 		if (!i) {
396 			if (status < 1)
397 				break;
398 			continue;
399 		}
400 		if (cp[i] == '\n')
401 			cp[i] = '\0';
402 
403 		FICL_STRING_SET_POINTER(s, cp);
404 		FICL_STRING_SET_LENGTH(s, i);
405 
406 		rval = ficlVmExecuteString(pVM, s);
407 		if (rval != FICL_VM_STATUS_QUIT &&
408 		    rval != FICL_VM_STATUS_USER_EXIT &&
409 		    rval != FICL_VM_STATUS_OUT_OF_TEXT) {
410 			pVM->sourceId = id;
411 			(void) ficlVmEvaluate(pVM, "");
412 			return (rval);
413 		}
414 	}
415 	pVM->sourceId = id;
416 
417 	/*
418 	 * Pass an empty line with SOURCE-ID == -1 to flush
419 	 * any pending REFILLs (as required by FILE wordset)
420 	 */
421 	(void) ficlVmEvaluate(pVM, "");
422 
423 	if (rval == FICL_VM_STATUS_USER_EXIT)
424 		ficlVmThrow(pVM, FICL_VM_STATUS_USER_EXIT);
425 
426 	return (rval);
427 }
428 
429 static void displayCellNoPad(ficlVm *pVM)
430 {
431 	ficlCell c;
432 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
433 
434 	c = ficlStackPop(ficlVmGetDataStack(pVM));
435 	ficlLtoa((c).i, pVM->pad, pVM->base);
436 	ficlVmTextOut(pVM, pVM->pad);
437 }
438 
439 /*
440  * isdir? - Return whether an fd corresponds to a directory.
441  *
442  * isdir? ( fd -- bool )
443  */
444 static void
445 isdirQuestion(ficlVm *pVM)
446 {
447 	struct stat sb;
448 	ficlInteger flag;
449 	int fd;
450 
451 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1);
452 
453 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
454 	flag = FICL_FALSE;
455 	do {
456 		if (fd < 0)
457 			break;
458 		if (fstat(fd, &sb) < 0)
459 			break;
460 		if (!S_ISDIR(sb.st_mode))
461 			break;
462 		flag = FICL_TRUE;
463 	} while (0);
464 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
465 }
466 
467 /*
468  * fopen - open a file and return new fd on stack.
469  *
470  * fopen ( ptr count mode -- fd )
471  */
472 extern char *get_dev(const char *);
473 
474 static void
475 pfopen(ficlVm *pVM)
476 {
477 	int mode, fd, count;
478 	char *ptr, *name;
479 #ifndef STAND
480 	char *tmp;
481 #endif
482 
483 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
484 
485 	mode = ficlStackPopInteger(ficlVmGetDataStack(pVM));	/* get mode */
486 	count = ficlStackPopInteger(ficlVmGetDataStack(pVM));	/* get count */
487 	ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM));	/* get ptr */
488 
489 	if ((count < 0) || (ptr == NULL)) {
490 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
491 		return;
492 	}
493 
494 	/* ensure that the string is null terminated */
495 	name = (char *)malloc(count+1);
496 	bcopy(ptr, name, count);
497 	name[count] = 0;
498 #ifndef STAND
499 	tmp = get_dev(name);
500 	free(name);
501 	name = tmp;
502 #endif
503 
504 	/* open the file */
505 	fd = open(name, mode);
506 	free(name);
507 	ficlStackPushInteger(ficlVmGetDataStack(pVM), fd);
508 }
509 
510 /*
511  * fclose - close a file who's fd is on stack.
512  * fclose ( fd -- )
513  */
514 static void
515 pfclose(ficlVm *pVM)
516 {
517 	int fd;
518 
519 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
520 
521 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
522 	if (fd != -1)
523 		close(fd);
524 }
525 
526 /*
527  * fread - read file contents
528  * fread  ( fd buf nbytes  -- nread )
529  */
530 static void
531 pfread(ficlVm *pVM)
532 {
533 	int fd, len;
534 	char *buf;
535 
536 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
537 
538 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM));
539 	buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */
540 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
541 	if (len > 0 && buf && fd != -1)
542 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
543 		    read(fd, buf, len));
544 	else
545 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
546 }
547 
548 /*
549  * fopendir - open directory
550  *
551  * fopendir ( addr len -- ptr TRUE | FALSE )
552  */
553 static void pfopendir(ficlVm *pVM)
554 {
555 #ifndef STAND
556 	DIR *dir;
557 	char *tmp;
558 #else
559 	struct stat sb;
560 	int fd;
561 #endif
562 	int count;
563 	char *ptr, *name;
564 	ficlInteger flag = FICL_FALSE;
565 
566 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 2, 1);
567 
568 	count = ficlStackPopInteger(ficlVmGetDataStack(pVM));
569 	ptr = ficlStackPopPointer(ficlVmGetDataStack(pVM));	/* get ptr */
570 
571 	if ((count < 0) || (ptr == NULL)) {
572 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
573 		return;
574 	}
575 	/* ensure that the string is null terminated */
576 	name = (char *)malloc(count+1);
577 	bcopy(ptr, name, count);
578 	name[count] = 0;
579 #ifndef STAND
580 	tmp = get_dev(name);
581 	free(name);
582 	name = tmp;
583 #else
584 	fd = open(name, O_RDONLY);
585 	free(name);
586 	do {
587 		if (fd < 0)
588 			break;
589 		if (fstat(fd, &sb) < 0)
590 			break;
591 		if (!S_ISDIR(sb.st_mode))
592 			break;
593 		flag = FICL_TRUE;
594 		ficlStackPushInteger(ficlVmGetDataStack(pVM), fd);
595 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
596 		return;
597 	} while (0);
598 
599 	if (fd >= 0)
600 		close(fd);
601 
602 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
603 		return;
604 #endif
605 #ifndef STAND
606 	dir = opendir(name);
607 	if (dir == NULL) {
608 		ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
609 		return;
610 	} else
611 		flag = FICL_TRUE;
612 
613 	ficlStackPushPointer(ficlVmGetDataStack(pVM), dir);
614 	ficlStackPushInteger(ficlVmGetDataStack(pVM), flag);
615 #endif
616 }
617 
618 /*
619  * freaddir - read directory contents
620  * freaddir ( fd -- ptr len TRUE | FALSE )
621  */
622 static void
623 pfreaddir(ficlVm *pVM)
624 {
625 #ifndef STAND
626 	static DIR *dir = NULL;
627 #else
628 	int fd;
629 #endif
630 	struct dirent *d = NULL;
631 
632 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 3);
633 	/*
634 	 * libstand readdir does not always return . nor .. so filter
635 	 * them out to have consistent behaviour.
636 	 */
637 #ifndef STAND
638 	dir = ficlStackPopPointer(ficlVmGetDataStack(pVM));
639 	if (dir != NULL)
640 		do {
641 			d = readdir(dir);
642 			if (d != NULL && strcmp(d->d_name, ".") == 0)
643 				continue;
644 			if (d != NULL && strcmp(d->d_name, "..") == 0)
645 				continue;
646 			break;
647 		} while (d != NULL);
648 #else
649 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
650 	if (fd != -1)
651 		do {
652 			d = readdirfd(fd);
653 			if (d != NULL && strcmp(d->d_name, ".") == 0)
654 				continue;
655 			if (d != NULL && strcmp(d->d_name, "..") == 0)
656 				continue;
657 			break;
658 		} while (d != NULL);
659 #endif
660 	if (d != NULL) {
661 		ficlStackPushPointer(ficlVmGetDataStack(pVM), d->d_name);
662 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
663 		    strlen(d->d_name));
664 		ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_TRUE);
665 	} else {
666 		ficlStackPushInteger(ficlVmGetDataStack(pVM), FICL_FALSE);
667 	}
668 }
669 
670 /*
671  * fclosedir - close a dir on stack.
672  *
673  * fclosedir ( fd -- )
674  */
675 static void
676 pfclosedir(ficlVm *pVM)
677 {
678 #ifndef STAND
679 	DIR *dir;
680 #else
681 	int fd;
682 #endif
683 
684 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
685 
686 #ifndef STAND
687 	dir = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get dir */
688 	if (dir != NULL)
689 		closedir(dir);
690 #else
691 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
692 	if (fd != -1)
693 		close(fd);
694 #endif
695 }
696 
697 /*
698  * fload - interpret file contents
699  *
700  * fload  ( fd -- )
701  */
702 static void pfload(ficlVm *pVM)
703 {
704 	int fd;
705 
706 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
707 
708 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
709 	if (fd != -1)
710 		ficlExecFD(pVM, fd);
711 }
712 
713 /*
714  * fwrite - write file contents
715  *
716  * fwrite  ( fd buf nbytes  -- nwritten )
717  */
718 static void
719 pfwrite(ficlVm *pVM)
720 {
721 	int fd, len;
722 	char *buf;
723 
724 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
725 
726 	len = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* bytes to read */
727 	buf = ficlStackPopPointer(ficlVmGetDataStack(pVM)); /* get buffer */
728 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM)); /* get fd */
729 	if (len > 0 && buf && fd != -1)
730 		ficlStackPushInteger(ficlVmGetDataStack(pVM),
731 		    write(fd, buf, len));
732 	else
733 		ficlStackPushInteger(ficlVmGetDataStack(pVM), -1);
734 }
735 
736 /*
737  * fseek - seek to a new position in a file
738  *
739  * fseek  ( fd ofs whence  -- pos )
740  */
741 static void
742 pfseek(ficlVm *pVM)
743 {
744 	int fd, pos, whence;
745 
746 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 3, 1);
747 
748 	whence = ficlStackPopInteger(ficlVmGetDataStack(pVM));
749 	pos = ficlStackPopInteger(ficlVmGetDataStack(pVM));
750 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
751 	ficlStackPushInteger(ficlVmGetDataStack(pVM), lseek(fd, pos, whence));
752 }
753 
754 /*
755  * key - get a character from stdin
756  *
757  * key ( -- char )
758  */
759 static void
760 key(ficlVm *pVM)
761 {
762 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
763 
764 	ficlStackPushInteger(ficlVmGetDataStack(pVM), getchar());
765 }
766 
767 /*
768  * key? - check for a character from stdin (FACILITY)
769  * key? ( -- flag )
770  */
771 static void
772 keyQuestion(ficlVm *pVM)
773 {
774 #ifndef STAND
775 	char ch = -1;
776 	struct termios oldt;
777 	struct termios newt;
778 #endif
779 
780 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
781 
782 #ifndef STAND
783 	tcgetattr(STDIN_FILENO, &oldt);
784 	newt = oldt;
785 	newt.c_lflag &= ~(ICANON | ECHO);
786 	newt.c_cc[VMIN] = 0;
787 	newt.c_cc[VTIME] = 0;
788 	tcsetattr(STDIN_FILENO, TCSANOW, &newt);
789 	ch = getchar();
790 	tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
791 
792 	if (ch != -1)
793 		(void) ungetc(ch, stdin);
794 
795 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
796 	    ch != -1? FICL_TRUE : FICL_FALSE);
797 #else
798 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
799 	    ischar()? FICL_TRUE : FICL_FALSE);
800 #endif
801 }
802 
803 /*
804  * seconds - gives number of seconds since beginning of time
805  *
806  * beginning of time is defined as:
807  *
808  *	BTX	- number of seconds since midnight
809  *	FreeBSD	- number of seconds since Jan 1 1970
810  *
811  * seconds ( -- u )
812  */
813 static void
814 pseconds(ficlVm *pVM)
815 {
816 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 0, 1);
817 
818 	ficlStackPushUnsigned(ficlVmGetDataStack(pVM),
819 	    (ficlUnsigned) time(NULL));
820 }
821 
822 /*
823  * ms - wait at least that many milliseconds (FACILITY)
824  * ms ( u -- )
825  */
826 static void
827 ms(ficlVm *pVM)
828 {
829 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 0);
830 
831 #ifndef STAND
832 	usleep(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
833 #else
834 	delay(ficlStackPopUnsigned(ficlVmGetDataStack(pVM)) * 1000);
835 #endif
836 }
837 
838 /*
839  * fkey - get a character from a file
840  * fkey ( file -- char )
841  */
842 static void
843 fkey(ficlVm *pVM)
844 {
845 	int i, fd;
846 	char ch;
847 
848 	FICL_STACK_CHECK(ficlVmGetDataStack(pVM), 1, 1);
849 
850 	fd = ficlStackPopInteger(ficlVmGetDataStack(pVM));
851 	i = read(fd, &ch, 1);
852 	ficlStackPushInteger(ficlVmGetDataStack(pVM), i > 0 ? ch : -1);
853 }
854 
855 
856 #ifdef STAND
857 #ifdef __i386__
858 
859 /*
860  * outb ( port# c -- )
861  * Store a byte to I/O port number port#
862  */
863 void
864 ficlOutb(ficlVm *pVM)
865 {
866 	uint8_t c;
867 	uint32_t port;
868 
869 	port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
870 	c = ficlStackPopInteger(ficlVmGetDataStack(pVM));
871 	outb(port, c);
872 }
873 
874 /*
875  * inb ( port# -- c )
876  * Fetch a byte from I/O port number port#
877  */
878 void
879 ficlInb(ficlVm *pVM)
880 {
881 	uint8_t c;
882 	uint32_t port;
883 
884 	port = ficlStackPopUnsigned(ficlVmGetDataStack(pVM));
885 	c = inb(port);
886 	ficlStackPushInteger(ficlVmGetDataStack(pVM), c);
887 }
888 #endif
889 #endif
890 
891 /*
892  * Retrieves free space remaining on the dictionary
893  */
894 static void
895 freeHeap(ficlVm *pVM)
896 {
897 	ficlStackPushInteger(ficlVmGetDataStack(pVM),
898 	    ficlDictionaryCellsAvailable(ficlVmGetDictionary(pVM)));
899 }
900 
901 /*
902  * f i c l C o m p i l e P l a t f o r m
903  * Build FreeBSD platform extensions into the system dictionary
904  */
905 void
906 ficlSystemCompilePlatform(ficlSystem *pSys)
907 {
908 	ficlDictionary *dp = ficlSystemGetDictionary(pSys);
909 	ficlDictionary *env = ficlSystemGetEnvironment(pSys);
910 #ifdef STAND
911 	ficlCompileFcn **fnpp;
912 #endif
913 
914 	FICL_SYSTEM_ASSERT(pSys, dp);
915 	FICL_SYSTEM_ASSERT(pSys, env);
916 
917 	ficlDictionarySetPrimitive(dp, ".#", displayCellNoPad,
918 	    FICL_WORD_DEFAULT);
919 	ficlDictionarySetPrimitive(dp, "isdir?", isdirQuestion,
920 	    FICL_WORD_DEFAULT);
921 	ficlDictionarySetPrimitive(dp, "fopen", pfopen, FICL_WORD_DEFAULT);
922 	ficlDictionarySetPrimitive(dp, "fclose", pfclose, FICL_WORD_DEFAULT);
923 	ficlDictionarySetPrimitive(dp, "fread", pfread, FICL_WORD_DEFAULT);
924 	ficlDictionarySetPrimitive(dp, "fopendir", pfopendir,
925 	    FICL_WORD_DEFAULT);
926 	ficlDictionarySetPrimitive(dp, "freaddir", pfreaddir,
927 	    FICL_WORD_DEFAULT);
928 	ficlDictionarySetPrimitive(dp, "fclosedir", pfclosedir,
929 	    FICL_WORD_DEFAULT);
930 	ficlDictionarySetPrimitive(dp, "fload", pfload, FICL_WORD_DEFAULT);
931 	ficlDictionarySetPrimitive(dp, "fkey", fkey, FICL_WORD_DEFAULT);
932 	ficlDictionarySetPrimitive(dp, "fseek", pfseek, FICL_WORD_DEFAULT);
933 	ficlDictionarySetPrimitive(dp, "fwrite", pfwrite, FICL_WORD_DEFAULT);
934 	ficlDictionarySetPrimitive(dp, "key", key, FICL_WORD_DEFAULT);
935 	ficlDictionarySetPrimitive(dp, "key?", keyQuestion, FICL_WORD_DEFAULT);
936 	ficlDictionarySetPrimitive(dp, "ms", ms, FICL_WORD_DEFAULT);
937 	ficlDictionarySetPrimitive(dp, "seconds", pseconds, FICL_WORD_DEFAULT);
938 	ficlDictionarySetPrimitive(dp, "heap?", freeHeap, FICL_WORD_DEFAULT);
939 
940 	ficlDictionarySetPrimitive(dp, "setenv", ficlSetenv, FICL_WORD_DEFAULT);
941 	ficlDictionarySetPrimitive(dp, "setenv?", ficlSetenvq,
942 	    FICL_WORD_DEFAULT);
943 	ficlDictionarySetPrimitive(dp, "getenv", ficlGetenv, FICL_WORD_DEFAULT);
944 	ficlDictionarySetPrimitive(dp, "unsetenv", ficlUnsetenv,
945 	    FICL_WORD_DEFAULT);
946 	ficlDictionarySetPrimitive(dp, "copyin", ficlCopyin, FICL_WORD_DEFAULT);
947 	ficlDictionarySetPrimitive(dp, "copyout", ficlCopyout,
948 	    FICL_WORD_DEFAULT);
949 	ficlDictionarySetPrimitive(dp, "findfile", ficlFindfile,
950 	    FICL_WORD_DEFAULT);
951 	ficlDictionarySetPrimitive(dp, "ccall", ficlCcall, FICL_WORD_DEFAULT);
952 	ficlDictionarySetPrimitive(dp, "uuid-from-string", ficlUuidFromString,
953 	    FICL_WORD_DEFAULT);
954 	ficlDictionarySetPrimitive(dp, "uuid-to-string", ficlUuidToString,
955 	    FICL_WORD_DEFAULT);
956 #ifdef STAND
957 #ifdef __i386__
958 	ficlDictionarySetPrimitive(dp, "outb", ficlOutb, FICL_WORD_DEFAULT);
959 	ficlDictionarySetPrimitive(dp, "inb", ficlInb, FICL_WORD_DEFAULT);
960 #endif
961 	/* Register words from linker set. */
962 	SET_FOREACH(fnpp, Xficl_compile_set)
963 		(*fnpp)(pSys);
964 #endif
965 
966 #if defined(__i386__) || defined(__amd64__)
967 	ficlDictionarySetConstant(env, "arch-i386", FICL_TRUE);
968 	ficlDictionarySetConstant(env, "arch-sparc", FICL_FALSE);
969 #endif
970 #ifdef __sparc
971 	ficlDictionarySetConstant(env, "arch-i386", FICL_FALSE);
972 	ficlDictionarySetConstant(env, "arch-sparc", FICL_TRUE);
973 #endif
974 }
975