1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * Copyright (c) 1997-2005
5 *	Herbert Xu <herbert@gondor.apana.org.au>.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 *	@(#)nodes.c.pat	8.2 (Berkeley) 5/4/95
35 */
36
37#include <zircon/syscalls.h>
38#include <stdlib.h>
39
40/*
41 * Routine for dealing with parsed shell commands.
42 */
43
44#include "shell.h"
45#include "nodes.h"
46#include "memalloc.h"
47#include "machdep.h"
48#include "mystring.h"
49#include "system.h"
50#include "error.h"
51#include "var.h"
52
53
54int     funcblocksize;		/* size of structures in function */
55int     funcstringsize;		/* size of strings in node */
56pointer funcblock;		/* block to allocate function from */
57char   *funcstring;		/* block to allocate strings from */
58
59%SIZES
60
61
62STATIC void calcsize(union node *);
63STATIC void sizenodelist(struct nodelist *);
64STATIC union node *copynode(union node *);
65STATIC struct nodelist *copynodelist(struct nodelist *);
66STATIC char *nodesavestr(char *);
67
68STATIC void writenode(union node *n, size_t node_size, size_t block_size);
69STATIC void encodenode(union node *);
70STATIC void encodenodelist(struct nodelist *);
71STATIC void encodestring(const char *);
72
73STATIC void decodenode(union node **);
74STATIC void decodenodelist(struct nodelist **);
75STATIC char *decodestring();
76
77/*
78 * Make a copy of a parse tree.
79 */
80
81struct funcnode *
82copyfunc(union node *n)
83{
84	struct funcnode *f;
85	size_t blocksize;
86
87	funcblocksize = offsetof(struct funcnode, n);
88	funcstringsize = 0;
89	calcsize(n);
90	blocksize = funcblocksize;
91	f = ckmalloc(blocksize + funcstringsize);
92	funcblock = (char *) f + offsetof(struct funcnode, n);
93	funcstring = (char *) f + blocksize;
94	copynode(n);
95	f->count = 0;
96	return f;
97}
98
99
100
101STATIC void
102calcsize(n)
103	union node *n;
104{
105	%CALCSIZE
106}
107
108
109
110STATIC void
111sizenodelist(lp)
112	struct nodelist *lp;
113{
114	while (lp) {
115		funcblocksize += SHELL_ALIGN(sizeof(struct nodelist));
116		calcsize(lp->n);
117		lp = lp->next;
118	}
119}
120
121
122
123STATIC union node *
124copynode(n)
125	union node *n;
126{
127	union node *new;
128
129	%COPY
130	return new;
131}
132
133
134STATIC struct nodelist *
135copynodelist(lp)
136	struct nodelist *lp;
137{
138	struct nodelist *start;
139	struct nodelist **lpp;
140
141	lpp = &start;
142	while (lp) {
143		*lpp = funcblock;
144		funcblock = (char *) funcblock +
145		    SHELL_ALIGN(sizeof(struct nodelist));
146		(*lpp)->n = copynode(lp->n);
147		lp = lp->next;
148		lpp = &(*lpp)->next;
149	}
150	*lpp = NULL;
151	return start;
152}
153
154
155
156STATIC char *
157nodesavestr(s)
158	char   *s;
159{
160	char   *rtn = funcstring;
161
162	funcstring = stpcpy(funcstring, s) + 1;
163	return rtn;
164}
165
166STATIC void writenode(union node *n, size_t node_size, size_t block_size)
167{
168	if (block_size > funcblocksize) {
169		sh_error("Unable to encode AST");
170		exraise(-1);
171	}
172	memcpy(funcblock, n, node_size);
173	funcblock = (char *) funcblock + block_size;
174	funcblocksize -= block_size;
175}
176
177STATIC void
178encodenode(union node *n)
179{
180	%ENCODE
181}
182
183STATIC void
184encodenodelist(struct nodelist *lp)
185{
186	while (lp) {
187		memcpy(funcblock, lp, sizeof(struct nodelist));
188		funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
189		encodenode(lp->n);
190		lp = lp->next;
191	}
192}
193
194STATIC void
195encodestring(const char *s)
196{
197	funcstring = stpcpy(funcstring, s) + 1;
198}
199
200
201STATIC void
202decodenode(union node **npp)
203{
204	%DECODE
205}
206
207STATIC void
208decodenodelist(struct nodelist **lpp)
209{
210	while (*lpp) {
211		*lpp = funcblock;
212		funcblock = (char *) funcblock + SHELL_ALIGN(sizeof(struct nodelist));
213		struct nodelist *lp = *lpp;
214		decodenode(&lp->n);
215		lpp = &lp->next;
216	}
217}
218
219STATIC char *
220decodestring()
221{
222	char *result = funcstring;
223	funcstring += strlen(result) + 1;
224	return result;
225}
226
227/*
228 * Free a parse tree.
229 */
230
231void
232freefunc(struct funcnode *f)
233{
234	if (f && --f->count < 0)
235		ckfree(f);
236}
237
238// Fuchsia-specific:
239// This is the definition of the header of the VMO used for transferring initialization
240// information to a subshell.  This information would be automatically inherited if we
241// were able to invoke the subshell using a fork().
242// For now, we pass symbol table information (non-exported symbols, those are passed in
243// the environment) and a list of operations to be performed by the subshell.
244struct state_header
245{
246	size_t total_size;
247	size_t num_symbols;
248	size_t symtab_offset;
249	size_t cmd_offset;
250	size_t string_offset;
251};
252static const size_t kHeaderSize = SHELL_ALIGN(sizeof(struct state_header));
253
254static char *ignored_syms[] = { "_", "PPID", "PWD" };
255
256static bool
257ignore_sym(char *name)
258{
259	for (size_t sym_ndx = 0;
260	     sym_ndx < sizeof(ignored_syms) / sizeof(char *);
261	     sym_ndx++) {
262		if (!strcmp(ignored_syms[sym_ndx], name)) {
263			return true;
264		}
265	}
266	return false;
267}
268
269// Determine the space needed to represent the NULL-terminated symbol table
270// 'vars'. Also sets 'num_vars' to the number of symbol table entries.
271static size_t
272calc_symtab_size(char **vars, size_t *num_vars)
273{
274	size_t total_len = 0;
275	*num_vars = 0;
276	while (*vars) {
277		if (! ignore_sym(*vars)) {
278			// + 2 for NULL symbol flags
279			total_len += strlen(*vars) + 2;
280			(*num_vars)++;
281		}
282		vars++;
283	}
284	return total_len;
285}
286
287// Write symbols into 'buffer'. If 'is_readonly' is set, all variables are
288// marked as such.
289static size_t
290output_symtab(char *buffer, char **vars, bool is_readonly)
291{
292	char *orig_buffer = buffer;
293	while (*vars) {
294		if (! ignore_sym(*vars)) {
295			*buffer++ = is_readonly ? 1 : 0;
296			size_t len = strlen(*vars);
297			buffer = mempcpy(buffer, *vars, len + 1);
298		}
299		vars++;
300	}
301	return buffer - orig_buffer;
302}
303
304// Read in symbols from the encoded table 'buffer'. We currently only support
305// two variants of variables: readonly (flags == 1) and writable (flags == 0).
306static void
307restore_symtab(char *buffer, size_t num_syms)
308{
309	while(num_syms--) {
310		bool is_readonly = (*buffer++ == 1);
311		setvareq(buffer, is_readonly ? VREADONLY : 0);
312		buffer += (strlen(buffer) + 1);
313	}
314}
315
316// The encoded format contains four segments:
317//
318// * A header that specifies the number of symbols, and offsets of each of
319//   the three segments (see "struct state_header").
320// * A symbol table. Each entry in the symbol table is a single-byte of flags
321//   (1 = read-only, 0 = writable) followed by a NULL-terminted NAME=VALUE
322//   string.
323// * A sequence of nodes in a pre-order traversal of the node tree.
324//   - The encoded size of each node is determined by its type.
325//   - Pointer fields in each node contain zero if that pointer should decode
326//     a NULL. Otherwise, if the pointer should decode as non-NULL, the field
327//     contains an arbitrary non-zero value. (These values are the address of
328//     the node or the string in the encoding process, which isn't meaningful to
329//     the decoding progress).
330// * A sequence of null-terminated strings, in the order the strings are
331//   encountered in a pre-order traversal of the node tree.
332
333zx_status_t
334codec_encode(struct nodelist *nlist, zx_handle_t *vmo)
335{
336	funcblocksize = 0;
337	funcstringsize = 0;
338	char **writable_vars = listvars(0, VEXPORT | VREADONLY, 0);
339	char **readonly_vars = listvars(VREADONLY, VEXPORT, 0);
340
341	// Calculate the size of the components
342	size_t num_writable_vars;
343	size_t num_readonly_vars;
344	size_t total_symtab_size = calc_symtab_size(writable_vars, &num_writable_vars) +
345				   calc_symtab_size(readonly_vars, &num_readonly_vars);
346	total_symtab_size = SHELL_ALIGN(total_symtab_size);
347	sizenodelist(nlist);
348	struct state_header header;
349
350	// Fill in the header
351	header.num_symbols = num_writable_vars + num_readonly_vars;
352	header.symtab_offset = kHeaderSize;
353	header.cmd_offset = header.symtab_offset + total_symtab_size;
354	header.string_offset = header.cmd_offset + funcblocksize;
355
356	const size_t total_size = header.string_offset + funcstringsize;
357	header.total_size = num_writable_vars + num_readonly_vars;
358	char buffer[total_size];
359
360	// Output the symbol tables
361	memcpy(buffer, &header, sizeof(header));
362	size_t symtab_offset = header.symtab_offset;
363	char* symtab = &buffer[symtab_offset];
364	symtab_offset += output_symtab(symtab, writable_vars, 0);
365	output_symtab(symtab, readonly_vars, 1);
366
367	// Output the command nodes
368	funcblock = buffer + header.cmd_offset;
369	funcstring = buffer + header.string_offset;
370	encodenodelist(nlist);
371
372	// And VMO-ify the whole thing
373	zx_status_t status = zx_vmo_create(total_size, 0, vmo);
374	if (status != ZX_OK)
375		return status;
376	return zx_vmo_write(*vmo, buffer, 0, total_size);
377}
378
379struct nodelist *codec_decode(char *buffer, size_t length)
380{
381	if (length < sizeof(size_t)) {
382		return NULL;
383	}
384
385	struct state_header header;
386	memcpy(&header, buffer, sizeof(header));
387	if (length != header.total_size) {
388		return NULL;
389	}
390
391	restore_symtab(buffer + header.symtab_offset, header.num_symbols);
392	funcblock = buffer + header.cmd_offset;
393	funcstring = buffer + header.string_offset;
394	struct nodelist dummy;
395	// The decodenodelist API is very... unique. It needs the
396	// argument to point to something non-NULL, even though the
397	// argument is otherwise ignored and used as an output parameter.
398
399