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