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