1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1991, 1993 5 * The Regents of the University of California. 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 35 #ifndef lint 36 #if 0 37 static char sccsid[] = "@(#)show.c 8.3 (Berkeley) 5/4/95"; 38 #endif 39 #endif /* not lint */ 40 #include <sys/cdefs.h> 41 #include <fcntl.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <stdarg.h> 45 #include <errno.h> 46 47 #include "shell.h" 48 #include "parser.h" 49 #include "nodes.h" 50 #include "mystring.h" 51 #include "show.h" 52 53 54 #ifdef DEBUG 55 static void shtree(union node *, int, char *, FILE*); 56 static void shcmd(union node *, FILE *); 57 static void sharg(union node *, FILE *); 58 static void indent(int, char *, FILE *); 59 static void trstring(char *); 60 61 62 void 63 showtree(union node *n) 64 { 65 trputs("showtree called\n"); 66 shtree(n, 1, NULL, stdout); 67 } 68 69 70 static void 71 shtree(union node *n, int ind, char *pfx, FILE *fp) 72 { 73 struct nodelist *lp; 74 const char *s; 75 76 if (n == NULL) 77 return; 78 79 indent(ind, pfx, fp); 80 switch(n->type) { 81 case NSEMI: 82 s = "; "; 83 goto binop; 84 case NAND: 85 s = " && "; 86 goto binop; 87 case NOR: 88 s = " || "; 89 binop: 90 shtree(n->nbinary.ch1, ind, NULL, fp); 91 /* if (ind < 0) */ 92 fputs(s, fp); 93 shtree(n->nbinary.ch2, ind, NULL, fp); 94 break; 95 case NCMD: 96 shcmd(n, fp); 97 if (ind >= 0) 98 putc('\n', fp); 99 break; 100 case NPIPE: 101 for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 102 shcmd(lp->n, fp); 103 if (lp->next) 104 fputs(" | ", fp); 105 } 106 if (n->npipe.backgnd) 107 fputs(" &", fp); 108 if (ind >= 0) 109 putc('\n', fp); 110 break; 111 default: 112 fprintf(fp, "<node type %d>", n->type); 113 if (ind >= 0) 114 putc('\n', fp); 115 break; 116 } 117 } 118 119 120 121 static void 122 shcmd(union node *cmd, FILE *fp) 123 { 124 union node *np; 125 int first; 126 const char *s; 127 int dftfd; 128 129 first = 1; 130 for (np = cmd->ncmd.args ; np ; np = np->narg.next) { 131 if (! first) 132 putchar(' '); 133 sharg(np, fp); 134 first = 0; 135 } 136 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { 137 if (! first) 138 putchar(' '); 139 switch (np->nfile.type) { 140 case NTO: s = ">"; dftfd = 1; break; 141 case NAPPEND: s = ">>"; dftfd = 1; break; 142 case NTOFD: s = ">&"; dftfd = 1; break; 143 case NCLOBBER: s = ">|"; dftfd = 1; break; 144 case NFROM: s = "<"; dftfd = 0; break; 145 case NFROMTO: s = "<>"; dftfd = 0; break; 146 case NFROMFD: s = "<&"; dftfd = 0; break; 147 case NHERE: s = "<<"; dftfd = 0; break; 148 case NXHERE: 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 if (np->nfile.type == NHERE) { 160 fprintf(fp, "HERE"); 161 } else if (np->nfile.type == NXHERE) { 162 fprintf(fp, "XHERE"); 163 } else { 164 sharg(np->nfile.fname, fp); 165 } 166 first = 0; 167 } 168 } 169 170 171 172 static void 173 sharg(union node *arg, FILE *fp) 174 { 175 char *p; 176 struct nodelist *bqlist; 177 int subtype; 178 179 if (arg->type != NARG) { 180 printf("<node type %d>\n", arg->type); 181 fflush(stdout); 182 abort(); 183 } 184 bqlist = arg->narg.backquote; 185 for (p = arg->narg.text ; *p ; p++) { 186 switch (*p) { 187 case CTLESC: 188 putc(*++p, fp); 189 break; 190 case CTLVAR: 191 putc('$', fp); 192 putc('{', fp); 193 subtype = *++p; 194 if (subtype == VSLENGTH) 195 putc('#', fp); 196 197 while (*p != '=') 198 putc(*p++, fp); 199 200 if (subtype & VSNUL) 201 putc(':', fp); 202 203 switch (subtype & VSTYPE) { 204 case VSNORMAL: 205 putc('}', fp); 206 break; 207 case VSMINUS: 208 putc('-', fp); 209 break; 210 case VSPLUS: 211 putc('+', fp); 212 break; 213 case VSQUESTION: 214 putc('?', fp); 215 break; 216 case VSASSIGN: 217 putc('=', fp); 218 break; 219 case VSTRIMLEFT: 220 putc('#', fp); 221 break; 222 case VSTRIMLEFTMAX: 223 putc('#', fp); 224 putc('#', fp); 225 break; 226 case VSTRIMRIGHT: 227 putc('%', fp); 228 break; 229 case VSTRIMRIGHTMAX: 230 putc('%', fp); 231 putc('%', fp); 232 break; 233 case VSLENGTH: 234 break; 235 default: 236 printf("<subtype %d>", subtype); 237 } 238 break; 239 case CTLENDVAR: 240 putc('}', fp); 241 break; 242 case CTLBACKQ: 243 case CTLBACKQ|CTLQUOTE: 244 putc('$', fp); 245 putc('(', fp); 246 shtree(bqlist->n, -1, NULL, fp); 247 putc(')', fp); 248 break; 249 default: 250 putc(*p, fp); 251 break; 252 } 253 } 254 } 255 256 257 static void 258 indent(int amount, char *pfx, FILE *fp) 259 { 260 int i; 261 262 for (i = 0 ; i < amount ; i++) { 263 if (pfx && i == amount - 1) 264 fputs(pfx, fp); 265 putc('\t', fp); 266 } 267 } 268 269 270 /* 271 * Debugging stuff. 272 */ 273 274 275 static FILE *tracefile; 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 (void) vfprintf(tracefile, fmt, va); 301 if (strchr(fmt, '\n')) 302 (void) 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 strcpy(s, p); 393 strcat(s, "/trace"); 394 } 395 #else 396 strcpy(s, "./trace"); 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