1 /*
2  * This file was generated by the mknodes program.
3  */
4 
5 /*-
6  * Copyright (c) 1991, 1993
7  *	The Regents of the University of California.  All rights reserved.
8  * Copyright (c) 1997-2005
9  *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
10  *
11  * This code is derived from software contributed to Berkeley by
12  * Kenneth Almquist.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  * 3. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  *	@(#)nodes.c.pat	8.2 (Berkeley) 5/4/95
39  */
40 
41 #include <zircon/syscalls.h>
42 #include <stdlib.h>
43 
44 /*
45  * Routine for dealing with parsed shell commands.
46  */
47 
48 #include "shell.h"
49 #include "nodes.h"
50 #include "memalloc.h"
51 #include "machdep.h"
52 #include "mystring.h"
53 #include "system.h"
54 #include "error.h"
55 #include "var.h"
56 
57 
58 int     funcblocksize;		/* size of structures in function */
59 int     funcstringsize;		/* size of strings in node */
60 pointer funcblock;		/* block to allocate function from */
61 char   *funcstring;		/* block to allocate strings from */
62 
63 static const short nodesize[26] = {
64       SHELL_ALIGN(sizeof (struct ncmd)),
65       SHELL_ALIGN(sizeof (struct npipe)),
66       SHELL_ALIGN(sizeof (struct nredir)),
67       SHELL_ALIGN(sizeof (struct nredir)),
68       SHELL_ALIGN(sizeof (struct nredir)),
69       SHELL_ALIGN(sizeof (struct nbinary)),
70       SHELL_ALIGN(sizeof (struct nbinary)),
71       SHELL_ALIGN(sizeof (struct nbinary)),
72       SHELL_ALIGN(sizeof (struct nif)),
73       SHELL_ALIGN(sizeof (struct nbinary)),
74       SHELL_ALIGN(sizeof (struct nbinary)),
75       SHELL_ALIGN(sizeof (struct nfor)),
76       SHELL_ALIGN(sizeof (struct ncase)),
77       SHELL_ALIGN(sizeof (struct nclist)),
78       SHELL_ALIGN(sizeof (struct ndefun)),
79       SHELL_ALIGN(sizeof (struct narg)),
80       SHELL_ALIGN(sizeof (struct nfile)),
81       SHELL_ALIGN(sizeof (struct nfile)),
82       SHELL_ALIGN(sizeof (struct nfile)),
83       SHELL_ALIGN(sizeof (struct nfile)),
84       SHELL_ALIGN(sizeof (struct nfile)),
85       SHELL_ALIGN(sizeof (struct ndup)),
86       SHELL_ALIGN(sizeof (struct ndup)),
87       SHELL_ALIGN(sizeof (struct nhere)),
88       SHELL_ALIGN(sizeof (struct nhere)),
89       SHELL_ALIGN(sizeof (struct nnot)),
90 };
91 
92 
93 STATIC void calcsize(union node *);
94 STATIC void sizenodelist(struct nodelist *);
95 STATIC union node *copynode(union node *);
96 STATIC struct nodelist *copynodelist(struct nodelist *);
97 STATIC char *nodesavestr(char *);
98 
99 STATIC void writenode(union node *n, size_t node_size, size_t block_size);
100 STATIC void encodenode(union node *);
101 STATIC void encodenodelist(struct nodelist *);
102 STATIC void encodestring(const char *);
103 
104 STATIC void decodenode(union node **);
105 STATIC void decodenodelist(struct nodelist **);
106 STATIC char *decodestring();
107 
108 /*
109  * Make a copy of a parse tree.
110  */
111 
112 struct funcnode *
copyfunc(union node * n)113 copyfunc(union node *n)
114 {
115 	struct funcnode *f;
116 	size_t blocksize;
117 
118 	funcblocksize = offsetof(struct funcnode, n);
119 	funcstringsize = 0;
120 	calcsize(n);
121 	blocksize = funcblocksize;
122 	f = ckmalloc(blocksize + funcstringsize);
123 	funcblock = (char *) f + offsetof(struct funcnode, n);
124 	funcstring = (char *) f + blocksize;
125 	copynode(n);
126 	f->count = 0;
127 	return f;
128 }
129 
130 
131 
132 STATIC void
calcsize(n)133 calcsize(n)
134 	union node *n;
135 {
136 	if (n == NULL)
137 		return;
138 	funcblocksize += nodesize[n->type];
139 	switch (n->type) {
140 	case NCMD:
141 		calcsize(n->ncmd.redirect);
142 		calcsize(n->ncmd.args);
143 		calcsize(n->ncmd.assign);
144 		break;
145 	case NPIPE:
146 		sizenodelist(n->npipe.cmdlist);
147 		break;
148 	case NREDIR:
149 	case NBACKGND:
150 	case NSUBSHELL:
151 		calcsize(n->nredir.redirect);
152 		calcsize(n->nredir.n);
153 		break;
154 	case NAND:
155 	case NOR:
156 	case NSEMI:
157 	case NWHILE:
158 	case NUNTIL:
159 		calcsize(n->nbinary.ch2);
160 		calcsize(n->nbinary.ch1);
161 		break;
162 	case NIF:
163 		calcsize(n->nif.elsepart);
164 		calcsize(n->nif.ifpart);
165 		calcsize(n->nif.test);
166 		break;
167 	case NFOR:
168 		funcstringsize += strlen(n->nfor.var) + 1;
169 		calcsize(n->nfor.body);
170 		calcsize(n->nfor.args);
171 		break;
172 	case NCASE:
173 		calcsize(n->ncase.cases);
174 		calcsize(n->ncase.expr);
175 		break;
176 	case NCLIST:
177 		calcsize(n->nclist.body);
178 		calcsize(n->nclist.pattern);
179 		calcsize(n->nclist.next);
180 		break;
181 	case NDEFUN:
182 		calcsize(n->ndefun.body);
183 		funcstringsize += strlen(n->ndefun.text) + 1;
184 		break;
185 	case NARG:
186 		sizenodelist(n->narg.backquote);
187 		funcstringsize += strlen(n->narg.text) + 1;
188 		calcsize(n->narg.next);
189 		break;
190 	case NTO:
191 	case NCLOBBER:
192 	case NFROM:
193 	case NFROMTO:
194 	case NAPPEND:
195 		calcsize(n->nfile.fname);
196 		calcsize(n->nfile.next);
197 		break;
198 	case NTOFD:
199 	case NFROMFD:
200 		calcsize(n->ndup.vname);
201 		calcsize(n->ndup.next);
202 		break;
203 	case NHERE:
204 	case NXHERE:
205 		calcsize(n->nhere.doc);
206 		calcsize(n->nhere.next);
207 		break;
208 	case NNOT:
209 		calcsize(n->nnot.com);
210 		break;
211 	};
212 }
213 
214 
215 
216 STATIC void
sizenodelist(lp)217 sizenodelist(lp)
218 	struct nodelist *lp;
219 {
220 	while (lp) {
221 		funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
222 		calcsize(lp->n);
223 		lp = lp->next;
224 	}
225 }
226 
227 
228 
229 STATIC union node *
copynode(n)230 copynode(n)
231 	union node *n;
232 {
233 	union node *new;
234 
235 	if (n == NULL)
236 		return NULL;
237 	new = funcblock;
238 	funcblock = (char *) funcblock + nodesize[n->type];
239 	switch (n->type) {
240 	case NCMD:
241 		new->ncmd.redirect = copynode(n->ncmd.redirect);
242 		new->ncmd.args = copynode(n->ncmd.args);
243 		new->ncmd.assign = copynode(n->ncmd.assign);
244 		new->ncmd.linno = n->ncmd.linno;
245 		break;
246 	case NPIPE:
247 		new->npipe.cmdlist = copynodelist(n->npipe.cmdlist);
248 		new->npipe.backgnd = n->npipe.backgnd;
249 		break;
250 	case NREDIR:
251 	case NBACKGND:
252 	case NSUBSHELL:
253 		new->nredir.redirect = copynode(n->nredir.redirect);
254 		new->nredir.n = copynode(n->nredir.n);
255 		new->nredir.linno = n->nredir.linno;
256 		break;
257 	case NAND:
258 	case NOR:
259 	case NSEMI:
260 	case NWHILE:
261 	case NUNTIL:
262 		new->nbinary.ch2 = copynode(n->nbinary.ch2);
263 		new->nbinary.ch1 = copynode(n->nbinary.ch1);
264 		break;
265 	case NIF:
266 		new->nif.elsepart = copynode(n->nif.elsepart);
267 		new->nif.ifpart = copynode(n->nif.ifpart);
268 		new->nif.test = copynode(n->nif.test);
269 		break;
270 	case NFOR:
271 		new->nfor.var = nodesavestr(n->nfor.var);
272 		new->nfor.body = copynode(n->nfor.body);
273 		new->nfor.args = copynode(n->nfor.args);
274 		new->nfor.linno = n->nfor.linno;
275 		break;
276 	case NCASE:
277 		new->ncase.cases = copynode(n->ncase.cases);
278 		new->ncase.expr = copynode(n->ncase.expr);
279 		new->ncase.linno = n->ncase.linno;
280 		break;
281 	case NCLIST:
282 		new->nclist.body = copynode(n->nclist.body);
283 		new->nclist.pattern = copynode(n->nclist.pattern);
284 		new->nclist.next = copynode(n->nclist.next);
285 		break;
286 	case NDEFUN:
287 		new->ndefun.body = copynode(n->ndefun.body);
288 		new->ndefun.text = nodesavestr(n->ndefun.text);
289 		new->ndefun.linno = n->ndefun.linno;
290 		break;
291 	case NARG:
292 		new->narg.backquote = copynodelist(n->narg.backquote);
293 		new->narg.text = nodesavestr(n->narg.text);
294 		new->narg.next = copynode(n->narg.next);
295 		break;
296 	case NTO:
297 	case NCLOBBER:
298 	case NFROM:
299 	case NFROMTO:
300 	case NAPPEND:
301 		new->nfile.fname = copynode(n->nfile.fname);
302 		new->nfile.fd = n->nfile.fd;
303 		new->nfile.next = copynode(n->nfile.next);
304 		break;
305 	case NTOFD:
306 	case NFROMFD:
307 		new->ndup.vname = copynode(n->ndup.vname);
308 		new->ndup.dupfd = n->ndup.dupfd;
309 		new->ndup.fd = n->ndup.fd;
310 		new->ndup.next = copynode(n->ndup.next);
311 		break;
312 	case NHERE:
313 	case NXHERE:
314 		new->nhere.doc = copynode(n->nhere.doc);
315 		new->nhere.fd = n->nhere.fd;
316 		new->nhere.next = copynode(n->nhere.next);
317 		break;
318 	case NNOT:
319 		new->nnot.com = copynode(n->nnot.com);
320 		break;
321 	};
322 	new->type = n->type;
323 	return new;
324 }
325 
326 
327 STATIC struct nodelist *
copynodelist(lp)328 copynodelist(lp)
329 	struct nodelist *lp;
330 {
331 	struct nodelist *start;
332 	struct nodelist **lpp;
333 
334 	lpp = &start;
335 	while (lp) {
336 		*lpp = funcblock;
337 		funcblock = (char *) funcblock +
338 		    SHELL_ALIGN(sizeof(struct nodelist));
339 		(*lpp)->n = copynode(lp->n);
340 		lp = lp->next;
341 		lpp = &(*lpp)->next;
342 	}
343 	*lpp = NULL;
344 	return start;
345 }
346 
347 
348 
349 STATIC char *
nodesavestr(s)350 nodesavestr(s)
351 	char   *s;
352 {
353 	char   *rtn = funcstring;
354 
355 	funcstring = stpcpy(funcstring, s) + 1;
356 	return rtn;
357 }
358 
writenode(union node * n,size_t node_size,size_t block_size)359 STATIC void writenode(union node *n, size_t node_size, size_t block_size)
360 {
361 	if (block_size > funcblocksize) {
362 		sh_error("Unable to encode AST");
363 		exraise(-1);
364 	}
365 	memcpy(funcblock, n, node_size);
366 	funcblock = (char *) funcblock + block_size;
367 	funcblocksize -= block_size;
368 }
369 
370 STATIC void
encodenode(union node * n)371 encodenode(union node *n)
372 {
373 	if (n == NULL)
374 		return;
375 	switch (n->type) {
376 	case NCMD:
377 		writenode(n, sizeof(struct ncmd), nodesize[n->type]);
378 		encodenode(n->ncmd.redirect);
379 		encodenode(n->ncmd.args);
380 		encodenode(n->ncmd.assign);
381 		break;
382 	case NPIPE:
383 		writenode(n, sizeof(struct npipe), nodesize[n->type]);
384 		encodenodelist(n->npipe.cmdlist);
385 		break;
386 	case NREDIR:
387 	case NBACKGND:
388 	case NSUBSHELL:
389 		writenode(n, sizeof(struct nredir), nodesize[n->type]);
390 		encodenode(n->nredir.redirect);
391 		encodenode(n->nredir.n);
392 		break;
393 	case NAND:
394 	case NOR:
395 	case NSEMI:
396 	case NWHILE:
397 	case NUNTIL:
398 		writenode(n, sizeof(struct nbinary), nodesize[n->type]);
399 		encodenode(n->nbinary.ch2);
400 		encodenode(n->nbinary.ch1);
401 		break;
402 	case NIF:
403 		writenode(n, sizeof(struct nif), nodesize[n->type]);
404 		encodenode(n->nif.elsepart);
405 		encodenode(n->nif.ifpart);
406 		encodenode(n->nif.test);
407 		break;
408 	case NFOR:
409 		writenode(n, sizeof(struct nfor), nodesize[n->type]);
410 		encodestring(n->nfor.var);
411 		encodenode(n->nfor.body);
412 		encodenode(n->nfor.args);
413 		break;
414 	case NCASE:
415 		writenode(n, sizeof(struct ncase), nodesize[n->type]);
416 		encodenode(n->ncase.cases);
417 		encodenode(n->ncase.expr);
418 		break;
419 	case NCLIST:
420 		writenode(n, sizeof(struct nclist), nodesize[n->type]);
421 		encodenode(n->nclist.body);
422 		encodenode(n->nclist.pattern);
423 		encodenode(n->nclist.next);
424 		break;
425 	case NDEFUN:
426 		writenode(n, sizeof(struct ndefun), nodesize[n->type]);
427 		encodenode(n->ndefun.body);
428 		encodestring(n->ndefun.text);
429 		break;
430 	case NARG:
431 		writenode(n, sizeof(struct narg), nodesize[n->type]);
432 		encodenodelist(n->narg.backquote);
433 		encodestring(n->narg.text);
434 		encodenode(n->narg.next);
435 		break;
436 	case NTO:
437 	case NCLOBBER:
438 	case NFROM:
439 	case NFROMTO:
440 	case NAPPEND:
441 		writenode(n, sizeof(struct nfile), nodesize[n->type]);
442 		encodenode(n->nfile.fname);
443 		encodenode(n->nfile.next);
444 		break;
445 	case NTOFD:
446 	case NFROMFD:
447 		writenode(n, sizeof(struct ndup), nodesize[n->type]);
448 		encodenode(n->ndup.vname);
449 		encodenode(n->ndup.next);
450 		break;
451 	case NHERE:
452 	case NXHERE:
453 		writenode(n, sizeof(struct nhere), nodesize[n->type]);
454 		encodenode(n->nhere.doc);
455 		encodenode(n->nhere.next);
456 		break;
457 	case NNOT:
458 		writenode(n, sizeof(struct nnot), nodesize[n->type]);
459 		encodenode(n->nnot.com);
460 		break;
461 	};
462 }
463 
464 STATIC void
encodenodelist(struct nodelist * lp)465 encodenodelist(struct nodelist *lp)
466 {
467 	while (lp) {
468 		memcpy(funcblock, lp, sizeof(struct nodelist));
469 		funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
470 		encodenode(lp->n);
471 		lp = lp->next;
472 	}
473 }
474 
475 STATIC void
encodestring(const char * s)476 encodestring(const char *s)
477 {
478 	funcstring = stpcpy(funcstring, s) + 1;
479 }
480 
481 
482 STATIC void
decodenode(union node ** npp)483 decodenode(union node **npp)
484 {
485 	if (*npp == NULL)
486 		return;
487 	*npp = funcblock;
488 	union node *n = *npp;
489 	funcblock = (char *) funcblock + nodesize[n->type];
490 	switch (n->type) {
491 	case NCMD:
492 		decodenode(&n->ncmd.redirect);
493 		decodenode(&n->ncmd.args);
494 		decodenode(&n->ncmd.assign);
495 		break;
496 	case NPIPE:
497 		decodenodelist(&n->npipe.cmdlist);
498 		break;
499 	case NREDIR:
500 	case NBACKGND:
501 	case NSUBSHELL:
502 		decodenode(&n->nredir.redirect);
503 		decodenode(&n->nredir.n);
504 		break;
505 	case NAND:
506 	case NOR:
507 	case NSEMI:
508 	case NWHILE:
509 	case NUNTIL:
510 		decodenode(&n->nbinary.ch2);
511 		decodenode(&n->nbinary.ch1);
512 		break;
513 	case NIF:
514 		decodenode(&n->nif.elsepart);
515 		decodenode(&n->nif.ifpart);
516 		decodenode(&n->nif.test);
517 		break;
518 	case NFOR:
519 		n->nfor.var = decodestring();
520 		decodenode(&n->nfor.body);
521 		decodenode(&n->nfor.args);
522 		break;
523 	case NCASE:
524 		decodenode(&n->ncase.cases);
525 		decodenode(&n->ncase.expr);
526 		break;
527 	case NCLIST:
528 		decodenode(&n->nclist.body);
529 		decodenode(&n->nclist.pattern);
530 		decodenode(&n->nclist.next);
531 		break;
532 	case NDEFUN:
533 		decodenode(&n->ndefun.body);
534 		n->ndefun.text = decodestring();
535 		break;
536 	case NARG:
537 		decodenodelist(&n->narg.backquote);
538 		n->narg.text = decodestring();
539 		decodenode(&n->narg.next);
540 		break;
541 	case NTO:
542 	case NCLOBBER:
543 	case NFROM:
544 	case NFROMTO:
545 	case NAPPEND:
546 		decodenode(&n->nfile.fname);
547 		decodenode(&n->nfile.next);
548 		break;
549 	case NTOFD:
550 	case NFROMFD:
551 		decodenode(&n->ndup.vname);
552 		decodenode(&n->ndup.next);
553 		break;
554 	case NHERE:
555 	case NXHERE:
556 		decodenode(&n->nhere.doc);
557 		decodenode(&n->nhere.next);
558 		break;
559 	case NNOT:
560 		decodenode(&n->nnot.com);
561 		break;
562 	};
563 }
564 
565 STATIC void
decodenodelist(struct nodelist ** lpp)566 decodenodelist(struct nodelist **lpp)
567 {
568 	while (*lpp) {
569 		*lpp = funcblock;
570 		funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
571 		struct nodelist *lp = *lpp;
572 		decodenode(&lp->n);
573 		lpp = &lp->next;
574 	}
575 }
576 
577 STATIC char *
decodestring()578 decodestring()
579 {
580 	char *result = funcstring;
581 	funcstring += strlen(result) + 1;
582 	return result;
583 }
584 
585 /*
586  * Free a parse tree.
587  */
588 
589 void
freefunc(struct funcnode * f)590 freefunc(struct funcnode *f)
591 {
592 	if (f && --f->count < 0)
593 		ckfree(f);
594 }
595 
596 // Fuchsia-specific:
597 // This is the definition of the header of the VMO used for transferring initialization
598 // information to a subshell.  This information would be automatically inherited if we
599 // were able to invoke the subshell using a fork().
600 // For now, we pass symbol table information (non-exported symbols, those are passed in
601 // the environment) and a list of operations to be performed by the subshell.
602 struct state_header
603 {
604 	size_t total_size;
605 	size_t num_symbols;
606 	size_t symtab_offset;
607 	size_t cmd_offset;
608 	size_t string_offset;
609 };
610 static const size_t kHeaderSize = SHELL_ALIGN(sizeof(struct state_header));
611 
612 static char *ignored_syms[] = { "_", "PPID", "PWD" };
613 
614 static bool
ignore_sym(char * name)615 ignore_sym(char *name)
616 {
617 	for (size_t sym_ndx = 0;
618 	     sym_ndx < sizeof(ignored_syms) / sizeof(char *);
619 	     sym_ndx++) {
620 		if (!strcmp(ignored_syms[sym_ndx], name)) {
621 			return true;
622 		}
623 	}
624 	return false;
625 }
626 
627 // Determine the space needed to represent the NULL-terminated symbol table
628 // 'vars'. Also sets 'num_vars' to the number of symbol table entries.
629 static size_t
calc_symtab_size(char ** vars,size_t * num_vars)630 calc_symtab_size(char **vars, size_t *num_vars)
631 {
632 	size_t total_len = 0;
633 	*num_vars = 0;
634 	while (*vars) {
635 		if (! ignore_sym(*vars)) {
636 			// + 2 for NULL symbol flags
637 			total_len += strlen(*vars) + 2;
638 			(*num_vars)++;
639 		}
640 		vars++;
641 	}
642 	return total_len;
643 }
644 
645 // Write symbols into 'buffer'. If 'is_readonly' is set, all variables are
646 // marked as such.
647 static size_t
output_symtab(char * buffer,char ** vars,bool is_readonly)648 output_symtab(char *buffer, char **vars, bool is_readonly)
649 {
650 	char *orig_buffer = buffer;
651 	while (*vars) {
652 		if (! ignore_sym(*vars)) {
653 			*buffer++ = is_readonly ? 1 : 0;
654 			size_t len = strlen(*vars);
655 			buffer = mempcpy(buffer, *vars, len + 1);
656 		}
657 		vars++;
658 	}
659 	return buffer - orig_buffer;
660 }
661 
662 // Read in symbols from the encoded table 'buffer'. We currently only support
663 // two variants of variables: readonly (flags == 1) and writable (flags == 0).
664 static void
restore_symtab(char * buffer,size_t num_syms)665 restore_symtab(char *buffer, size_t num_syms)
666 {
667 	while(num_syms--) {
668 		bool is_readonly = (*buffer++ == 1);
669 		setvareq(buffer, is_readonly ? VREADONLY : 0);
670 		buffer += (strlen(buffer) + 1);
671 	}
672 }
673 
674 // The encoded format contains four segments:
675 //
676 // * A header that specifies the number of symbols, and offsets of each of
677 //   the three segments (see "struct state_header").
678 // * A symbol table. Each entry in the symbol table is a single-byte of flags
679 //   (1 = read-only, 0 = writable) followed by a NULL-terminted NAME=VALUE
680 //   string.
681 // * A sequence of nodes in a pre-order traversal of the node tree.
682 //   - The encoded size of each node is determined by its type.
683 //   - Pointer fields in each node contain zero if that pointer should decode
684 //     a NULL. Otherwise, if the pointer should decode as non-NULL, the field
685 //     contains an arbitrary non-zero value. (These values are the address of
686 //     the node or the string in the encoding process, which isn't meaningful to
687 //     the decoding progress).
688 // * A sequence of null-terminated strings, in the order the strings are
689 //   encountered in a pre-order traversal of the node tree.
690 
691 zx_status_t
codec_encode(struct nodelist * nlist,zx_handle_t * vmo)692 codec_encode(struct nodelist *nlist, zx_handle_t *vmo)
693 {
694 	funcblocksize = 0;
695 	funcstringsize = 0;
696 	char **writable_vars = listvars(0, VEXPORT | VREADONLY, 0);
697 	char **readonly_vars = listvars(VREADONLY, VEXPORT, 0);
698 
699 	// Calculate the size of the components
700 	size_t num_writable_vars;
701 	size_t num_readonly_vars;
702 	size_t total_symtab_size = calc_symtab_size(writable_vars, &num_writable_vars) +
703 				   calc_symtab_size(readonly_vars, &num_readonly_vars);
704 	total_symtab_size = SHELL_ALIGN(total_symtab_size);
705 	sizenodelist(nlist);
706 	struct state_header header;
707 
708 	// Fill in the header
709 	header.num_symbols = num_writable_vars + num_readonly_vars;
710 	header.symtab_offset = kHeaderSize;
711 	header.cmd_offset = header.symtab_offset + total_symtab_size;
712 	header.string_offset = header.cmd_offset + funcblocksize;
713 
714 	char buffer[header.string_offset + funcstringsize];
715 	header.total_size = sizeof(buffer);
716 
717 	// Output the symbol tables
718 	memcpy(buffer, &header, sizeof(header));
719 	size_t symtab_offset = header.symtab_offset;
720 	char* symtab = &buffer[symtab_offset];
721 	symtab_offset += output_symtab(symtab, writable_vars, 0);
722 	output_symtab(symtab, readonly_vars, 1);
723 
724 	// Output the command nodes
725 	funcblock = buffer + header.cmd_offset;
726 	funcstring = buffer + header.string_offset;
727 	encodenodelist(nlist);
728 
729 	// And VMO-ify the whole thing
730 	zx_status_t status = zx_vmo_create(sizeof(buffer), 0, vmo);
731 	if (status != ZX_OK)
732 		return status;
733 	return zx_vmo_write(*vmo, buffer, 0, sizeof(buffer));
734 }
735 
codec_decode(char * buffer,size_t length)736 struct nodelist *codec_decode(char *buffer, size_t length)
737 {
738 	struct state_header header;
739 	if (length < sizeof(header)) {
740 		return NULL;
741 	}
742 	memcpy(&header, buffer, sizeof(header));
743 	if (length < header.total_size) {
744 		return NULL;
745 	}
746 
747 	restore_symtab(buffer + header.symtab_offset, header.num_symbols);
748 	funcblock = buffer + header.cmd_offset;
749 	funcstring = buffer + header.string_offset;
750 	struct nodelist dummy;
751 	// The decodenodelist API is very... unique. It needs the
752 	// argument to point to something non-NULL, even though the
753 	// argument is otherwise ignored and used as an output parameter.
754 	struct nodelist *nlist = &dummy;
755 	decodenodelist(&nlist);
756 	return nlist;
757 }
758 
759