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