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