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