1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
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,char * argv[],void * extra)60 int b_exec(int argc,char *argv[], void *extra)
61 {
62 struct login logdata;
63 register int n;
64 logdata.clear = 0;
65 logdata.arg0 = 0;
66 logdata.sh = ((Shbltin_t*)extra)->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,(void*)&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[],void * extra)98 int B_login(int argc,char *argv[],void *extra)
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 = ((Shbltin_t*)extra)->shp;
106 else
107 {
108 logp = (struct login*)extra;
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(pname,argv,NIL(struct argnod*));
154 sh_done(shp,0);
155 }
156 return(1);
157 }
158
b_let(int argc,char * argv[],void * extra)159 int b_let(int argc,char *argv[],void *extra)
160 {
161 register int r;
162 register char *arg;
163 NOT_USED(argc);
164 NOT_USED(extra);
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(arg);
179 return(r);
180 }
181
b_eval(int argc,char * argv[],void * extra)182 int b_eval(int argc,char *argv[], void *extra)
183 {
184 register int r;
185 register Shell_t *shp = ((Shbltin_t*)extra)->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[],void * extra)207 int b_dot_cmd(register int n,char *argv[],void* extra)
208 {
209 register char *script;
210 register Namval_t *np;
211 register int jmpval;
212 register Shell_t *shp = ((Shbltin_t*)extra)->shp;
213 struct sh_scoped savst, *prevscope = shp->st.self;
214 char *filename=0;
215 int fd;
216 struct dolnod *argsave=0, *saveargfor;
217 struct checkpt buff;
218 Sfio_t *iop=0;
219 short level;
220 while (n = optget(argv,sh_optdot)) switch (n)
221 {
222 case ':':
223 errormsg(SH_DICT,2, "%s", opt_info.arg);
224 break;
225 case '?':
226 errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
227 return(2);
228 }
229 argv += opt_info.index;
230 script = *argv;
231 if(error_info.errors || !script)
232 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
233 if(shp->dot_depth+1 > DOTMAX)
234 errormsg(SH_DICT,ERROR_exit(1),e_toodeep,script);
235 if(!(np=shp->posix_fun))
236 {
237 /* check for KornShell style function first */
238 np = nv_search(script,shp->fun_tree,0);
239 if(np && is_afunction(np) && !nv_isattr(np,NV_FPOSIX))
240 {
241 if(!np->nvalue.ip)
242 {
243 path_search(script,NIL(Pathcomp_t**),0);
244 if(np->nvalue.ip)
245 {
246 if(nv_isattr(np,NV_FPOSIX))
247 np = 0;
248 }
249 else
250 errormsg(SH_DICT,ERROR_exit(1),e_found,script);
251 }
252 }
253 else
254 np = 0;
255 if(!np)
256 {
257 if((fd=path_open(script,path_get(script))) < 0)
258 errormsg(SH_DICT,ERROR_system(1),e_open,script);
259 filename = path_fullname(stkptr(shp->stk,PATH_OFFSET));
260 }
261 }
262 *prevscope = shp->st;
263 shp->st.lineno = np?((struct functnod*)nv_funtree(np))->functline:1;
264 shp->st.var_local = shp->st.save_tree = shp->var_tree;
265 if(filename)
266 {
267 shp->st.filename = filename;
268 shp->st.lineno = 1;
269 }
270 level = shp->fn_depth+shp->dot_depth+1;
271 nv_putval(SH_LEVELNOD,(char*)&level,NV_INT16);
272 shp->st.prevst = prevscope;
273 shp->st.self = &savst;
274 shp->topscope = (Shscope_t*)shp->st.self;
275 prevscope->save_tree = shp->var_tree;
276 shp->st.cmdname = argv[0];
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(&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 char buff[IOBSIZE+1];
293 iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fd,SF_READ);
294 sh_eval(iop,0);
295 }
296 }
297 sh_popcontext(&buff);
298 if(!np)
299 free((void*)shp->st.filename);
300 shp->dot_depth--;
301 if((np || argv[1]) && jmpval!=SH_JMPSCRIPT)
302 sh_argreset(shp,argsave,saveargfor);
303 else
304 {
305 prevscope->dolc = shp->st.dolc;
306 prevscope->dolv = shp->st.dolv;
307 }
308 if (shp->st.self != &savst)
309 *shp->st.self = shp->st;
310 /* only restore the top Shscope_t portion for posix functions */
311 memcpy((void*)&shp->st, (void*)prevscope, sizeof(Shscope_t));
312 shp->topscope = (Shscope_t*)prevscope;
313 nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
314 if(shp->exitval > SH_EXITSIG)
315 sh_fault(shp->exitval&SH_EXITMASK);
316 if(jmpval && jmpval!=SH_JMPFUN)
317 siglongjmp(*shp->jmplist,jmpval);
318 return(shp->exitval);
319 }
320
321 /*
322 * null, true command
323 */
b_true(int argc,register char * argv[],void * extra)324 int b_true(int argc,register char *argv[],void *extra)
325 {
326 NOT_USED(argc);
327 NOT_USED(argv[0]);
328 NOT_USED(extra);
329 return(0);
330 }
331
332 /*
333 * false command
334 */
b_false(int argc,register char * argv[],void * extra)335 int b_false(int argc,register char *argv[], void *extra)
336 {
337 NOT_USED(argc);
338 NOT_USED(argv[0]);
339 NOT_USED(extra);
340 return(1);
341 }
342
b_shift(register int n,register char * argv[],void * extra)343 int b_shift(register int n, register char *argv[], void *extra)
344 {
345 register char *arg;
346 register Shell_t *shp = ((Shbltin_t*)extra)->shp;
347 while((n = optget(argv,sh_optshift))) switch(n)
348 {
349 case ':':
350 errormsg(SH_DICT,2, "%s", opt_info.arg);
351 break;
352 case '?':
353 errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
354 return(2);
355 }
356 if(error_info.errors)
357 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
358 argv += opt_info.index;
359 n = ((arg= *argv)?(int)sh_arith(arg):1);
360 if(n<0 || shp->st.dolc<n)
361 errormsg(SH_DICT,ERROR_exit(1),e_number,arg);
362 else
363 {
364 shp->st.dolv += n;
365 shp->st.dolc -= n;
366 }
367 return(0);
368 }
369
b_wait(int n,register char * argv[],void * extra)370 int b_wait(int n,register char *argv[],void *extra)
371 {
372 register Shell_t *shp = ((Shbltin_t*)extra)->shp;
373 while((n = optget(argv,sh_optwait))) switch(n)
374 {
375 case ':':
376 errormsg(SH_DICT,2, "%s", opt_info.arg);
377 break;
378 case '?':
379 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
380 break;
381 }
382 if(error_info.errors)
383 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
384 argv += opt_info.index;
385 job_bwait(argv);
386 return(shp->exitval);
387 }
388
389 #ifdef JOBS
390 # if 0
391 /* for the dictionary generator */
392 int b_fg(int n,char *argv[],void *extra){}
393 int b_disown(int n,char *argv[],void *extra){}
394 # endif
b_bg(register int n,register char * argv[],void * extra)395 int b_bg(register int n,register char *argv[],void *extra)
396 {
397 register int flag = **argv;
398 register Shell_t *shp = ((Shbltin_t*)extra)->shp;
399 register const char *optstr = sh_optbg;
400 if(*argv[0]=='f')
401 optstr = sh_optfg;
402 else if(*argv[0]=='d')
403 optstr = sh_optdisown;
404 while((n = optget(argv,optstr))) switch(n)
405 {
406 case ':':
407 errormsg(SH_DICT,2, "%s", opt_info.arg);
408 break;
409 case '?':
410 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
411 break;
412 }
413 if(error_info.errors)
414 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
415 argv += opt_info.index;
416 if(!sh_isoption(SH_MONITOR) || !job.jobcontrol)
417 {
418 if(sh_isstate(SH_INTERACTIVE))
419 errormsg(SH_DICT,ERROR_exit(1),e_no_jctl);
420 return(1);
421 }
422 if(flag=='d' && *argv==0)
423 argv = (char**)0;
424 if(job_walk(sfstdout,job_switch,flag,argv))
425 errormsg(SH_DICT,ERROR_exit(1),e_no_job);
426 return(shp->exitval);
427 }
428
b_jobs(register int n,char * argv[],void * extra)429 int b_jobs(register int n,char *argv[],void *extra)
430 {
431 register int flag = 0;
432 register Shell_t *shp = ((Shbltin_t*)extra)->shp;
433 while((n = optget(argv,sh_optjobs))) switch(n)
434 {
435 case 'l':
436 flag = JOB_LFLAG;
437 break;
438 case 'n':
439 flag = JOB_NFLAG;
440 break;
441 case 'p':
442 flag = JOB_PFLAG;
443 break;
444 case ':':
445 errormsg(SH_DICT,2, "%s", opt_info.arg);
446 break;
447 case '?':
448 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
449 break;
450 }
451 argv += opt_info.index;
452 if(error_info.errors)
453 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
454 if(*argv==0)
455 argv = (char**)0;
456 if(job_walk(sfstdout,job_list,flag,argv))
457 errormsg(SH_DICT,ERROR_exit(1),e_no_job);
458 job_wait((pid_t)0);
459 return(shp->exitval);
460 }
461 #endif
462
463 #ifdef _cmd_universe
464 /*
465 * There are several universe styles that are masked by the getuniv(),
466 * setuniv() calls.
467 */
b_universe(int argc,char * argv[],void * extra)468 int b_universe(int argc, char *argv[],void *extra)
469 {
470 register char *arg;
471 register int n;
472 NOT_USED(extra);
473 while((n = optget(argv,sh_optuniverse))) switch(n)
474 {
475 case ':':
476 errormsg(SH_DICT,2, "%s", opt_info.arg);
477 break;
478 case '?':
479 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
480 break;
481 }
482 argv += opt_info.index;
483 argc -= opt_info.index;
484 if(error_info.errors || argc>1)
485 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
486 if(arg = argv[0])
487 {
488 if(!astconf("UNIVERSE",0,arg))
489 errormsg(SH_DICT,ERROR_exit(1), e_badname,arg);
490 }
491 else
492 {
493 if(!(arg=astconf("UNIVERSE",0,0)))
494 errormsg(SH_DICT,ERROR_exit(1),e_nouniverse);
495 else
496 sfputr(sfstdout,arg,'\n');
497 }
498 return(0);
499 }
500 #endif /* cmd_universe */
501
502 #if SHOPT_FS_3D
503 # if 0
504 /* for the dictionary generator */
505 int b_vmap(int argc,char *argv[], void *extra){}
506 # endif
b_vpath(register int argc,char * argv[],void * extra)507 int b_vpath(register int argc,char *argv[], void *extra)
508 {
509 register int flag, n;
510 register const char *optstr;
511 register char *vend;
512 register Shell_t *shp = ((Shbltin_t*)extra)->shp;
513 if(argv[0][1]=='p')
514 {
515 optstr = sh_optvpath;
516 flag = FS3D_VIEW;
517 }
518 else
519 {
520 optstr = sh_optvmap;
521 flag = FS3D_VERSION;
522 }
523 while(n = optget(argv, optstr)) switch(n)
524 {
525 case ':':
526 errormsg(SH_DICT,2, "%s", opt_info.arg);
527 break;
528 case '?':
529 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
530 break;
531 }
532 if(error_info.errors)
533 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
534 if(!shp->lim.fs3d)
535 goto failed;
536 argv += opt_info.index;
537 argc -= opt_info.index;
538 switch(argc)
539 {
540 case 0:
541 case 1:
542 flag |= FS3D_GET;
543 if((n = mount(*argv,(char*)0,flag,0)) >= 0)
544 {
545 vend = stkalloc(shp->stk,++n);
546 n = mount(*argv,vend,flag|FS3D_SIZE(n),0);
547 }
548 if(n < 0)
549 goto failed;
550 if(argc==1)
551 {
552 sfprintf(sfstdout,"%s\n",vend);
553 break;
554 }
555 n = 0;
556 while(flag = *vend++)
557 {
558 if(flag==' ')
559 {
560 flag = e_sptbnl[n+1];
561 n = !n;
562 }
563 sfputc(sfstdout,flag);
564 }
565 if(n)
566 sfputc(sfstdout,'\n');
567 break;
568 default:
569 if((argc&1))
570 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
571 /*FALLTHROUGH*/
572 case 2:
573 if(!shp->lim.fs3d)
574 goto failed;
575 if(shp->subshell && !shp->subshare)
576 sh_subfork();
577 for(n=0;n<argc;n+=2)
578 {
579 if(mount(argv[n+1],argv[n],flag,0)<0)
580 goto failed;
581 }
582 }
583 return(0);
584 failed:
585 if(argc>1)
586 errormsg(SH_DICT,ERROR_exit(1),e_cantset,flag==2?e_mapping:e_versions);
587 else
588 errormsg(SH_DICT,ERROR_exit(1),e_cantget,flag==2?e_mapping:e_versions);
589 return(1);
590 }
591 #endif /* SHOPT_FS_3D */
592
593