1 /*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)show.c 8.3 (Berkeley) 5/4/95 37 * $FreeBSD: src/bin/sh/show.c,v 1.27 2010/10/13 22:18:03 obrien Exp $ 38 */ 39 40 #include <fcntl.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <stdarg.h> 44 #include <errno.h> 45 46 #include "shell.h" 47 #include "parser.h" 48 #include "nodes.h" 49 #include "mystring.h" 50 #include "show.h" 51 52 53 #ifdef DEBUG 54 static void shtree(union node *, int, char *, FILE*); 55 static void shcmd(union node *, FILE *); 56 static void sharg(union node *, FILE *); 57 static void indent(int, char *, FILE *); 58 static void trstring(char *); 59 60 61 void 62 showtree(union node *n) 63 { 64 trputs("showtree called\n"); 65 shtree(n, 1, NULL, stdout); 66 } 67 68 69 static void 70 shtree(union node *n, int ind, char *pfx, FILE *fp) 71 { 72 struct nodelist *lp; 73 char *s; 74 75 if (n == NULL) 76 return; 77 78 indent(ind, pfx, fp); 79 switch(n->type) { 80 case NSEMI: 81 s = "; "; 82 goto binop; 83 case NAND: 84 s = " && "; 85 goto binop; 86 case NOR: 87 s = " || "; 88 binop: 89 shtree(n->nbinary.ch1, ind, NULL, fp); 90 /* if (ind < 0) */ 91 fputs(s, fp); 92 shtree(n->nbinary.ch2, ind, NULL, fp); 93 break; 94 case NCMD: 95 shcmd(n, fp); 96 if (ind >= 0) 97 putc('\n', fp); 98 break; 99 case NPIPE: 100 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 101 shcmd(lp->n, fp); 102 if (lp->next) 103 fputs(" | ", fp); 104 } 105 if (n->npipe.backgnd) 106 fputs(" &", fp); 107 if (ind >= 0) 108 putc('\n', fp); 109 break; 110 default: 111 fprintf(fp, "<node type %d>", n->type); 112 if (ind >= 0) 113 putc('\n', fp); 114 break; 115 } 116 } 117 118 119 120 static void 121 shcmd(union node *cmd, FILE *fp) 122 { 123 union node *np; 124 int first; 125 char *s; 126 int dftfd; 127 128 first = 1; 129 for (np = cmd->ncmd.args ; np ; np = np->narg.next) { 130 if (! first) 131 putchar(' '); 132 sharg(np, fp); 133 first = 0; 134 } 135 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { 136 if (! first) 137 putchar(' '); 138 switch (np->nfile.type) { 139 case NTO: s = ">"; dftfd = 1; break; 140 case NAPPEND: s = ">>"; dftfd = 1; break; 141 case NTOFD: s = ">&"; dftfd = 1; break; 142 case NCLOBBER: s = ">|"; dftfd = 1; break; 143 case NFROM: s = "<"; dftfd = 0; break; 144 case NFROMTO: s = "<>"; dftfd = 0; break; 145 case NFROMFD: s = "<&"; dftfd = 0; break; 146 case NHERE: s = "<<"; dftfd = 0; break; 147 case NXHERE: s = "<<"; dftfd = 0; break; 148 default: s = "*error*"; dftfd = 0; break; 149 } 150 if (np->nfile.fd != dftfd) 151 fprintf(fp, "%d", np->nfile.fd); 152 fputs(s, fp); 153 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { 154 if (np->ndup.dupfd >= 0) 155 fprintf(fp, "%d", np->ndup.dupfd); 156 else 157 fprintf(fp, "-"); 158 } else if (np->nfile.type == NHERE) { 159 fprintf(fp, "HERE"); 160 } else if (np->nfile.type == NXHERE) { 161 fprintf(fp, "XHERE"); 162 } else { 163 sharg(np->nfile.fname, fp); 164 } 165 first = 0; 166 } 167 } 168 169 170 171 static void 172 sharg(union node *arg, FILE *fp) 173 { 174 char *p; 175 struct nodelist *bqlist; 176 int subtype; 177 178 if (arg->type != NARG) { 179 printf("<node type %d>\n", arg->type); 180 fflush(stdout); 181 abort(); 182 } 183 bqlist = arg->narg.backquote; 184 for (p = arg->narg.text ; *p ; p++) { 185 switch (*p) { 186 case CTLESC: 187 putc(*++p, fp); 188 break; 189 case CTLVAR: 190 putc('$', fp); 191 putc('{', fp); 192 subtype = *++p; 193 if (subtype == VSLENGTH) 194 putc('#', fp); 195 196 while (*p != '=') 197 putc(*p++, fp); 198 199 if (subtype & VSNUL) 200 putc(':', fp); 201 202 switch (subtype & VSTYPE) { 203 case VSNORMAL: 204 putc('}', fp); 205 break; 206 case VSMINUS: 207 putc('-', fp); 208 break; 209 case VSPLUS: 210 putc('+', fp); 211 break; 212 case VSQUESTION: 213 putc('?', fp); 214 break; 215 case VSASSIGN: 216 putc('=', fp); 217 break; 218 case VSTRIMLEFT: 219 putc('#', fp); 220 break; 221 case VSTRIMLEFTMAX: 222 putc('#', fp); 223 putc('#', fp); 224 break; 225 case VSTRIMRIGHT: 226 putc('%', fp); 227 break; 228 case VSTRIMRIGHTMAX: 229 putc('%', fp); 230 putc('%', fp); 231 break; 232 case VSLENGTH: 233 break; 234 default: 235 printf("<subtype %d>", subtype); 236 } 237 break; 238 case CTLENDVAR: 239 putc('}', fp); 240 break; 241 case CTLBACKQ: 242 case CTLBACKQ|CTLQUOTE: 243 putc('$', fp); 244 putc('(', fp); 245 shtree(bqlist->n, -1, NULL, fp); 246 putc(')', fp); 247 break; 248 default: 249 putc(*p, fp); 250 break; 251 } 252 } 253 } 254 255 256 static void 257 indent(int amount, char *pfx, FILE *fp) 258 { 259 int i; 260 261 for (i = 0 ; i < amount ; i++) { 262 if (pfx && i == amount - 1) 263 fputs(pfx, fp); 264 putc('\t', fp); 265 } 266 } 267 268 269 /* 270 * Debugging stuff. 271 */ 272 273 274 FILE *tracefile; 275 276 #if DEBUG >= 2 277 int debug = 1; 278 #else 279 int debug = 0; 280 #endif 281 282 283 void 284 trputc(int c) 285 { 286 if (tracefile == NULL) 287 return; 288 putc(c, tracefile); 289 if (c == '\n') 290 fflush(tracefile); 291 } 292 293 294 void 295 sh_trace(const char *fmt, ...) 296 { 297 va_list va; 298 va_start(va, fmt); 299 if (tracefile != NULL) { 300 vfprintf(tracefile, fmt, va); 301 if (strchr(fmt, '\n')) 302 fflush(tracefile); 303 } 304 va_end(va); 305 } 306 307 308 void 309 trputs(const char *s) 310 { 311 if (tracefile == NULL) 312 return; 313 fputs(s, tracefile); 314 if (strchr(s, '\n')) 315 fflush(tracefile); 316 } 317 318 319 static void 320 trstring(char *s) 321 { 322 char *p; 323 char c; 324 325 if (tracefile == NULL) 326 return; 327 putc('"', tracefile); 328 for (p = s ; *p ; p++) { 329 switch (*p) { 330 case '\n': c = 'n'; goto backslash; 331 case '\t': c = 't'; goto backslash; 332 case '\r': c = 'r'; goto backslash; 333 case '"': c = '"'; goto backslash; 334 case '\\': c = '\\'; goto backslash; 335 case CTLESC: c = 'e'; goto backslash; 336 case CTLVAR: c = 'v'; goto backslash; 337 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; 338 case CTLBACKQ: c = 'q'; goto backslash; 339 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 340 backslash: putc('\\', tracefile); 341 putc(c, tracefile); 342 break; 343 default: 344 if (*p >= ' ' && *p <= '~') 345 putc(*p, tracefile); 346 else { 347 putc('\\', tracefile); 348 putc(*p >> 6 & 03, tracefile); 349 putc(*p >> 3 & 07, tracefile); 350 putc(*p & 07, tracefile); 351 } 352 break; 353 } 354 } 355 putc('"', tracefile); 356 } 357 358 359 void 360 trargs(char **ap) 361 { 362 if (tracefile == NULL) 363 return; 364 while (*ap) { 365 trstring(*ap++); 366 if (*ap) 367 putc(' ', tracefile); 368 else 369 putc('\n', tracefile); 370 } 371 fflush(tracefile); 372 } 373 374 375 void 376 opentrace(void) 377 { 378 char s[100]; 379 int flags; 380 381 if (!debug) 382 return; 383 #ifdef not_this_way 384 { 385 char *p; 386 if ((p = getenv("HOME")) == NULL) { 387 if (geteuid() == 0) 388 p = "/"; 389 else 390 p = "/tmp"; 391 } 392 scopy(p, s); 393 strcat(s, "/trace"); 394 } 395 #else 396 scopy("./trace", s); 397 #endif /* not_this_way */ 398 if ((tracefile = fopen(s, "a")) == NULL) { 399 fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno)); 400 return; 401 } 402 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) 403 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 404 fputs("\nTracing started.\n", tracefile); 405 fflush(tracefile); 406 } 407 #endif /* DEBUG */ 408