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