]>
Commit | Line | Data |
---|---|---|
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: head/bin/sh/show.c 326025 2017-11-20 19:49:47Z pfg $"); | |
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 */ |