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