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 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95"; 40 #endif 41 #endif /* not lint */ 42 #include <sys/cdefs.h> 43 __FBSDID("$FreeBSD$"); 44 45 #include <stdio.h> 46 #include <stdarg.h> 47 #include <errno.h> 48 49 #include "shell.h" 50 #include "parser.h" 51 #include "nodes.h" 52 #include "mystring.h" 53 #include "show.h" 54 55 56 #ifdef DEBUG 57 static void shtree(union node *, int, char *, FILE*); 58 static void shcmd(union node *, FILE *); 59 static void sharg(union node *, FILE *); 60 static void indent(int, char *, FILE *); 61 static void trstring(char *); 62 63 64 void 65 showtree(union node *n) 66 { 67 trputs("showtree called\n"); 68 shtree(n, 1, NULL, stdout); 69 } 70 71 72 static void 73 shtree(union node *n, int ind, char *pfx, FILE *fp) 74 { 75 struct nodelist *lp; 76 char *s; 77 78 if (n == NULL) 79 return; 80 81 indent(ind, pfx, fp); 82 switch(n->type) { 83 case NSEMI: 84 s = "; "; 85 goto binop; 86 case NAND: 87 s = " && "; 88 goto binop; 89 case NOR: 90 s = " || "; 91 binop: 92 shtree(n->nbinary.ch1, ind, NULL, fp); 93 /* if (ind < 0) */ 94 fputs(s, fp); 95 shtree(n->nbinary.ch2, ind, NULL, fp); 96 break; 97 case NCMD: 98 shcmd(n, fp); 99 if (ind >= 0) 100 putc('\n', fp); 101 break; 102 case NPIPE: 103 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 104 shcmd(lp->n, fp); 105 if (lp->next) 106 fputs(" | ", fp); 107 } 108 if (n->npipe.backgnd) 109 fputs(" &", fp); 110 if (ind >= 0) 111 putc('\n', fp); 112 break; 113 default: 114 fprintf(fp, "<node type %d>", n->type); 115 if (ind >= 0) 116 putc('\n', fp); 117 break; 118 } 119 } 120 121 122 123 static void 124 shcmd(union node *cmd, FILE *fp) 125 { 126 union node *np; 127 int first; 128 char *s; 129 int dftfd; 130 131 first = 1; 132 for (np = cmd->ncmd.args ; np ; np = np->narg.next) { 133 if (! first) 134 putchar(' '); 135 sharg(np, fp); 136 first = 0; 137 } 138 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { 139 if (! first) 140 putchar(' '); 141 switch (np->nfile.type) { 142 case NTO: s = ">"; dftfd = 1; break; 143 case NAPPEND: s = ">>"; dftfd = 1; break; 144 case NTOFD: s = ">&"; dftfd = 1; break; 145 case NCLOBBER: s = ">|"; dftfd = 1; break; 146 case NFROM: s = "<"; dftfd = 0; break; 147 case NFROMTO: s = "<>"; dftfd = 0; break; 148 case NFROMFD: s = "<&"; dftfd = 0; break; 149 default: s = "*error*"; dftfd = 0; break; 150 } 151 if (np->nfile.fd != dftfd) 152 fprintf(fp, "%d", np->nfile.fd); 153 fputs(s, fp); 154 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { 155 if (np->ndup.dupfd >= 0) 156 fprintf(fp, "%d", np->ndup.dupfd); 157 else 158 fprintf(fp, "-"); 159 } else { 160 sharg(np->nfile.fname, fp); 161 } 162 first = 0; 163 } 164 } 165 166 167 168 static void 169 sharg(union node *arg, FILE *fp) 170 { 171 char *p; 172 struct nodelist *bqlist; 173 int subtype; 174 175 if (arg->type != NARG) { 176 printf("<node type %d>\n", arg->type); 177 fflush(stdout); 178 abort(); 179 } 180 bqlist = arg->narg.backquote; 181 for (p = arg->narg.text ; *p ; p++) { 182 switch (*p) { 183 case CTLESC: 184 putc(*++p, fp); 185 break; 186 case CTLVAR: 187 putc('$', fp); 188 putc('{', fp); 189 subtype = *++p; 190 if (subtype == VSLENGTH) 191 putc('#', fp); 192 193 while (*p != '=') 194 putc(*p++, fp); 195 196 if (subtype & VSNUL) 197 putc(':', fp); 198 199 switch (subtype & VSTYPE) { 200 case VSNORMAL: 201 putc('}', fp); 202 break; 203 case VSMINUS: 204 putc('-', fp); 205 break; 206 case VSPLUS: 207 putc('+', fp); 208 break; 209 case VSQUESTION: 210 putc('?', fp); 211 break; 212 case VSASSIGN: 213 putc('=', fp); 214 break; 215 case VSTRIMLEFT: 216 putc('#', fp); 217 break; 218 case VSTRIMLEFTMAX: 219 putc('#', fp); 220 putc('#', fp); 221 break; 222 case VSTRIMRIGHT: 223 putc('%', fp); 224 break; 225 case VSTRIMRIGHTMAX: 226 putc('%', fp); 227 putc('%', fp); 228 break; 229 case VSLENGTH: 230 break; 231 default: 232 printf("<subtype %d>", subtype); 233 } 234 break; 235 case CTLENDVAR: 236 putc('}', fp); 237 break; 238 case CTLBACKQ: 239 case CTLBACKQ|CTLQUOTE: 240 putc('$', fp); 241 putc('(', fp); 242 shtree(bqlist->n, -1, NULL, fp); 243 putc(')', fp); 244 break; 245 default: 246 putc(*p, fp); 247 break; 248 } 249 } 250 } 251 252 253 static void 254 indent(int amount, char *pfx, FILE *fp) 255 { 256 int i; 257 258 for (i = 0 ; i < amount ; i++) { 259 if (pfx && i == amount - 1) 260 fputs(pfx, fp); 261 putc('\t', fp); 262 } 263 } 264 265 266 /* 267 * Debugging stuff. 268 */ 269 270 271 FILE *tracefile; 272 273 #if DEBUG == 2 274 int debug = 1; 275 #else 276 int debug = 0; 277 #endif 278 279 280 void 281 trputc(int c) 282 { 283 if (tracefile == NULL) 284 return; 285 putc(c, tracefile); 286 if (c == '\n') 287 fflush(tracefile); 288 } 289 290 291 void 292 sh_trace(const char *fmt, ...) 293 { 294 va_list va; 295 va_start(va, fmt); 296 if (tracefile != NULL) { 297 (void) vfprintf(tracefile, fmt, va); 298 if (strchr(fmt, '\n')) 299 (void) fflush(tracefile); 300 } 301 va_end(va); 302 } 303 304 305 void 306 trputs(char *s) 307 { 308 if (tracefile == NULL) 309 return; 310 fputs(s, tracefile); 311 if (strchr(s, '\n')) 312 fflush(tracefile); 313 } 314 315 316 static void 317 trstring(char *s) 318 { 319 char *p; 320 char c; 321 322 if (tracefile == NULL) 323 return; 324 putc('"', tracefile); 325 for (p = s ; *p ; p++) { 326 switch (*p) { 327 case '\n': c = 'n'; goto backslash; 328 case '\t': c = 't'; goto backslash; 329 case '\r': c = 'r'; goto backslash; 330 case '"': c = '"'; goto backslash; 331 case '\\': c = '\\'; goto backslash; 332 case CTLESC: c = 'e'; goto backslash; 333 case CTLVAR: c = 'v'; goto backslash; 334 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; 335 case CTLBACKQ: c = 'q'; goto backslash; 336 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 337 backslash: putc('\\', tracefile); 338 putc(c, tracefile); 339 break; 340 default: 341 if (*p >= ' ' && *p <= '~') 342 putc(*p, tracefile); 343 else { 344 putc('\\', tracefile); 345 putc(*p >> 6 & 03, tracefile); 346 putc(*p >> 3 & 07, tracefile); 347 putc(*p & 07, tracefile); 348 } 349 break; 350 } 351 } 352 putc('"', tracefile); 353 } 354 355 356 void 357 trargs(char **ap) 358 { 359 if (tracefile == NULL) 360 return; 361 while (*ap) { 362 trstring(*ap++); 363 if (*ap) 364 putc(' ', tracefile); 365 else 366 putc('\n', tracefile); 367 } 368 fflush(tracefile); 369 } 370 371 372 void 373 opentrace(void) 374 { 375 char s[100]; 376 char *getenv(); 377 #ifdef O_APPEND 378 int flags; 379 #endif 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 #ifdef O_APPEND 403 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) 404 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 405 #endif 406 fputs("\nTracing started.\n", tracefile); 407 fflush(tracefile); 408 } 409 #endif /* DEBUG */ 410