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 * exec [arg...]
23 * eval [arg...]
24 * jobs [-lnp] [job...]
25 * login [arg...]
26 * let expr...
27 * . file [arg...]
28 * :, true, false
29 * vpath [top] [base]
30 * vmap [top] [base]
31 * wait [job...]
32 * shift [n]
33 *
34 * David Korn
35 * AT&T Labs
36 *
37 */
38
39 #include "defs.h"
40 #include "variables.h"
41 #include "shnodes.h"
42 #include "path.h"
43 #include "io.h"
44 #include "name.h"
45 #include "history.h"
46 #include "builtins.h"
47 #include "jobs.h"
48
49 #define DOTMAX MAXDEPTH /* maximum level of . nesting */
50
51 static void noexport(Namval_t*,void*);
52
53 struct login
54 {
55 Shell_t *sh;
56 int clear;
57 char *arg0;
58 };
59
b_exec(int argc __unused,char * argv[],Shbltin_t * context)60 int b_exec(int argc __unused, char *argv[], Shbltin_t *context)
61 {
62 struct login logdata;
63 register int n;
64 logdata.clear = 0;
65 logdata.arg0 = 0;
66 logdata.sh = context->shp;
67 logdata.sh->st.ioset = 0;
68 while (n = optget(argv, sh_optexec)) switch (n)
69 {
70 case 'a':
71 logdata.arg0 = opt_info.arg;
72 argc = 0;
73 break;
74 case 'c':
75 logdata.clear=1;
76 break;
77 case ':':
78 errormsg(SH_DICT,2, "%s", opt_info.arg);
79 break;
80 case '?':
81 errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
82 return(2);
83 }
84 argv += opt_info.index;
85 if(error_info.errors)
86 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
87 if(*argv)
88 B_login(0,argv,(Shbltin_t*)&logdata);
89 return(0);
90 }
91
noexport(register Namval_t * np,void * data)92 static void noexport(register Namval_t* np, void *data)
93 {
94 NOT_USED(data);
95 nv_offattr(np,NV_EXPORT);
96 }
97
B_login(int argc,char * argv[],Shbltin_t * context)98 int B_login(int argc,char *argv[],Shbltin_t *context)
99 {
100 struct checkpt *pp;
101 register struct login *logp=0;
102 register Shell_t *shp;
103 const char *pname;
104 if(argc)
105 shp = context->shp;
106 else
107 {
108 logp = (struct login*)context;
109 shp = logp->sh;
110 }
111 pp = (struct checkpt*)shp->jmplist;
112 if(sh_isoption(SH_RESTRICTED))
113 errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[0]);
114 else
115 {
116 register struct argnod *arg=shp->envlist;
117 register Namval_t* np;
118 register char *cp;
119 if(shp->subshell && !shp->subshare)
120 sh_subfork();
121 if(logp && logp->clear)
122 {
123 #ifdef _ENV_H
124 env_close(shp->env);
125 shp->env = env_open((char**)0,3);
126 #else
127 nv_scan(shp->var_tree,noexport,0,NV_EXPORT,NV_EXPORT);
128 #endif
129 }
130 while(arg)
131 {
132 if((cp=strchr(arg->argval,'=')) &&
133 (*cp=0,np=nv_search(arg->argval,shp->var_tree,0)))
134 {
135 nv_onattr(np,NV_EXPORT);
136 sh_envput(shp->env,np);
137 }
138 if(cp)
139 *cp = '=';
140 arg=arg->argnxt.ap;
141 }
142 pname = argv[0];
143 if(logp && logp->arg0)
144 argv[0] = logp->arg0;
145 #ifdef JOBS
146 if(job_close(shp) < 0)
147 return(1);
148 #endif /* JOBS */
149 /* force bad exec to terminate shell */
150 pp->mode = SH_JMPEXIT;
151 sh_sigreset(2);
152 sh_freeup(shp);
153 path_exec(shp,pname,argv,NIL(struct argnod*));
154 sh_done(shp,0);
155 }
156 return(1);
157 }
158
b_let(int argc,char * argv[],Shbltin_t * context)159 int b_let(int argc,char *argv[],Shbltin_t *context)
160 {
161 register int r;
162 register char *arg;
163 Shell_t *shp = context->shp;
164 NOT_USED(argc);
165 while (r = optget(argv,sh_optlet)) switch (r)
166 {
167 case ':':
168 errormsg(SH_DICT,2, "%s", opt_info.arg);
169 break;
170 case '?':
171 errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
172 break;
173 }
174 argv += opt_info.index;
175 if(error_info.errors || !*argv)
176 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
177 while(arg= *argv++)
178 r = !sh_arith(shp,arg);
179 return(r);
180 }
181
b_eval(int argc,char * argv[],Shbltin_t * context)182 int b_eval(int argc,char *argv[], Shbltin_t *context)
183 {
184 register int r;
185 register Shell_t *shp = context->shp;
186 NOT_USED(argc);
187 while (r = optget(argv,sh_opteval)) switch (r)
188 {
189 case ':':
190 errormsg(SH_DICT,2, "%s", opt_info.arg);
191 break;
192 case '?':
193 errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
194 return(2);
195 }
196 if(error_info.errors)
197 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
198 argv += opt_info.index;
199 if(*argv && **argv)
200 {
201 sh_offstate(SH_MONITOR);
202 sh_eval(sh_sfeval(argv),0);
203 }
204 return(shp->exitval);
205 }
206
b_dot_cmd(register int n,char * argv[],Shbltin_t * context)207 int b_dot_cmd(register int n,char *argv[],Shbltin_t *context)
208 {
209 register char *script;
210 register Namval_t *np;
211 register int jmpval;
212 register Shell_t *shp = context->shp;
213 struct sh_scoped savst, *prevscope = shp->st.self;
214 char *filename=0, *buffer=0;
215 int fd;
216 struct dolnod *saveargfor;
217 volatile struct dolnod *argsave=0;
218 struct checkpt buff;
219 Sfio_t *iop=0;
220 short level;
221 while (n = optget(argv,sh_optdot)) switch (n)
222 {
223 case ':':
224 errormsg(SH_DICT,2, "%s", opt_info.arg);
225 break;
226 case '?':
227 errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
228 return(2);
229 }
230 argv += opt_info.index;
231 script = *argv;
232 if(error_info.errors || !script)
233 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
234 if(shp->dot_depth+1 > DOTMAX)
235 errormsg(SH_DICT,ERROR_exit(1),e_toodeep,script);
236 if(!(np=shp->posix_fun))
237 {
238 /* check for KornShell style function first */
239 np = nv_search(script,shp->fun_tree,0);
240 if(np && is_afunction(np) && !nv_isattr(np,NV_FPOSIX))
241 {
242 if(!np->nvalue.ip)
243 {
244 path_search(shp,script,NIL(Pathcomp_t**),0);
245 if(np->nvalue.ip)
246 {
247 if(nv_isattr(np,NV_FPOSIX))
248 np = 0;
249 }
250 else
251 errormsg(SH_DICT,ERROR_exit(1),e_found,script);
252 }
253 }
254 else
255 np = 0;
256 if(!np)
257 {
258 if((fd=path_open(shp,script,path_get(shp,script))) < 0)
259 errormsg(SH_DICT,ERROR_system(1),e_open,script);
260 filename = path_fullname(shp,stkptr(shp->stk,PATH_OFFSET));
261 }
262 }
263 *prevscope = shp->st;
264 shp->st.lineno = np?((struct functnod*)nv_funtree(np))->functline:1;
265 shp->st.var_local = shp->st.save_tree = shp->var_tree;
266 if(filename)
267 {
268 shp->st.filename = filename;
269 shp->st.lineno = 1;
270 }
271 level = shp->fn_depth+shp->dot_depth+1;
272 nv_putval(SH_LEVELNOD,(char*)&level,NV_INT16);
273 shp->st.prevst = prevscope;
274 shp->st.self = &savst;
275 shp->topscope = (Shscope_t*)shp->st.self;
276 prevscope->save_tree = shp->var_tree;
277 if(np)
278 shp->st.filename = np->nvalue.rp->fname;
279 nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
280 shp->posix_fun = 0;
281 if(np || argv[1])
282 argsave = sh_argnew(shp,argv,&saveargfor);
283 sh_pushcontext(shp,&buff,SH_JMPDOT);
284 jmpval = sigsetjmp(buff.buff,0);
285 if(jmpval == 0)
286 {
287 shp->dot_depth++;
288 if(np)
289 sh_exec((Shnode_t*)(nv_funtree(np)),sh_isstate(SH_ERREXIT));
290 else
291 {
292 buffer = malloc(IOBSIZE+1);
293 iop = sfnew(NIL(Sfio_t*),buffer,IOBSIZE,fd,SF_READ);
294 sh_offstate(SH_NOFORK);
295 sh_eval(iop,sh_isstate(SH_PROFILE)?SH_FUNEVAL:0);
296 }
297 }
298 sh_popcontext(shp,&buff);
299 if(buffer)
300 free(buffer);
301 if(!np)
302 free((void*)shp->st.filename);
303 shp->dot_depth--;
304 if((np || argv[1]) && jmpval!=SH_JMPSCRIPT)
305 sh_argreset(shp,(struct dolnod*)argsave,saveargfor);
306 else
307 {
308 prevscope->dolc = shp->st.dolc;
309 prevscope->dolv = shp->st.dolv;
310 }
311 if (shp->st.self != &savst)
312 *shp->st.self = shp->st;
313 /* only restore the top Shscope_t portion for posix functions */
314 memcpy((void*)&shp->st, (void*)prevscope, sizeof(Shscope_t));
315 shp->topscope = (Shscope_t*)prevscope;
316 nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
317 if(jmpval && jmpval!=SH_JMPFUN)
318 siglongjmp(*shp->jmplist,jmpval);
319 return(shp->exitval);
320 }
321
322 /*
323 * null, true command
324 */
b_true(int argc,register char * argv[],Shbltin_t * context)325 int b_true(int argc,register char *argv[],Shbltin_t *context)
326 {
327 NOT_USED(argc);
328 NOT_USED(argv[0]);
329 NOT_USED(context);
330 return(0);
331 }
332
333 /*
334 * false command
335 */
b_false(int argc,register char * argv[],Shbltin_t * context)336 int b_false(int argc,register char *argv[], Shbltin_t *context)
337 {
338 NOT_USED(argc);
339 NOT_USED(argv[0]);
340 NOT_USED(context);
341 return(1);
342 }
343
b_shift(register int n,register char * argv[],Shbltin_t * context)344 int b_shift(register int n, register char *argv[], Shbltin_t *context)
345 {
346 register char *arg;
347 register Shell_t *shp = context->shp;
348 while((n = optget(argv,sh_optshift))) switch(n)
349 {
350 case ':':
351 errormsg(SH_DICT,2, "%s", opt_info.arg);
352 break;
353 case '?':
354 errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
355 return(2);
356 }
357 if(error_info.errors)
358 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
359 argv += opt_info.index;
360 n = ((arg= *argv)?(int)sh_arith(shp,arg):1);
361 if(n<0 || shp->st.dolc<n)
362 errormsg(SH_DICT,ERROR_exit(1),e_number,arg);
363 else
364 {
365 shp->st.dolv += n;
366 shp->st.dolc -= n;
367 }
368 return(0);
369 }
370
b_wait(int n,register char * argv[],Shbltin_t * context)371 int b_wait(int n,register char *argv[],Shbltin_t *context)
372 {
373 register Shell_t *shp = context->shp;
374 while((n = optget(argv,sh_optwait))) switch(n)
375 {
376 case ':':
377 errormsg(SH_DICT,2, "%s", opt_info.arg);
378 break;
379 case '?':
380 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
381 break;
382 }
383 if(error_info.errors)
384 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
385 argv += opt_info.index;
386 job_bwait(argv);
387 return(shp->exitval);
388 }
389
390 #ifdef JOBS
391 # if 0
392 /* for the dictionary generator */
393 int b_fg(int n,char *argv[],Shbltin_t *context){}
394 int b_disown(int n,char *argv[],Shbltin_t *context){}
395 # endif
b_bg(register int n,register char * argv[],Shbltin_t * context)396 int b_bg(register int n,register char *argv[],Shbltin_t *context)
397 {
398 register int flag = **argv;
399 register Shell_t *shp = context->shp;
400 register const char *optstr = sh_optbg;
401 if(*argv[0]=='f')
402 optstr = sh_optfg;
403 else if(*argv[0]=='d')
404 optstr = sh_optdisown;
405 while((n = optget(argv,optstr))) switch(n)
406 {
407 case ':':
408 errormsg(SH_DICT,2, "%s", opt_info.arg);
409 break;
410 case '?':
411 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
412 break;
413 }
414 if(error_info.errors)
415 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
416 argv += opt_info.index;
417 if(!sh_isoption(SH_MONITOR) || !job.jobcontrol)
418 {
419 if(sh_isstate(SH_INTERACTIVE))
420 errormsg(SH_DICT,ERROR_exit(1),e_no_jctl);
421 return(1);
422 }
423 if(flag=='d' && *argv==0)
424 argv = (char**)0;
425 if(job_walk(sfstdout,job_switch,flag,argv))
426 errormsg(SH_DICT,ERROR_exit(1),e_no_job);
427 return(shp->exitval);
428 }
429
b_jobs(register int n,char * argv[],Shbltin_t * context)430 int b_jobs(register int n,char *argv[],Shbltin_t *context)
431 {
432 register int flag = 0;
433 register Shell_t *shp = context->shp;
434 while((n = optget(argv,sh_optjobs))) switch(n)
435 {
436 case 'l':
437 flag = JOB_LFLAG;
438 break;
439 case 'n':
440 flag = JOB_NFLAG;
441 break;
442 case 'p':
443 flag = JOB_PFLAG;
444 break;
445 case ':':
446 errormsg(SH_DICT,2, "%s", opt_info.arg);
447 break;
448 case '?':
449 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
450 break;
451 }
452 argv += opt_info.index;
453 if(error_info.errors)
454 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
455 if(*argv==0)
456 argv = (char**)0;
457 if(job_walk(sfstdout,job_list,flag,argv))
458 errormsg(SH_DICT,ERROR_exit(1),e_no_job);
459 job_wait((pid_t)0);
460 return(shp->exitval);
461 }
462 #endif
463
464 #ifdef _cmd_universe
465 /*
466 * There are several universe styles that are masked by the getuniv(),
467 * setuniv() calls.
468 */
b_universe(int argc,char * argv[],Shbltin_t * context)469 int b_universe(int argc, char *argv[],Shbltin_t *context)
470 {
471 register char *arg;
472 register int n;
473 NOT_USED(context);
474 while((n = optget(argv,sh_optuniverse))) switch(n)
475 {
476 case ':':
477 errormsg(SH_DICT,2, "%s", opt_info.arg);
478 break;
479 case '?':
480 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
481 break;
482 }
483 argv += opt_info.index;
484 argc -= opt_info.index;
485 if(error_info.errors || argc>1)
486 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
487 if(arg = argv[0])
488 {
489 if(!astconf("UNIVERSE",0,arg))
490 errormsg(SH_DICT,ERROR_exit(1), e_badname,arg);
491 }
492 else
493 {
494 if(!(arg=astconf("UNIVERSE",0,0)))
495 errormsg(SH_DICT,ERROR_exit(1),e_nouniverse);
496 else
497 sfputr(sfstdout,arg,'\n');
498 }
499 return(0);
500 }
501 #endif /* cmd_universe */
502
503 #if SHOPT_FS_3D
504 #if _UWIN
505 #include <sys/mount.h>
506 #endif
507 # if 0
508 /* for the dictionary generator */
509 int b_vmap(int argc,char *argv[], Shbltin_t *context){}
510 # endif
b_vpath(register int argc,char * argv[],Shbltin_t * context)511 int b_vpath(register int argc,char *argv[], Shbltin_t *context)
512 {
513 register int flag, n;
514 register const char *optstr;
515 register char *vend;
516 register Shell_t *shp = context->shp;
517 if(argv[0][1]=='p')
518 {
519 optstr = sh_optvpath;
520 flag = FS3D_VIEW;
521 }
522 else
523 {
524 optstr = sh_optvmap;
525 flag = FS3D_VERSION;
526 }
527 while(n = optget(argv, optstr)) switch(n)
528 {
529 case ':':
530 errormsg(SH_DICT,2, "%s", opt_info.arg);
531 break;
532 case '?':
533 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
534 break;
535 }
536 if(error_info.errors)
537 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
538 #ifdef MS_3D
539 flag |= MS_3D;
540 #else
541 if(!shp->gd->lim.fs3d)
542 goto failed;
543 #endif
544 argv += opt_info.index;
545 argc -= opt_info.index;
546 switch(argc)
547 {
548 case 0:
549 case 1:
550 flag |= FS3D_GET;
551 if((n = mount(*argv,(char*)0,flag,0)) >= 0)
552 {
553 vend = stkalloc(shp->stk,++n);
554 n = mount(*argv,vend,flag|FS3D_SIZE(n),0);
555 }
556 if(n < 0)
557 goto failed;
558 if(argc==1)
559 {
560 sfprintf(sfstdout,"%s\n",vend);
561 break;
562 }
563 n = 0;
564 while(flag = *vend++)
565 {
566 if(flag==' ')
567 {
568 flag = e_sptbnl[n+1];
569 n = !n;
570 }
571 sfputc(sfstdout,flag);
572 }
573 if(n)
574 sfputc(sfstdout,'\n');
575 break;
576 default:
577 if((argc&1))
578 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
579 /*FALLTHROUGH*/
580 case 2:
581 if(shp->subshell && !shp->subshare)
582 sh_subfork();
583 for(n=0;n<argc;n+=2)
584 if(mount(argv[n+1],argv[n],flag,0)<0)
585 goto failed;
586 }
587 return(0);
588 failed:
589 errormsg(SH_DICT,ERROR_exit(1),(argc>1)?e_cantset:e_cantget,(flag&FS3D_VIEW)?e_mapping:e_versions);
590 return(1);
591 }
592 #endif /* SHOPT_FS_3D */
593
594