xref: /titanic_50/usr/src/lib/libshell/common/bltins/misc.c (revision d6114e2d100d9ec3b45f9968d45ac2e3a0827af0)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2009 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 
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 
92 static void     noexport(register Namval_t* np, void *data)
93 {
94 	NOT_USED(data);
95 	nv_offattr(np,NV_EXPORT);
96 }
97 
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 
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 
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 
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  */
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  */
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 
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 
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
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 
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  */
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
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