1145519Sdarrenr/*- 2145510Sdarrenr * SPDX-License-Identifier: BSD-3-Clause 331183Speter * 431183Speter * Copyright (c) 1991, 1993 531183Speter * The Regents of the University of California. All rights reserved. 631183Speter * 780486Sdarrenr * This code is derived from software contributed to Berkeley by 831183Speter * Kenneth Almquist. 931183Speter * 1031183Speter * Redistribution and use in source and binary forms, with or without 1131183Speter * modification, are permitted provided that the following conditions 1231183Speter * are met: 1331183Speter * 1. Redistributions of source code must retain the above copyright 1431183Speter * notice, this list of conditions and the following disclaimer. 1531183Speter * 2. Redistributions in binary form must reproduce the above copyright 1631183Speter * notice, this list of conditions and the following disclaimer in the 1731183Speter * documentation and/or other materials provided with the distribution. 1831183Speter * 3. Neither the name of the University nor the names of its contributors 1931183Speter * may be used to endorse or promote products derived from this software 2031183Speter * without specific prior written permission. 2131183Speter * 2231183Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2331183Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2431183Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2531183Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2631183Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2731183Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2831183Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2931183Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3031183Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3131183Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3231183Speter * SUCH DAMAGE. 3331183Speter */ 3431183Speter 3531183Speter#include <fcntl.h> 3631183Speter#include <stdio.h> 3731183Speter#include <stdlib.h> 3831183Speter#include <stdarg.h> 3931183Speter#include <errno.h> 4031183Speter 4131183Speter#include "shell.h" 4231183Speter#include "parser.h" 4331183Speter#include "nodes.h" 4431183Speter#include "mystring.h" 4531183Speter#include "show.h" 4631183Speter 4731183Speter 4831183Speter#ifdef DEBUG 4953024Sguidostatic void shtree(union node *, int, char *, FILE*); 5031183Speterstatic void shcmd(union node *, FILE *); 5131183Speterstatic void sharg(union node *, FILE *); 5231183Speterstatic void indent(int, char *, FILE *); 5331183Speterstatic void trstring(char *); 5431183Speter 5531183Speter 5631183Spetervoid 5731183Spetershowtree(union node *n) 5831183Speter{ 5931183Speter trputs("showtree called\n"); 6031183Speter shtree(n, 1, NULL, stdout); 6131183Speter} 6231183Speter 6331183Speter 6431183Speterstatic void 6531183Spetershtree(union node *n, int ind, char *pfx, FILE *fp) 6631183Speter{ 6731183Speter struct nodelist *lp; 6831183Speter const char *s; 6931183Speter 7031183Speter if (n == NULL) 7131183Speter return; 7231183Speter 7331183Speter indent(ind, pfx, fp); 7431183Speter switch(n->type) { 7531183Speter case NSEMI: 7631183Speter s = "; "; 7731183Speter goto binop; 7831183Speter case NAND: 7931183Speter s = " && "; 8031183Speter goto binop; 8131183Speter case NOR: 8231183Speter s = " || "; 8331183Speterbinop: 8431183Speter shtree(n->nbinary.ch1, ind, NULL, fp); 8531183Speter /* if (ind < 0) */ 8631183Speter fputs(s, fp); 8731183Speter shtree(n->nbinary.ch2, ind, NULL, fp); 8831183Speter break; 8931183Speter case NCMD: 9031183Speter shcmd(n, fp); 9131183Speter if (ind >= 0) 9231183Speter putc('\n', fp); 9331183Speter break; 9431183Speter case NPIPE: 9531183Speter for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { 9631183Speter shcmd(lp->n, fp); 9753024Sguido if (lp->next) 9831183Speter fputs(" | ", fp); 9931183Speter } 10031183Speter if (n->npipe.backgnd) 10131183Speter fputs(" &", fp); 10231183Speter if (ind >= 0) 10331183Speter putc('\n', fp); 10431183Speter break; 10531183Speter default: 10631183Speter fprintf(fp, "<node type %d>", n->type); 10737074Speter if (ind >= 0) 10831183Speter putc('\n', fp); 109 break; 110 } 111} 112 113 114 115static void 116shcmd(union node *cmd, FILE *fp) 117{ 118 union node *np; 119 int first; 120 const char *s; 121 int dftfd; 122 123 first = 1; 124 for (np = cmd->ncmd.args ; np ; np = np->narg.next) { 125 if (! first) 126 putchar(' '); 127 sharg(np, fp); 128 first = 0; 129 } 130 for (np = cmd->ncmd.redirect ; np ; np = np->nfile.next) { 131 if (! first) 132 putchar(' '); 133 switch (np->nfile.type) { 134 case NTO: s = ">"; dftfd = 1; break; 135 case NAPPEND: s = ">>"; dftfd = 1; break; 136 case NTOFD: s = ">&"; dftfd = 1; break; 137 case NCLOBBER: s = ">|"; dftfd = 1; break; 138 case NFROM: s = "<"; dftfd = 0; break; 139 case NFROMTO: s = "<>"; dftfd = 0; break; 140 case NFROMFD: s = "<&"; dftfd = 0; break; 141 case NHERE: s = "<<"; dftfd = 0; break; 142 case NXHERE: s = "<<"; dftfd = 0; break; 143 default: s = "*error*"; dftfd = 0; break; 144 } 145 if (np->nfile.fd != dftfd) 146 fprintf(fp, "%d", np->nfile.fd); 147 fputs(s, fp); 148 if (np->nfile.type == NTOFD || np->nfile.type == NFROMFD) { 149 if (np->ndup.dupfd >= 0) 150 fprintf(fp, "%d", np->ndup.dupfd); 151 else 152 fprintf(fp, "-"); 153 } else if (np->nfile.type == NHERE) { 154 fprintf(fp, "HERE"); 155 } else if (np->nfile.type == NXHERE) { 156 fprintf(fp, "XHERE"); 157 } else { 158 sharg(np->nfile.fname, fp); 159 } 160 first = 0; 161 } 162} 163 164 165 166static void 167sharg(union node *arg, FILE *fp) 168{ 169 char *p; 170 struct nodelist *bqlist; 171 int subtype; 172 173 if (arg->type != NARG) { 174 printf("<node type %d>\n", arg->type); 175 fflush(stdout); 176 abort(); 177 } 178 bqlist = arg->narg.backquote; 179 for (p = arg->narg.text ; *p ; p++) { 180 switch (*p) { 181 case CTLESC: 182 putc(*++p, fp); 183 break; 184 case CTLVAR: 185 putc('$', fp); 186 putc('{', fp); 187 subtype = *++p; 188 if (subtype == VSLENGTH) 189 putc('#', fp); 190 191 while (*p != '=') 192 putc(*p++, fp); 193 194 if (subtype & VSNUL) 195 putc(':', fp); 196 197 switch (subtype & VSTYPE) { 198 case VSNORMAL: 199 putc('}', fp); 200 break; 201 case VSMINUS: 202 putc('-', fp); 203 break; 204 case VSPLUS: 205 putc('+', fp); 206 break; 207 case VSQUESTION: 208 putc('?', fp); 209 break; 210 case VSASSIGN: 211 putc('=', fp); 212 break; 213 case VSTRIMLEFT: 214 putc('#', fp); 215 break; 216 case VSTRIMLEFTMAX: 217 putc('#', fp); 218 putc('#', fp); 219 break; 220 case VSTRIMRIGHT: 221 putc('%', fp); 222 break; 223 case VSTRIMRIGHTMAX: 224 putc('%', fp); 225 putc('%', fp); 226 break; 227 case VSLENGTH: 228 break; 229 default: 230 printf("<subtype %d>", subtype); 231 } 232 break; 233 case CTLENDVAR: 234 putc('}', fp); 235 break; 236 case CTLBACKQ: 237 case CTLBACKQ|CTLQUOTE: 238 putc('$', fp); 239 putc('(', fp); 240 shtree(bqlist->n, -1, NULL, fp); 241 putc(')', fp); 242 break; 243 default: 244 putc(*p, fp); 245 break; 246 } 247 } 248} 249 250 251static void 252indent(int amount, char *pfx, FILE *fp) 253{ 254 int i; 255 256 for (i = 0 ; i < amount ; i++) { 257 if (pfx && i == amount - 1) 258 fputs(pfx, fp); 259 putc('\t', fp); 260 } 261} 262 263 264/* 265 * Debugging stuff. 266 */ 267 268 269static FILE *tracefile; 270#if DEBUG >= 2 271int debug = 1; 272#else 273int debug = 0; 274#endif 275 276 277void 278trputc(int c) 279{ 280 if (tracefile == NULL) 281 return; 282 putc(c, tracefile); 283 if (c == '\n') 284 fflush(tracefile); 285} 286 287 288void 289sh_trace(const char *fmt, ...) 290{ 291 va_list va; 292 va_start(va, fmt); 293 if (tracefile != NULL) { 294 (void) vfprintf(tracefile, fmt, va); 295 if (strchr(fmt, '\n')) 296 (void) fflush(tracefile); 297 } 298 va_end(va); 299} 300 301 302void 303trputs(const char *s) 304{ 305 if (tracefile == NULL) 306 return; 307 fputs(s, tracefile); 308 if (strchr(s, '\n')) 309 fflush(tracefile); 310} 311 312 313static void 314trstring(char *s) 315{ 316 char *p; 317 char c; 318 319 if (tracefile == NULL) 320 return; 321 putc('"', tracefile); 322 for (p = s ; *p ; p++) { 323 switch (*p) { 324 case '\n': c = 'n'; goto backslash; 325 case '\t': c = 't'; goto backslash; 326 case '\r': c = 'r'; goto backslash; 327 case '"': c = '"'; goto backslash; 328 case '\\': c = '\\'; goto backslash; 329 case CTLESC: c = 'e'; goto backslash; 330 case CTLVAR: c = 'v'; goto backslash; 331 case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; 332 case CTLBACKQ: c = 'q'; goto backslash; 333 case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; 334backslash: putc('\\', tracefile); 335 putc(c, tracefile); 336 break; 337 default: 338 if (*p >= ' ' && *p <= '~') 339 putc(*p, tracefile); 340 else { 341 putc('\\', tracefile); 342 putc(*p >> 6 & 03, tracefile); 343 putc(*p >> 3 & 07, tracefile); 344 putc(*p & 07, tracefile); 345 } 346 break; 347 } 348 } 349 putc('"', tracefile); 350} 351 352 353void 354trargs(char **ap) 355{ 356 if (tracefile == NULL) 357 return; 358 while (*ap) { 359 trstring(*ap++); 360 if (*ap) 361 putc(' ', tracefile); 362 else 363 putc('\n', tracefile); 364 } 365 fflush(tracefile); 366} 367 368 369void 370opentrace(void) 371{ 372 char s[100]; 373 int flags; 374 375 if (!debug) 376 return; 377#ifdef not_this_way 378 { 379 char *p; 380 if ((p = getenv("HOME")) == NULL) { 381 if (geteuid() == 0) 382 p = "/"; 383 else 384 p = "/tmp"; 385 } 386 strcpy(s, p); 387 strcat(s, "/trace"); 388 } 389#else 390 strcpy(s, "./trace"); 391#endif /* not_this_way */ 392 if ((tracefile = fopen(s, "a")) == NULL) { 393 fprintf(stderr, "Can't open %s: %s\n", s, strerror(errno)); 394 return; 395 } 396 if ((flags = fcntl(fileno(tracefile), F_GETFL, 0)) >= 0) 397 fcntl(fileno(tracefile), F_SETFL, flags | O_APPEND); 398 fputs("\nTracing started.\n", tracefile); 399 fflush(tracefile); 400} 401#endif /* DEBUG */ 402