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 __FBSDID("$FreeBSD$"); 42 43 #include <fcntl.h> 44 #include <stdio.h> 45 #include <stdlib.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 case NHERE: s = "<<"; dftfd = 0; break; 150 case NXHERE: 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 if (np->nfile.type == NHERE) { 162 fprintf(fp, "HERE"); 163 } else if (np->nfile.type == NXHERE) { 164 fprintf(fp, "XHERE"); 165 } else { 166 sharg(np->nfile.fname, fp); 167 } 168 first = 0; 169 } 170 } 171 172 173 174 static void 175 sharg(union node *arg, FILE *fp) 176 { 177 char *p; 178 struct nodelist *bqlist; 179 int subtype; 180 181 if (arg->type != NARG) { 182 printf("<node type %d>\n", arg->type); 183 fflush(stdout); 184 abort(); 185 } 186 bqlist = arg->narg.backquote; 187 for (p = arg->narg.text ; *p ; p++) { 188 switch (*p) { 189 case CTLESC: 190 putc(*++p, fp); 191 break; 192 case CTLVAR: 193 putc('$', fp); 194 putc('{', fp); 195 subtype = *++p; 196 if (subtype == VSLENGTH) 197 putc('#', fp); 198 199 while (*p != '=') 200 putc(*p++, fp); 201 202 if (subtype & VSNUL) 203 putc(':', fp); 204 205 switch (subtype & VSTYPE) { 206 case VSNORMAL: 207 putc('}', fp); 208 break; 209 case VSMINUS: 210 putc('-', fp); 211 break; 212 case VSPLUS: 213 putc('+', fp); 214 break; 215 case VSQUESTION: 216 putc('?', fp); 217 break; 218 case VSASSIGN: 219 putc('=', fp); 220 break; 221 case VSTRIMLEFT: 222 putc('#', fp); 223 break; 224 case VSTRIMLEFTMAX: 225 putc('#', fp); 226 putc('#', fp); 227 break; 228 case VSTRIMRIGHT: 229 putc('%', fp); 230 break; 231 case VSTRIMRIGHTMAX: 232 putc('%', fp); 233 putc('%', fp); 234 break; 235 case VSLENGTH: 236 break; 237 default: 238 printf("<subtype %d>", subtype); 239 } 240 break; 241 case CTLENDVAR: 242 putc('}', fp); 243 break; 244 case CTLBACKQ: 245 case CTLBACKQ|CTLQUOTE: 246 putc('$', fp); 247 putc('(', fp); 248 shtree(bqlist->n, -1, NULL, fp); 249 putc(')', fp); 250 break; 251 default: 252 putc(*p, fp); 253 break; 254 } 255 } 256 } 257 258 259 static void 260 indent(int amount, char *pfx, FILE *fp) 261 { 262 int i; 263 264 for (i = 0 ; i < amount ; i++) { 265 if (pfx && i == amount - 1) 266 fputs(pfx, fp); 267 putc('\t', fp); 268 } 269 } 270 271 272 /* 273 * Debugging stuff. 274 */ 275 276 277 FILE *tracefile; 278 279 #if DEBUG >= 2 280 int debug = 1; 281 #else 282 int debug = 0; 283 #endif 284 285 286 void 287 trputc(int c) 288 { 289 if (tracefile == NULL) 290 return; 291 putc(c, tracefile); 292 if (c == '\n') 293 fflush(tracefile); 294 } 295 296 297 void 298 sh_trace(const char *fmt, ...) 299 { 300 va_list va; 301 va_start(va, fmt); 302 if (tracefile != NULL) { 303 (void) vfprintf(tracefile, fmt, va); 304 if (strchr(fmt, '\n')) 305 (void) fflush(tracefile); 306 } 307 va_end(va); 308 } 309 310 311 void 312 trputs(const char *s) 313 { 314 if (tracefile == NULL) 315 return; 316 fputs(s, tracefile); 317 if (strchr(s, '\n')) 318 fflush(tracefile); 319 } 320 321 322 static void 323 trstring(char *s) 324 { 325 char *p; 326 char c; 327 328 if (tracefile == NULL) 329 return; 330 putc('"', tracefile); 331 for (p = s ; *p ; p++) { 332 switch (*p) { 333 case '\n': c = 'n'; goto backslash; 334 case '\t': c = 't'; goto backslash; 335 case '\r': c = 'r'; goto backslash; 336 case '"': c = '"'; goto backslash; 337 case '\\': c = '\\'; goto backslash; 338 case CTLESC: c = 'e'; goto backslash; 339 case CTLVAR: c = 'v'; goto backslash; 340 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; 341 case CTLBACKQ: c = 'q'; goto backslash; 342 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 343 backslash: putc('\\', tracefile); 344 putc(c, tracefile); 345 break; 346 default: 347 if (*p >= ' ' && *p <= '~') 348 putc(*p, tracefile); 349 else { 350 putc('\\', tracefile); 351 putc(*p >> 6 & 03, tracefile); 352 putc(*p >> 3 & 07, tracefile); 353 putc(*p & 07, tracefile); 354 } 355 break; 356 } 357 } 358 putc('"', tracefile); 359 } 360 361 362 void 363 trargs(char **ap) 364 { 365 if (tracefile == NULL) 366 return; 367 while (*ap) { 368 trstring(*ap++); 369 if (*ap) 370 putc(' ', tracefile); 371 else 372 putc('\n', tracefile); 373 } 374 fflush(tracefile); 375 } 376 377 378 void 379 opentrace(void) 380 { 381 char s[100]; 382 int flags; 383 384 if (!debug) 385 return; 386 #ifdef not_this_way 387 { 388 char *p; 389 if ((p = getenv("HOME")) == NULL) { 390 if (geteuid() == 0) 391 p = "/"; 392 else 393 p = "/tmp"; 394 } 395 strcpy(s, p); 396 strcat(s, "/trace"); 397 } 398 #else 399 strcpy(s, "./trace"); 400 #endif /* not_this_way */ 401 if ((tracefile = fopen(s, "a")) == NULL) { 402 fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno)); 403 return; 404 } 405 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) 406 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 407 fputs("\nTracing started.\n", tracefile); 408 fflush(tracefile); 409 } 410 #endif /* DEBUG */ 411