xref: /titanic_51/usr/src/lib/libshell/common/bltins/misc.c (revision 3ce7283d71d01ba5f0245dc25366a3791a324d04)
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 
60 int
61 b_exec(int argc __unused, char *argv[], void *extra)
62 {
63 	struct login logdata;
64 	register int n;
65 	logdata.clear = 0;
66 	logdata.arg0 = 0;
67 	logdata.sh = ((Shbltin_t*)extra)->shp;
68         logdata.sh->st.ioset = 0;
69 	while (n = optget(argv, sh_optexec)) switch (n)
70 	{
71 	    case 'a':
72 		logdata.arg0 = opt_info.arg;
73 		argc = 0;
74 		break;
75 	    case 'c':
76 		logdata.clear=1;
77 		break;
78 	    case ':':
79 		errormsg(SH_DICT,2, "%s", opt_info.arg);
80 		break;
81 	    case '?':
82 		errormsg(SH_DICT,ERROR_usage(0), "%s", opt_info.arg);
83 		return(2);
84 	}
85 	argv += opt_info.index;
86 	if(error_info.errors)
87 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
88 	if(*argv)
89                 B_login(0,argv,(void*)&logdata);
90 	return(0);
91 }
92 
93 static void     noexport(register Namval_t* np, void *data)
94 {
95 	NOT_USED(data);
96 	nv_offattr(np,NV_EXPORT);
97 }
98 
99 int    B_login(int argc,char *argv[],void *extra)
100 {
101 	struct checkpt *pp;
102 	register struct login *logp=0;
103 	register Shell_t *shp;
104 	const char *pname;
105 	if(argc)
106 		shp = ((Shbltin_t*)extra)->shp;
107 	else
108 	{
109 		logp = (struct login*)extra;
110 		shp = logp->sh;
111 	}
112 	pp = (struct checkpt*)shp->jmplist;
113 	if(sh_isoption(SH_RESTRICTED))
114 		errormsg(SH_DICT,ERROR_exit(1),e_restricted,argv[0]);
115 	else
116         {
117 		register struct argnod *arg=shp->envlist;
118 		register Namval_t* np;
119 		register char *cp;
120 		if(shp->subshell && !shp->subshare)
121 			sh_subfork();
122 		if(logp && logp->clear)
123 		{
124 #ifdef _ENV_H
125 			env_close(shp->env);
126 			shp->env = env_open((char**)0,3);
127 #else
128 			nv_scan(shp->var_tree,noexport,0,NV_EXPORT,NV_EXPORT);
129 #endif
130 		}
131 		while(arg)
132 		{
133 			if((cp=strchr(arg->argval,'=')) &&
134 				(*cp=0,np=nv_search(arg->argval,shp->var_tree,0)))
135 			{
136 				nv_onattr(np,NV_EXPORT);
137 				sh_envput(shp->env,np);
138 			}
139 			if(cp)
140 				*cp = '=';
141 			arg=arg->argnxt.ap;
142 		}
143 		pname = argv[0];
144 		if(logp && logp->arg0)
145 			argv[0] = logp->arg0;
146 #ifdef JOBS
147 		if(job_close(shp) < 0)
148 			return(1);
149 #endif /* JOBS */
150 		/* force bad exec to terminate shell */
151 		pp->mode = SH_JMPEXIT;
152 		sh_sigreset(2);
153 		sh_freeup(shp);
154 		path_exec(pname,argv,NIL(struct argnod*));
155 		sh_done(shp,0);
156         }
157 	return(1);
158 }
159 
160 int    b_let(int argc,char *argv[],void *extra)
161 {
162 	register int r;
163 	register char *arg;
164 	NOT_USED(argc);
165 	NOT_USED(extra);
166 	while (r = optget(argv,sh_optlet)) switch (r)
167 	{
168 	    case ':':
169 		errormsg(SH_DICT,2, "%s", opt_info.arg);
170 		break;
171 	    case '?':
172 		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
173 		break;
174 	}
175 	argv += opt_info.index;
176 	if(error_info.errors || !*argv)
177 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
178 	while(arg= *argv++)
179 		r = !sh_arith(arg);
180 	return(r);
181 }
182 
183 int    b_eval(int argc,char *argv[], void *extra)
184 {
185 	register int r;
186 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
187 	NOT_USED(argc);
188 	while (r = optget(argv,sh_opteval)) switch (r)
189 	{
190 	    case ':':
191 		errormsg(SH_DICT,2, "%s", opt_info.arg);
192 		break;
193 	    case '?':
194 		errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
195 		return(2);
196 	}
197 	if(error_info.errors)
198 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
199 	argv += opt_info.index;
200 	if(*argv && **argv)
201 	{
202 		sh_offstate(SH_MONITOR);
203 		sh_eval(sh_sfeval(argv),0);
204 	}
205 	return(shp->exitval);
206 }
207 
208 int    b_dot_cmd(register int n,char *argv[],void* extra)
209 {
210 	register char *script;
211 	register Namval_t *np;
212 	register int jmpval;
213 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
214 	struct sh_scoped savst, *prevscope = shp->st.self;
215 	char *filename=0;
216 	int	fd;
217 	struct dolnod   *argsave=0, *saveargfor;
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(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(script,path_get(script))) < 0)
259 				errormsg(SH_DICT,ERROR_system(1),e_open,script);
260 			filename = path_fullname(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 	shp->st.cmdname = argv[0];
278 	if(np)
279 		shp->st.filename = np->nvalue.rp->fname;
280 	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
281 	shp->posix_fun = 0;
282 	if(np || argv[1])
283 		argsave = sh_argnew(shp,argv,&saveargfor);
284 	sh_pushcontext(&buff,SH_JMPDOT);
285 	jmpval = sigsetjmp(buff.buff,0);
286 	if(jmpval == 0)
287 	{
288 		shp->dot_depth++;
289 		if(np)
290 			sh_exec((Shnode_t*)(nv_funtree(np)),sh_isstate(SH_ERREXIT));
291 		else
292 		{
293 			char buff[IOBSIZE+1];
294 			iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fd,SF_READ);
295 			sh_eval(iop,0);
296 		}
297 	}
298 	sh_popcontext(&buff);
299 	if(!np)
300 		free((void*)shp->st.filename);
301 	shp->dot_depth--;
302 	if((np || argv[1]) && jmpval!=SH_JMPSCRIPT)
303 		sh_argreset(shp,argsave,saveargfor);
304 	else
305 	{
306 		prevscope->dolc = shp->st.dolc;
307 		prevscope->dolv = shp->st.dolv;
308 	}
309 	if (shp->st.self != &savst)
310 		*shp->st.self = shp->st;
311 	/* only restore the top Shscope_t portion for posix functions */
312 	memcpy((void*)&shp->st, (void*)prevscope, sizeof(Shscope_t));
313 	shp->topscope = (Shscope_t*)prevscope;
314 	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
315 	if(shp->exitval > SH_EXITSIG)
316 		sh_fault(shp->exitval&SH_EXITMASK);
317 	if(jmpval && jmpval!=SH_JMPFUN)
318 		siglongjmp(*shp->jmplist,jmpval);
319 	return(shp->exitval);
320 }
321 
322 /*
323  * null, true  command
324  */
325 int    b_true(int argc,register char *argv[],void *extra)
326 {
327 	NOT_USED(argc);
328 	NOT_USED(argv[0]);
329 	NOT_USED(extra);
330 	return(0);
331 }
332 
333 /*
334  * false  command
335  */
336 int    b_false(int argc,register char *argv[], void *extra)
337 {
338 	NOT_USED(argc);
339 	NOT_USED(argv[0]);
340 	NOT_USED(extra);
341 	return(1);
342 }
343 
344 int    b_shift(register int n, register char *argv[], void *extra)
345 {
346 	register char *arg;
347 	register Shell_t *shp = ((Shbltin_t*)extra)->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(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 
371 int    b_wait(int n,register char *argv[],void *extra)
372 {
373 	register Shell_t *shp = ((Shbltin_t*)extra)->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[],void *extra){}
394 	int    b_disown(int n,char *argv[],void *extra){}
395 #   endif
396 int    b_bg(register int n,register char *argv[],void *extra)
397 {
398 	register int flag = **argv;
399 	register Shell_t *shp = ((Shbltin_t*)extra)->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 
430 int    b_jobs(register int n,char *argv[],void *extra)
431 {
432 	register int flag = 0;
433 	register Shell_t *shp = ((Shbltin_t*)extra)->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  */
469 int	b_universe(int argc, char *argv[],void *extra)
470 {
471 	register char *arg;
472 	register int n;
473 	NOT_USED(extra);
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 0
505     /* for the dictionary generator */
506     int	b_vmap(int argc,char *argv[], void *extra){}
507 #   endif
508     int	b_vpath(register int argc,char *argv[], void *extra)
509     {
510 	register int flag, n;
511 	register const char *optstr;
512 	register char *vend;
513 	register Shell_t *shp = ((Shbltin_t*)extra)->shp;
514 	if(argv[0][1]=='p')
515 	{
516 		optstr = sh_optvpath;
517 		flag = FS3D_VIEW;
518 	}
519 	else
520 	{
521 		optstr = sh_optvmap;
522 		flag = FS3D_VERSION;
523 	}
524 	while(n = optget(argv, optstr)) switch(n)
525 	{
526 	    case ':':
527 		errormsg(SH_DICT,2, "%s", opt_info.arg);
528 		break;
529 	    case '?':
530 		errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
531 		break;
532 	}
533 	if(error_info.errors)
534 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
535 	if(!shp->lim.fs3d)
536 		goto failed;
537 	argv += opt_info.index;
538 	argc -= opt_info.index;
539 	switch(argc)
540 	{
541 	    case 0:
542 	    case 1:
543 		flag |= FS3D_GET;
544 		if((n = mount(*argv,(char*)0,flag,0)) >= 0)
545 		{
546 			vend = stkalloc(shp->stk,++n);
547 			n = mount(*argv,vend,flag|FS3D_SIZE(n),0);
548 		}
549 		if(n < 0)
550 			goto failed;
551 		if(argc==1)
552 		{
553 			sfprintf(sfstdout,"%s\n",vend);
554 			break;
555 		}
556 		n = 0;
557 		while(flag = *vend++)
558 		{
559 			if(flag==' ')
560 			{
561 				flag  = e_sptbnl[n+1];
562 				n = !n;
563 			}
564 			sfputc(sfstdout,flag);
565 		}
566 		if(n)
567 			sfputc(sfstdout,'\n');
568 		break;
569 	     default:
570 		if((argc&1))
571 			errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
572 		/*FALLTHROUGH*/
573 	     case 2:
574 		if(!shp->lim.fs3d)
575 			goto failed;
576 		if(shp->subshell && !shp->subshare)
577 			sh_subfork();
578  		for(n=0;n<argc;n+=2)
579 		{
580 			if(mount(argv[n+1],argv[n],flag,0)<0)
581 				goto failed;
582 		}
583 	}
584 	return(0);
585 failed:
586 	if(argc>1)
587 		errormsg(SH_DICT,ERROR_exit(1),e_cantset,flag==2?e_mapping:e_versions);
588 	else
589 		errormsg(SH_DICT,ERROR_exit(1),e_cantget,flag==2?e_mapping:e_versions);
590 	return(1);
591     }
592 #endif /* SHOPT_FS_3D */
593 
594