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