1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28
29 /*
30 * UNIX shell
31 */
32
33 #include "defs.h"
34 #include "sym.h"
35 #include <wait.h>
36
37 static unsigned char quote; /* used locally */
38 static unsigned char quoted; /* used locally */
39 static int getch();
40 static void comsubst(int);
41 static void flush(int);
42
43 static void
copyto(unsigned char endch,int trimflag)44 copyto(unsigned char endch, int trimflag)
45 /* trimflag - flag to check if argument will be trimmed */
46 {
47 unsigned int c;
48 unsigned int d;
49 unsigned char *pc;
50
51 while ((c = getch(endch, trimflag)) != endch && c)
52 if (quote) {
53 if(c == '\\') { /* don't interpret next character */
54 if (staktop >= brkend)
55 growstak(staktop);
56 pushstak(c);
57 d = readwc();
58 if(!escchar(d)) { /* both \ and following
59 character are quoted if next
60 character is not $, `, ", or \*/
61 if (staktop >= brkend)
62 growstak(staktop);
63 pushstak('\\');
64 if (staktop >= brkend)
65 growstak(staktop);
66 pushstak('\\');
67 pc = readw(d);
68 /* push entire multibyte char */
69 while(*pc) {
70 if (staktop >= brkend)
71 growstak(staktop);
72 pushstak(*pc++);
73 }
74 } else {
75 pc = readw(d);
76 /* d might be NULL */
77 /* Evenif d is NULL, we have to save it */
78 if (*pc) {
79 while (*pc) {
80 if (staktop >= brkend)
81 growstak(staktop);
82 pushstak(*pc++);
83 }
84 } else {
85 if (staktop >= brkend)
86 growstak(staktop);
87 pushstak(*pc);
88 }
89 }
90 } else { /* push escapes onto stack to quote characters */
91 pc = readw(c);
92 if (staktop >= brkend)
93 growstak(staktop);
94 pushstak('\\');
95 while(*pc) {
96 if (staktop >= brkend)
97 growstak(staktop);
98 pushstak(*pc++);
99 }
100 }
101 } else if(c == '\\') {
102 c = readwc(); /* get character to be escaped */
103 if (staktop >= brkend)
104 growstak(staktop);
105 pushstak('\\');
106 pc = readw(c);
107 /* c might be NULL */
108 /* Evenif c is NULL, we have to save it */
109 if (*pc) {
110 while (*pc) {
111 if (staktop >= brkend)
112 growstak(staktop);
113 pushstak(*pc++);
114 }
115 } else {
116 if (staktop >= brkend)
117 growstak(staktop);
118 pushstak(*pc);
119 }
120 } else {
121 pc = readw(c);
122 while (*pc) {
123 if (staktop >= brkend)
124 growstak(staktop);
125 pushstak(*pc++);
126 }
127 }
128 if (staktop >= brkend)
129 growstak(staktop);
130 zerostak();
131 if (c != endch)
132 error(badsub);
133 }
134
135 static void
skipto(unsigned char endch)136 skipto(unsigned char endch)
137 {
138 /*
139 * skip chars up to }
140 */
141 unsigned int c;
142
143 while ((c = readwc()) && c != endch)
144 {
145 switch (c)
146 {
147 case SQUOTE:
148 skipto(SQUOTE);
149 break;
150
151 case DQUOTE:
152 skipto(DQUOTE);
153 break;
154
155 case DOLLAR:
156 if (readwc() == BRACE)
157 skipto('}');
158 }
159 }
160 if (c != endch)
161 error(badsub);
162 }
163
164 static
getch(endch,trimflag)165 int getch(endch, trimflag)
166 unsigned char endch;
167 int trimflag; /* flag to check if an argument is going to be trimmed, here document
168 output is never trimmed
169 */
170 {
171 unsigned int d;
172 int atflag; /* flag to check if $@ has already been seen within double
173 quotes */
174 retry:
175 d = readwc();
176 if (!subchar(d))
177 return(d);
178
179 if (d == DOLLAR)
180 {
181 unsigned int c;
182
183 if ((c = readwc(), dolchar(c)))
184 {
185 struct namnod *n = (struct namnod *)NIL;
186 int dolg = 0;
187 BOOL bra;
188 BOOL nulflg;
189 unsigned char *argp, *v;
190 unsigned char idb[2];
191 unsigned char *id = idb;
192
193 if (bra = (c == BRACE))
194 c = readwc();
195 if (letter(c))
196 {
197 argp = (unsigned char *)relstak();
198 while (alphanum(c))
199 {
200 if (staktop >= brkend)
201 growstak(staktop);
202 pushstak(c);
203 c = readwc();
204 }
205 if (staktop >= brkend)
206 growstak(staktop);
207 zerostak();
208 n = lookup(absstak(argp));
209 setstak(argp);
210 if (n->namflg & N_FUNCTN)
211 error(badsub);
212 v = n->namval;
213 id = (unsigned char *)n->namid;
214 peekc = c | MARK;
215 }
216 else if (digchar(c))
217 {
218 *id = c;
219 idb[1] = 0;
220 if (astchar(c))
221 {
222 if(c == '@' && !atflag && quote) {
223 quoted--;
224 atflag = 1;
225 }
226 dolg = 1;
227 c = '1';
228 }
229 c -= '0';
230 v = ((c == 0) ? cmdadr : ((int)c <= dolc) ? dolv[c] : (unsigned char *)(dolg = 0));
231 }
232 else if (c == '$')
233 v = pidadr;
234 else if (c == '!')
235 v = pcsadr;
236 else if (c == '#')
237 {
238 itos(dolc);
239 v = numbuf;
240 }
241 else if (c == '?')
242 {
243 itos(retval);
244 v = numbuf;
245 }
246 else if (c == '-')
247 v = flagadr;
248 else if (bra)
249 error(badsub);
250 else
251 goto retry;
252 c = readwc();
253 if (c == ':' && bra) /* null and unset fix */
254 {
255 nulflg = 1;
256 c = readwc();
257 }
258 else
259 nulflg = 0;
260 if (!defchar(c) && bra)
261 error(badsub);
262 argp = 0;
263 if (bra)
264 {
265 if (c != '}')
266 {
267 argp = (unsigned char *)relstak();
268 if ((v == 0 || (nulflg && *v == 0)) ^ (setchar(c)))
269 copyto('}', trimflag);
270 else
271 skipto('}');
272 argp = absstak(argp);
273 }
274 }
275 else
276 {
277 peekc = c | MARK;
278 c = 0;
279 }
280 if (v && (!nulflg || *v))
281 {
282
283 if (c != '+')
284 {
285 for (;;)
286 {
287 if (*v == 0 && quote) {
288 if (staktop >= brkend)
289 growstak(staktop);
290 pushstak('\\');
291 if (staktop >= brkend)
292 growstak(staktop);
293 pushstak('\0');
294 } else {
295 while (c = *v) {
296 wchar_t wc;
297 int length;
298 if ((length = mbtowc(&wc, (char *)v, MB_LEN_MAX)) <= 0)
299 length = 1;
300
301 if(quote || (c == '\\' && trimflag)) {
302 if (staktop >= brkend)
303 growstak(staktop);
304 pushstak('\\');
305 }
306 while(length-- > 0) {
307 if (staktop >= brkend)
308 growstak(staktop);
309 pushstak(*v++);
310 }
311 }
312 }
313
314 if (dolg == 0 || (++dolg > dolc))
315 break;
316 else /* $* and $@ expansion */
317 {
318 v = dolv[dolg];
319 if(*id == '*' && quote) {
320 /* push quoted space so that " $* " will not be broken into separate arguments */
321 if (staktop >= brkend)
322 growstak(staktop);
323 pushstak('\\');
324 }
325 if (staktop >= brkend)
326 growstak(staktop);
327 pushstak(' ');
328 }
329 }
330 }
331 }
332 else if (argp)
333 {
334 if (c == '?') {
335 if(trimflag)
336 trim(argp);
337 failed(id, *argp ? (const char *)argp :
338 badparam);
339 }
340 else if (c == '=')
341 {
342 if (n)
343 {
344 int strlngth = staktop - stakbot;
345 unsigned char *savptr = fixstak();
346 unsigned char *newargp;
347 /*
348 * copy word onto stack, trim it, and then
349 * do assignment
350 */
351 usestak();
352 while(c = *argp) {
353 wchar_t wc;
354 int len;
355
356 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0)
357 len = 1;
358
359 if(c == '\\' && trimflag) {
360 argp++;
361 if (*argp == 0) {
362 argp++;
363 continue;
364 }
365 if ((len = mbtowc(&wc, (char *)argp, MB_LEN_MAX)) <= 0)
366 len = 1;
367 }
368 while(len-- > 0) {
369 if (staktop >= brkend)
370 growstak(staktop);
371 pushstak(*argp++);
372 }
373 }
374 newargp = fixstak();
375 assign(n, newargp);
376 tdystak(savptr);
377 (void) memcpystak(stakbot, savptr, strlngth);
378 staktop = stakbot + strlngth;
379 }
380 else
381 error(badsub);
382 }
383 }
384 else if (flags & setflg)
385 failed(id, unset);
386 goto retry;
387 }
388 else
389 peekc = c | MARK;
390 }
391 else if (d == endch)
392 return(d);
393 else if (d == SQUOTE)
394 {
395 comsubst(trimflag);
396 goto retry;
397 }
398 else if (d == DQUOTE && trimflag)
399 {
400 if(!quote) {
401 atflag = 0;
402 quoted++;
403 }
404 quote ^= QUOTE;
405 goto retry;
406 }
407 return(d);
408 }
409
410 unsigned char *
macro(as)411 macro(as)
412 unsigned char *as;
413 {
414 /*
415 * Strip "" and do $ substitution
416 * Leaves result on top of stack
417 */
418 BOOL savqu = quoted;
419 unsigned char savq = quote;
420 struct filehdr fb;
421
422 push(&fb);
423 estabf(as);
424 usestak();
425 quote = 0;
426 quoted = 0;
427 copyto(0, 1);
428 pop();
429 if (quoted && (stakbot == staktop)) {
430 if (staktop >= brkend)
431 growstak(staktop);
432 pushstak('\\');
433 if (staktop >= brkend)
434 growstak(staktop);
435 pushstak('\0');
436 /*
437 * above is the fix for *'.c' bug
438 */
439 }
440 quote = savq;
441 quoted = savqu;
442 return(fixstak());
443 }
444 /* Save file descriptor for command substitution */
445 int savpipe = -1;
446
447 static void
comsubst(int trimflag)448 comsubst(int trimflag)
449 /* trimflag - used to determine if argument will later be trimmed */
450 {
451 /*
452 * command substn
453 */
454 struct fileblk cb;
455 unsigned int d;
456 int strlngth = staktop - stakbot;
457 unsigned char *oldstaktop;
458 unsigned char *savptr = fixstak();
459 unsigned char *pc;
460
461 usestak();
462 while ((d = readwc()) != SQUOTE && d) {
463 if(d == '\\') {
464 d = readwc();
465 if(!escchar(d) || (d == '"' && !quote)) {
466 /* trim quotes for `, \, or " if command substitution is within
467 double quotes */
468 if (staktop >= brkend)
469 growstak(staktop);
470 pushstak('\\');
471 }
472 }
473 pc = readw(d);
474 /* d might be NULL */
475 if (*pc) {
476 while (*pc) {
477 if (staktop >= brkend)
478 growstak(staktop);
479 pushstak(*pc++);
480 }
481 } else {
482 if (staktop >= brkend)
483 growstak(staktop);
484 pushstak(*pc);
485 }
486 }
487 {
488 unsigned char *argc;
489
490 argc = fixstak();
491 push(&cb);
492 estabf(argc); /* read from string */
493 }
494 {
495 struct trenod *t;
496 int pv[2];
497
498 /*
499 * this is done like this so that the pipe
500 * is open only when needed
501 */
502 t = makefork(FPOU, cmd(EOFSYM, MTFLG | NLFLG ));
503 chkpipe(pv);
504 savpipe = pv[OTPIPE];
505 initf(pv[INPIPE]); /* read from pipe */
506 execute(t, XEC_NOSTOP, (int)(flags & errflg), 0, pv);
507 close(pv[OTPIPE]);
508 savpipe = -1;
509 }
510 tdystak(savptr);
511 (void) memcpystak(stakbot, savptr, strlngth);
512 oldstaktop = staktop = stakbot + strlngth;
513 while (d = readwc()) {
514 if(quote || (d == '\\' && trimflag)) {
515 unsigned char *rest;
516 /* quote output from command subst. if within double
517 quotes or backslash part of output */
518 rest = readw(d);
519 if (staktop >= brkend)
520 growstak(staktop);
521 pushstak('\\');
522 while(d = *rest++) {
523 /* Pick up all of multibyte character */
524 if (staktop >= brkend)
525 growstak(staktop);
526 pushstak(d);
527 }
528 }
529 else {
530 pc = readw(d);
531 while (*pc) {
532 if (staktop >= brkend)
533 growstak(staktop);
534 pushstak(*pc++);
535 }
536 }
537 }
538 {
539 extern pid_t parent;
540 int stat;
541 int rc;
542 int ret = 0;
543
544 while ((ret = waitpid(parent,&stat,0)) != parent) {
545 /* break out if waitpid(2) has failed */
546 if (ret == -1)
547 break;
548 }
549 if (WIFEXITED(stat))
550 rc = WEXITSTATUS(stat);
551 else
552 rc = (WTERMSIG(stat) | SIGFLG);
553 if (rc && (flags & errflg))
554 exitsh(rc);
555 exitval = rc;
556 flags |= eflag;
557 exitset();
558 }
559 while (oldstaktop != staktop)
560 { /* strip off trailing newlines from command substitution only */
561 if ((*--staktop) != NL)
562 {
563 ++staktop;
564 break;
565 } else if(quote)
566 staktop--; /* skip past backslashes if quoting */
567 }
568 pop();
569 }
570
571 #define CPYSIZ 512
572
573 void
subst(int in,int ot)574 subst(int in, int ot)
575 {
576 unsigned int c;
577 struct fileblk fb;
578 int count = CPYSIZ;
579 unsigned char *pc;
580
581 push(&fb);
582 initf(in);
583 /*
584 * DQUOTE used to stop it from quoting
585 */
586 while (c = (getch(DQUOTE, 0))) /* read characters from here document
587 and interpret them */
588 {
589 if(c == '\\') {
590 c = readwc(); /* check if character in here document is
591 escaped */
592 if(!escchar(c) || c == '"') {
593 if (staktop >= brkend)
594 growstak(staktop);
595 pushstak('\\');
596 }
597 }
598 pc = readw(c);
599 /* c might be NULL */
600 if (*pc) {
601 while (*pc) {
602 if (staktop >= brkend)
603 growstak(staktop);
604 pushstak(*pc++);
605 }
606 } else {
607 if (staktop >= brkend)
608 growstak(staktop);
609 pushstak(*pc);
610 }
611 if (--count == 0)
612 {
613 flush(ot);
614 count = CPYSIZ;
615 }
616 }
617 flush(ot);
618 pop();
619 }
620
621 static void
flush(int ot)622 flush(int ot)
623 {
624 write(ot, stakbot, staktop - stakbot);
625 if (flags & execpr)
626 write(output, stakbot, staktop - stakbot);
627 staktop = stakbot;
628 }
629