1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * David Korn <dgk@research.att.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21 /*
22 * UNIX shell
23 *
24 * S. R. Bourne
25 * Rewritten by David Korn
26 * AT&T Labs
27 *
28 */
29 /*
30 * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
31 */
32
33 #include "defs.h"
34 #include "path.h"
35 #include "builtins.h"
36 #include "terminal.h"
37 #include "edit.h"
38 #include "FEATURE/poll"
39 #if SHOPT_KIA
40 # include "shlex.h"
41 # include "io.h"
42 #endif /* SHOPT_KIA */
43 #if SHOPT_PFSH
44 # define PFSHOPT "P"
45 #else
46 # define PFSHOPT
47 #endif
48 #if SHOPT_BASH
49 # define BASHOPT "\374"
50 #else
51 # define BASHOPT
52 #endif
53 #if SHOPT_HISTEXPAND
54 # define HFLAG "H"
55 #else
56 # define HFLAG ""
57 #endif
58
59 #define SORT 1
60 #define PRINT 2
61
62 static char *null;
63
64 /* The following order is determined by sh_optset */
65 static const char optksh[] = PFSHOPT BASHOPT "DircabefhkmnpstuvxBCGEl" HFLAG;
66 static const int flagval[] =
67 {
68 #if SHOPT_PFSH
69 SH_PFSH,
70 #endif
71 #if SHOPT_BASH
72 SH_POSIX,
73 #endif
74 SH_DICTIONARY, SH_INTERACTIVE, SH_RESTRICTED, SH_CFLAG,
75 SH_ALLEXPORT, SH_NOTIFY, SH_ERREXIT, SH_NOGLOB, SH_TRACKALL,
76 SH_KEYWORD, SH_MONITOR, SH_NOEXEC, SH_PRIVILEGED, SH_SFLAG, SH_TFLAG,
77 SH_NOUNSET, SH_VERBOSE, SH_XTRACE, SH_BRACEEXPAND, SH_NOCLOBBER,
78 SH_GLOBSTARS, SH_RC, SH_LOGIN_SHELL,
79 #if SHOPT_HISTEXPAND
80 SH_HISTEXPAND,
81 #endif
82 0
83 };
84
85 #define NUM_OPTS (sizeof(flagval)/sizeof(*flagval))
86
87 typedef struct _arg_
88 {
89 Shell_t *sh;
90 struct dolnod *argfor; /* linked list of blocks to be cleaned up */
91 struct dolnod *dolh;
92 char flagadr[NUM_OPTS+1];
93 #if SHOPT_KIA
94 char *kiafile;
95 #endif /* SHOPT_KIA */
96 } Arg_t;
97
98 static int arg_expand(Shell_t*,struct argnod*,struct argnod**,int);
99 static void sh_argset(Arg_t*, char *[]);
100
101
102 /* ======== option handling ======== */
103
sh_argopen(Shell_t * shp)104 void *sh_argopen(Shell_t *shp)
105 {
106 void *addr = newof(0,Arg_t,1,0);
107 Arg_t *ap = (Arg_t*)addr;
108 ap->sh = shp;
109 return(addr);
110 }
111
infof(Opt_t * op,Sfio_t * sp,const char * s,Optdisc_t * dp)112 static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
113 {
114 #if SHOPT_BASH
115 extern const char sh_bash1[], sh_bash2[];
116 if(strcmp(s,"bash1")==0)
117 {
118 if(sh_isoption(SH_BASH))
119 sfputr(sp,sh_bash1,-1);
120 }
121 else if(strcmp(s,"bash2")==0)
122 {
123 if(sh_isoption(SH_BASH))
124 sfputr(sp,sh_bash2,-1);
125 }
126 else if(*s==':' && sh_isoption(SH_BASH))
127 sfputr(sp,s,-1);
128 else
129 #endif
130 if(*s!=':')
131 sfputr(sp,sh_set,-1);
132 return(1);
133 }
134
135 /*
136 * This routine turns options on and off
137 * The options "PDicr" are illegal from set command.
138 * The -o option is used to set option by name
139 * This routine returns the number of non-option arguments
140 */
sh_argopts(int argc,register char * argv[],void * context)141 int sh_argopts(int argc,register char *argv[], void *context)
142 {
143 Shell_t *shp = (Shell_t*)context;
144 register int n,o;
145 register Arg_t *ap = (Arg_t*)(shp->arg_context);
146 Lex_t *lp = (Lex_t*)(shp->lex_context);
147 Shopt_t newflags;
148 int setflag=0, action=0, trace=(int)sh_isoption(SH_XTRACE);
149 Namval_t *np = NIL(Namval_t*);
150 const char *cp;
151 int verbose,f;
152 Optdisc_t disc;
153 newflags=ap->sh->options;
154 memset(&disc, 0, sizeof(disc));
155 disc.version = OPT_VERSION;
156 disc.infof = infof;
157 opt_info.disc = &disc;
158
159 if(argc>0)
160 setflag = 4;
161 else
162 argc = -argc;
163 while((n = optget(argv,setflag?sh_optset:sh_optksh)))
164 {
165 o=0;
166 f=*opt_info.option=='-' && (opt_info.num || opt_info.arg);
167 switch(n)
168 {
169 case 'A':
170 np = nv_open(opt_info.arg,ap->sh->var_tree,NV_NOASSIGN|NV_ARRAY|NV_VARNAME);
171 if(f)
172 nv_unset(np);
173 continue;
174 #if SHOPT_BASH
175 case 'O': /* shopt options, only in bash mode */
176 if(!sh_isoption(SH_BASH))
177 errormsg(SH_DICT,ERROR_exit(1), e_option, opt_info.name);
178 #endif
179 case 'o': /* set options */
180 byname:
181 if(!opt_info.arg||!*opt_info.arg||*opt_info.arg=='-')
182 {
183 action = PRINT;
184 /* print style: -O => shopt options
185 * bash => print unset options also, no heading
186 */
187 verbose = (f?PRINT_VERBOSE:PRINT_NO_HEADER)|
188 (n=='O'?PRINT_SHOPT:0)|
189 (sh_isoption(SH_BASH)?PRINT_ALL|PRINT_NO_HEADER:0)|
190 ((opt_info.arg&&(!*opt_info.arg||*opt_info.arg=='-'))?(PRINT_TABLE|PRINT_NO_HEADER):0);
191 continue;
192 }
193 o = sh_lookopt(opt_info.arg,&f);
194 if(o<=0
195 || (!sh_isoption(SH_BASH) && (o&SH_BASHEXTRA))
196 || ((!sh_isoption(SH_BASH) || n=='o') && (o&SH_BASHOPT))
197
198 || (setflag && (o&SH_COMMANDLINE)))
199 {
200 errormsg(SH_DICT,2, e_option, opt_info.arg);
201 error_info.errors++;
202 }
203 o &= 0xff;
204 if(sh_isoption(SH_RESTRICTED) && !f && o==SH_RESTRICTED)
205 errormsg(SH_DICT,ERROR_exit(1), e_restricted, opt_info.arg);
206 break;
207 #if SHOPT_BASH
208 case -1: /* --rcfile */
209 ap->sh->gd->rcfile = opt_info.arg;
210 continue;
211 case -2: /* --noediting */
212 if (!f)
213 {
214 off_option(&newflags,SH_VI);
215 off_option(&newflags,SH_EMACS);
216 off_option(&newflags,SH_GMACS);
217 }
218 continue;
219 case -3: /* --profile */
220 n = 'l';
221 goto skip;
222 case -4: /* --posix */
223 /* mask lower 8 bits to find char in optksh string */
224 n&=0xff;
225 goto skip;
226 case -5: /* --version */
227 sfputr(sfstdout, "ksh bash emulation, version ",-1);
228 np = nv_open("BASH_VERSION",ap->sh->var_tree,0);
229 sfputr(sfstdout, nv_getval(np),-1);
230 np = nv_open("MACHTYPE",ap->sh->var_tree,0);
231 sfprintf(sfstdout, " (%s)\n", nv_getval(np));
232 sh_exit(0);
233 #endif
234 case -6: /* --default */
235 {
236 register const Shtable_t *tp;
237 for(tp=shtab_options; o = tp->sh_number; tp++)
238 if(!(o&SH_COMMANDLINE) && is_option(&newflags,o&0xff))
239 off_option(&newflags,o&0xff);
240 }
241 continue;
242 case -7:
243 f = 0;
244 goto byname;
245 case 'D':
246 on_option(&newflags,SH_NOEXEC);
247 goto skip;
248 case 'T':
249 if (opt_info.num)
250 ap->sh->test |= opt_info.num;
251 else
252 ap->sh->test = 0;
253 continue;
254 case 's':
255 if(setflag)
256 {
257 action = SORT;
258 continue;
259 }
260 #if SHOPT_KIA
261 goto skip;
262 case 'R':
263 if(setflag)
264 n = ':';
265 else
266 {
267 ap->kiafile = opt_info.arg;
268 n = 'n';
269 }
270 /*FALLTHROUGH*/
271 #endif /* SHOPT_KIA */
272 #if SHOPT_REGRESS
273 goto skip;
274 case 'I':
275 continue;
276 #endif /* SHOPT_REGRESS */
277 /*FALLTHROUGH*/
278 skip:
279 default:
280 if(cp=strchr(optksh,n))
281 o = flagval[cp-optksh];
282 break;
283 case ':':
284 if(opt_info.name[0]=='-'&&opt_info.name[1]=='-')
285 {
286 opt_info.arg = argv[opt_info.index-1] + 2;
287 f = 1;
288 goto byname;
289 }
290 errormsg(SH_DICT,2, "%s", opt_info.arg);
291 continue;
292 case '?':
293 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
294 return(-1);
295 }
296 if(f)
297 {
298 if(o==SH_VI || o==SH_EMACS || o==SH_GMACS)
299 {
300 off_option(&newflags,SH_VI);
301 off_option(&newflags,SH_EMACS);
302 off_option(&newflags,SH_GMACS);
303 }
304 on_option(&newflags,o);
305 off_option(&ap->sh->offoptions,o);
306 }
307 else
308 {
309 if ((o == SH_RESTRICTED) &&
310 sh_isoption(SH_RESTRICTED)) {
311 errormsg(SH_DICT, ERROR_exit(1),
312 e_restricted, "r");
313 }
314 if(o==SH_XTRACE)
315 trace = 0;
316 off_option(&newflags,o);
317 if(setflag==0)
318 on_option(&ap->sh->offoptions,o);
319 }
320 }
321 if(error_info.errors)
322 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage(NIL(char*)));
323 /* check for '-' or '+' argument */
324 if((cp=argv[opt_info.index]) && cp[1]==0 && (*cp=='+' || *cp=='-') &&
325 strcmp(argv[opt_info.index-1],"--"))
326 {
327 opt_info.index++;
328 off_option(&newflags,SH_XTRACE);
329 off_option(&newflags,SH_VERBOSE);
330 trace = 0;
331 }
332 if(trace)
333 sh_trace(shp,argv,1);
334 argc -= opt_info.index;
335 argv += opt_info.index;
336 if(action==PRINT)
337 sh_printopts(newflags,verbose,0);
338 if(setflag)
339 {
340 if(action==SORT)
341 {
342 if(argc>0)
343 strsort(argv,argc,strcoll);
344 else
345 strsort(ap->sh->st.dolv+1,ap->sh->st.dolc,strcoll);
346 }
347 if(np)
348 {
349 nv_setvec(np,0,argc,argv);
350 nv_close(np);
351 }
352 else if(argc>0 || ((cp=argv[-1]) && strcmp(cp,"--")==0))
353 sh_argset(ap,argv-1);
354 }
355 else if(is_option(&newflags,SH_CFLAG))
356 {
357 if(!(ap->sh->comdiv = *argv++))
358 {
359 errormsg(SH_DICT,2,e_cneedsarg);
360 errormsg(SH_DICT,ERROR_usage(2),optusage(NIL(char*)));
361 }
362 argc--;
363 }
364 /* handling SH_INTERACTIVE and SH_PRIVILEGED has been moved to
365 * sh_applyopts(), so that the code can be reused from b_shopt(), too
366 */
367 sh_applyopts(ap->sh,newflags);
368 #if SHOPT_KIA
369 if(ap->kiafile)
370 {
371 if(!argv[0])
372 errormsg(SH_DICT,ERROR_usage(2),"-R requires scriptname");
373 if(!(lp->kiafile=sfopen(NIL(Sfio_t*),ap->kiafile,"w+")))
374 errormsg(SH_DICT,ERROR_system(3),e_create,ap->kiafile);
375 if(!(lp->kiatmp=sftmp(2*SF_BUFSIZE)))
376 errormsg(SH_DICT,ERROR_system(3),e_tmpcreate);
377 sfputr(lp->kiafile,";vdb;CIAO/ksh",'\n');
378 lp->kiabegin = sftell(lp->kiafile);
379 lp->entity_tree = dtopen(&_Nvdisc,Dtbag);
380 lp->scriptname = strdup(sh_fmtq(argv[0]));
381 lp->script=kiaentity(lp,lp->scriptname,-1,'p',-1,0,0,'s',0,"");
382 lp->fscript=kiaentity(lp,lp->scriptname,-1,'f',-1,0,0,'s',0,"");
383 lp->unknown=kiaentity(lp,"<unknown>",-1,'p',-1,0,0,'0',0,"");
384 kiaentity(lp,"<unknown>",-1,'p',0,0,lp->unknown,'0',0,"");
385 lp->current = lp->script;
386 ap->kiafile = 0;
387 }
388 #endif /* SHOPT_KIA */
389 return(argc);
390 }
391
392 /* apply new options */
393
sh_applyopts(Shell_t * shp,Shopt_t newflags)394 void sh_applyopts(Shell_t* shp,Shopt_t newflags)
395 {
396 /* cannot set -n for interactive shells since there is no way out */
397 if(sh_isoption(SH_INTERACTIVE))
398 off_option(&newflags,SH_NOEXEC);
399 if(is_option(&newflags,SH_PRIVILEGED))
400 on_option(&newflags,SH_NOUSRPROFILE);
401 if(!sh_isstate(SH_INIT) && is_option(&newflags,SH_PRIVILEGED) != sh_isoption(SH_PRIVILEGED) || sh_isstate(SH_INIT) && is_option(&((Arg_t*)shp->arg_context)->sh->offoptions,SH_PRIVILEGED) && shp->gd->userid!=shp->gd->euserid)
402 {
403 if(!is_option(&newflags,SH_PRIVILEGED))
404 {
405 setuid(shp->gd->userid);
406 setgid(shp->gd->groupid);
407 if(shp->gd->euserid==0)
408 {
409 shp->gd->euserid = shp->gd->userid;
410 shp->gd->egroupid = shp->gd->groupid;
411 }
412 }
413 else if((shp->gd->userid!=shp->gd->euserid && setuid(shp->gd->euserid)<0) ||
414 (shp->gd->groupid!=shp->gd->egroupid && setgid(shp->gd->egroupid)<0) ||
415 (shp->gd->userid==shp->gd->euserid && shp->gd->groupid==shp->gd->egroupid))
416 off_option(&newflags,SH_PRIVILEGED);
417 }
418 #if SHOPT_BASH
419 on_option(&newflags,SH_CMDHIST);
420 on_option(&newflags,SH_CHECKHASH);
421 on_option(&newflags,SH_EXECFAIL);
422 on_option(&newflags,SH_EXPAND_ALIASES);
423 on_option(&newflags,SH_HISTAPPEND);
424 on_option(&newflags,SH_INTERACTIVE_COMM);
425 on_option(&newflags,SH_LITHIST);
426 on_option(&newflags,SH_NOEMPTYCMDCOMPL);
427
428 if(!is_option(&newflags,SH_XPG_ECHO) && sh_isoption(SH_XPG_ECHO))
429 astconf("UNIVERSE", 0, "ucb");
430 if(is_option(&newflags,SH_XPG_ECHO) && !sh_isoption(SH_XPG_ECHO))
431 astconf("UNIVERSE", 0, "att");
432 if(!is_option(&newflags,SH_PHYSICAL) && sh_isoption(SH_PHYSICAL))
433 astconf("PATH_RESOLVE", 0, "metaphysical");
434 if(is_option(&newflags,SH_PHYSICAL) && !sh_isoption(SH_PHYSICAL))
435 astconf("PATH_RESOLVE", 0, "physical");
436 if(is_option(&newflags,SH_HISTORY2) && !sh_isoption(SH_HISTORY2))
437 {
438 sh_onstate(SH_HISTORY);
439 sh_onoption(SH_HISTORY);
440 }
441 if(!is_option(&newflags,SH_HISTORY2) && sh_isoption(SH_HISTORY2))
442 {
443 sh_offstate(SH_HISTORY);
444 sh_offoption(SH_HISTORY);
445 }
446 #endif
447 shp->options = newflags;
448 }
449
450 /*
451 * returns the value of $-
452 */
sh_argdolminus(void * context)453 char *sh_argdolminus(void* context)
454 {
455 register Arg_t *ap = (Arg_t*)context;
456 register const char *cp=optksh;
457 register char *flagp=ap->flagadr;
458 while(cp< &optksh[NUM_OPTS])
459 {
460 int n = flagval[cp-optksh];
461 if(sh_isoption(n))
462 *flagp++ = *cp;
463 cp++;
464 }
465 *flagp = 0;
466 return(ap->flagadr);
467 }
468
469 /*
470 * set up positional parameters
471 */
sh_argset(Arg_t * ap,char * argv[])472 static void sh_argset(Arg_t *ap,char *argv[])
473 {
474 sh_argfree(ap->sh,ap->dolh,0);
475 ap->dolh = sh_argcreate(argv);
476 /* link into chain */
477 ap->dolh->dolnxt = ap->argfor;
478 ap->argfor = ap->dolh;
479 ap->sh->st.dolc = ap->dolh->dolnum-1;
480 ap->sh->st.dolv = ap->dolh->dolval;
481 }
482
483 /*
484 * free the argument list if the use count is 1
485 * If count is greater than 1 decrement count and return same blk
486 * Free the argument list if the use count is 1 and return next blk
487 * Delete the blk from the argfor chain
488 * If flag is set, then the block dolh is not freed
489 */
sh_argfree(Shell_t * shp,struct dolnod * blk,int flag)490 struct dolnod *sh_argfree(Shell_t *shp, struct dolnod *blk,int flag)
491 {
492 register struct dolnod* argr=blk;
493 register struct dolnod* argblk;
494 register Arg_t *ap = (Arg_t*)shp->arg_context;
495 if(argblk=argr)
496 {
497 if((--argblk->dolrefcnt)==0)
498 {
499 argr = argblk->dolnxt;
500 if(flag && argblk==ap->dolh)
501 ap->dolh->dolrefcnt = 1;
502 else
503 {
504 /* delete from chain */
505 if(ap->argfor == argblk)
506 ap->argfor = argblk->dolnxt;
507 else
508 {
509 for(argr=ap->argfor;argr;argr=argr->dolnxt)
510 if(argr->dolnxt==argblk)
511 break;
512 if(!argr)
513 return(NIL(struct dolnod*));
514 argr->dolnxt = argblk->dolnxt;
515 argr = argblk->dolnxt;
516 }
517 free((void*)argblk);
518 }
519 }
520 }
521 return(argr);
522 }
523
524 /*
525 * grab space for arglist and copy args
526 * The strings are copied after the argment vector
527 */
sh_argcreate(register char * argv[])528 struct dolnod *sh_argcreate(register char *argv[])
529 {
530 register struct dolnod *dp;
531 register char **pp=argv, *sp;
532 register int size=0,n;
533 /* count args and number of bytes of arglist */
534 while(sp= *pp++)
535 size += strlen(sp);
536 n = (pp - argv)-1;
537 dp=new_of(struct dolnod,n*sizeof(char*)+size+n);
538 dp->dolrefcnt=1; /* use count */
539 dp->dolnum = n;
540 dp->dolnxt = 0;
541 pp = dp->dolval;
542 sp = (char*)dp + sizeof(struct dolnod) + n*sizeof(char*);
543 while(n--)
544 {
545 *pp++ = sp;
546 sp = strcopy(sp, *argv++) + 1;
547 }
548 *pp = NIL(char*);
549 return(dp);
550 }
551
552 /*
553 * used to set new arguments for functions
554 */
sh_argnew(Shell_t * shp,char * argi[],struct dolnod ** savargfor)555 struct dolnod *sh_argnew(Shell_t *shp,char *argi[], struct dolnod **savargfor)
556 {
557 register Arg_t *ap = (Arg_t*)shp->arg_context;
558 register struct dolnod *olddolh = ap->dolh;
559 *savargfor = ap->argfor;
560 ap->dolh = 0;
561 ap->argfor = 0;
562 sh_argset(ap,argi);
563 return(olddolh);
564 }
565
566 /*
567 * reset arguments as they were before function
568 */
sh_argreset(Shell_t * shp,struct dolnod * blk,struct dolnod * afor)569 void sh_argreset(Shell_t *shp,struct dolnod *blk, struct dolnod *afor)
570 {
571 register Arg_t *ap = (Arg_t*)shp->arg_context;
572 while(ap->argfor=sh_argfree(shp,ap->argfor,0));
573 ap->argfor = afor;
574 if(ap->dolh = blk)
575 {
576 shp->st.dolc = ap->dolh->dolnum-1;
577 shp->st.dolv = ap->dolh->dolval;
578 }
579 }
580
581 /*
582 * increase the use count so that an sh_argset will not make it go away
583 */
sh_arguse(Shell_t * shp)584 struct dolnod *sh_arguse(Shell_t* shp)
585 {
586 register struct dolnod *dh;
587 register Arg_t *ap = (Arg_t*)shp->arg_context;
588 if(dh=ap->dolh)
589 dh->dolrefcnt++;
590 return(dh);
591 }
592
593 /*
594 * Print option settings on standard output
595 * if mode is inclusive or of PRINT_*
596 * if <mask> is set, only options with this mask value are displayed
597 */
sh_printopts(Shopt_t oflags,register int mode,Shopt_t * mask)598 void sh_printopts(Shopt_t oflags,register int mode, Shopt_t *mask)
599 {
600 register const Shtable_t *tp;
601 const char *name;
602 int on;
603 int value;
604 if(!(mode&PRINT_NO_HEADER))
605 sfputr(sfstdout,sh_translate(e_heading),'\n');
606 if(mode&PRINT_TABLE)
607 {
608 int w;
609 int c;
610 int r;
611 int i;
612
613 c = 0;
614 for(tp=shtab_options; value=tp->sh_number; tp++)
615 {
616 if(mask && !is_option(mask,value&0xff))
617 continue;
618 name = tp->sh_name;
619 if(name[0] == 'n' && name[1] == 'o' && name[2] != 't')
620 name += 2;
621 if(c<(w=strlen(name)))
622 c = w;
623 }
624 c += 4;
625 if((w = ed_window()) < (2*c))
626 w = 2*c;
627 r = w / c;
628 i = 0;
629 for(tp=shtab_options; value=tp->sh_number; tp++)
630 {
631 if(mask && !is_option(mask,value&0xff))
632 continue;
633 on = !!is_option(&oflags,value);
634 value &= 0xff;
635 name = tp->sh_name;
636 if(name[0] == 'n' && name[1] == 'o' && name[2] != 't')
637 {
638 name += 2;
639 on = !on;
640 }
641 if(++i>=r)
642 {
643 i = 0;
644 sfprintf(sfstdout, "%s%s\n", on ? "" : "no", name);
645 }
646 else
647 sfprintf(sfstdout, "%s%-*s", on ? "" : "no", on ? c : (c-2), name);
648 }
649 if(i)
650 sfputc(sfstdout,'\n');
651 return;
652 }
653 #if SHOPT_RAWONLY
654 on_option(&oflags,SH_VIRAW);
655 #endif
656 if(!(mode&(PRINT_ALL|PRINT_VERBOSE))) /* only print set options */
657 {
658 if(mode&PRINT_SHOPT)
659 sfwrite(sfstdout,"shopt -s",3);
660 else
661 sfwrite(sfstdout,"set --default",13);
662 }
663 for(tp=shtab_options; value=tp->sh_number; tp++)
664 {
665 if(mask && !is_option(mask,value&0xff))
666 continue;
667 if(sh_isoption(SH_BASH))
668 {
669 if (!(mode&PRINT_SHOPT) != !(value&SH_BASHOPT))
670 continue;
671 }
672 else if (value&(SH_BASHEXTRA|SH_BASHOPT))
673 continue;
674 on = !!is_option(&oflags,value);
675 name = tp->sh_name;
676 if(name[0] == 'n' && name[1] == 'o' && name[2] != 't')
677 {
678 name += 2;
679 on = !on;
680 }
681 if(mode&PRINT_VERBOSE)
682 {
683 sfputr(sfstdout,name,' ');
684 sfnputc(sfstdout,' ',24-strlen(name));
685 sfputr(sfstdout,on ? sh_translate(e_on) : sh_translate(e_off),'\n');
686 }
687 else if(mode&PRINT_ALL) /* print unset options also */
688 {
689 if(mode&PRINT_SHOPT)
690 sfprintf(sfstdout, "shopt -%c %s\n",
691 on?'s':'u',
692 name);
693 else
694 sfprintf(sfstdout, "set %co %s\n",
695 on?'-':'+',
696 name);
697 }
698 else if(!(value&SH_COMMANDLINE) && is_option(&oflags,value&0xff))
699 sfprintf(sfstdout," %s%s%s",(mode&PRINT_SHOPT)?"":"--",on?"":"no",name);
700 }
701 if(!(mode&(PRINT_VERBOSE|PRINT_ALL)))
702 sfputc(sfstdout,'\n');
703 }
704
705 /*
706 * build an argument list
707 */
sh_argbuild(Shell_t * shp,int * nargs,const struct comnod * comptr,int flag)708 char **sh_argbuild(Shell_t *shp,int *nargs, const struct comnod *comptr,int flag)
709 {
710 register struct argnod *argp;
711 struct argnod *arghead=0;
712 shp->xargmin = 0;
713 {
714 register const struct comnod *ac = comptr;
715 register int n;
716 /* see if the arguments have already been expanded */
717 if(!ac->comarg)
718 {
719 *nargs = 0;
720 return(&null);
721 }
722 else if(!(ac->comtyp&COMSCAN))
723 {
724 register struct dolnod *ap = (struct dolnod*)ac->comarg;
725 *nargs = ap->dolnum;
726 return(ap->dolval+ap->dolbot);
727 }
728 shp->lastpath = 0;
729 *nargs = 0;
730 if(ac)
731 {
732 if(ac->comnamp == SYSLET)
733 flag |= ARG_LET;
734 argp = ac->comarg;
735 while(argp)
736 {
737 n = arg_expand(shp,argp,&arghead,flag);
738 if(n>1)
739 {
740 if(shp->xargmin==0)
741 shp->xargmin = *nargs;
742 shp->xargmax = *nargs+n;
743 }
744 *nargs += n;
745 argp = argp->argnxt.ap;
746 }
747 argp = arghead;
748 }
749 }
750 {
751 register char **comargn;
752 register int argn;
753 register char **comargm;
754 argn = *nargs;
755 /* allow room to prepend args */
756 argn += 1;
757
758 comargn=(char**)stkalloc(shp->stk,(unsigned)(argn+1)*sizeof(char*));
759 comargm = comargn += argn;
760 *comargn = NIL(char*);
761 if(!argp)
762 {
763 /* reserve an extra null pointer */
764 *--comargn = 0;
765 return(comargn);
766 }
767 while(argp)
768 {
769 struct argnod *nextarg = argp->argchn.ap;
770 argp->argchn.ap = 0;
771 *--comargn = argp->argval;
772 if(!(argp->argflag&ARG_RAW))
773 sh_trim(*comargn);
774 if(!(argp=nextarg) || (argp->argflag&ARG_MAKE))
775 {
776 if((argn=comargm-comargn)>1)
777 strsort(comargn,argn,strcoll);
778 comargm = comargn;
779 }
780 }
781 shp->last_table = 0;
782 return(comargn);
783 }
784 }
785
786 #if _pipe_socketpair && !_socketpair_devfd
787 # define sh_pipe(a) sh_rpipe(a)
788 #endif
789
sh_argprocsub(Shell_t * shp,struct argnod * argp)790 struct argnod *sh_argprocsub(Shell_t *shp,struct argnod *argp)
791 {
792 /* argument of the form <(cmd) or >(cmd) */
793 register struct argnod *ap;
794 int monitor, fd, pv[3];
795 int subshell = shp->subshell;
796 ap = (struct argnod*)stkseek(shp->stk,ARGVAL);
797 ap->argflag |= ARG_MAKE;
798 ap->argflag &= ~ARG_RAW;
799 fd = argp->argflag&ARG_RAW;
800 if(fd==0 && shp->subshell)
801 sh_subtmpfile(shp);
802 #if SHOPT_DEVFD
803 sfwrite(shp->stk,e_devfdNN,8);
804 pv[2] = 0;
805 sh_pipe(pv);
806 #else
807 pv[0] = -1;
808 shp->fifo = pathtemp(0,0,0,"ksh.fifo",0);
809 mkfifo(shp->fifo,S_IRUSR|S_IWUSR);
810 sfputr(shp->stk,shp->fifo,0);
811 #endif /* SHOPT_DEVFD */
812 sfputr(shp->stk,fmtbase((long)pv[fd],10,0),0);
813 ap = (struct argnod*)stkfreeze(shp->stk,0);
814 shp->inpipe = shp->outpipe = 0;
815 if(monitor = (sh_isstate(SH_MONITOR)!=0))
816 sh_offstate(SH_MONITOR);
817 shp->subshell = 0;
818 if(fd)
819 {
820 shp->inpipe = pv;
821 sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
822 }
823 else
824 {
825 shp->outpipe = pv;
826 sh_exec((Shnode_t*)argp->argchn.ap,(int)sh_isstate(SH_ERREXIT));
827 }
828 shp->subshell = subshell;
829 if(monitor)
830 sh_onstate(SH_MONITOR);
831 #if SHOPT_DEVFD
832 close(pv[1-fd]);
833 sh_iosave(shp,-pv[fd], shp->topfd, (char*)0);
834 #else
835 free(shp->fifo);
836 shp->fifo = 0;
837 #endif /* SHOPT_DEVFD */
838 return(ap);
839 }
840
841 /* Argument expansion */
arg_expand(Shell_t * shp,register struct argnod * argp,struct argnod ** argchain,int flag)842 static int arg_expand(Shell_t *shp,register struct argnod *argp, struct argnod **argchain,int flag)
843 {
844 register int count = 0;
845 argp->argflag &= ~ARG_MAKE;
846 if(*argp->argval==0 && (argp->argflag&ARG_EXP))
847 {
848 struct argnod *ap;
849 ap = sh_argprocsub(shp,argp);
850 ap->argchn.ap = *argchain;
851 *argchain = ap;
852 count++;
853 }
854 else
855 if(!(argp->argflag&ARG_RAW))
856 {
857 #if SHOPT_OPTIMIZE
858 struct argnod *ap;
859 sh_stats(STAT_ARGEXPAND);
860 if(flag&ARG_OPTIMIZE)
861 argp->argchn.ap=0;
862 if(ap=argp->argchn.ap)
863 {
864 sh_stats(STAT_ARGHITS);
865 count = 1;
866 ap->argchn.ap = *argchain;
867 ap->argflag |= ARG_RAW;
868 ap->argflag &= ~ARG_EXP;
869 *argchain = ap;
870 }
871 else
872 #endif /* SHOPT_OPTIMIZE */
873 count = sh_macexpand(shp,argp,argchain,flag);
874 }
875 else
876 {
877 argp->argchn.ap = *argchain;
878 *argchain = argp;
879 argp->argflag |= ARG_MAKE;
880 count++;
881 }
882 return(count);
883 }
884
885