xref: /titanic_50/usr/src/lib/libshell/common/bltins/misc.c (revision 7eea693d6b672899726e75993fddc4e95b52647f)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5 *                      and is licensed under the                       *
6 *                  Common Public License, Version 1.0                  *
7 *                      by AT&T Knowledge Ventures                      *
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 = (Shell_t*)extra;
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 = (Shell_t*)extra;
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)
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() < 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();
153 		path_exec(pname,argv,NIL(struct argnod*));
154 		sh_done(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 = (Shell_t*)extra;
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 = (Shell_t*)extra;
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 	NOT_USED(extra);
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++ > DOTMAX)
234 		errormsg(SH_DICT,ERROR_exit(1),e_toodeep,script);
235 	shp->st.lineno = error_info.line;
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 #ifdef PATH_BFPATH
245 				path_search(script,NIL(Pathcomp_t*),0);
246 #else
247 				path_search(script,NIL(char*),0);
248 #endif
249 				if(np->nvalue.ip)
250 				{
251 					if(nv_isattr(np,NV_FPOSIX))
252 						np = 0;
253 				}
254 				else
255 					errormsg(SH_DICT,ERROR_exit(1),e_found,script);
256 			}
257 		}
258 		else
259 			np = 0;
260 		if(!np)
261 		{
262 			if((fd=path_open(script,path_get(script))) < 0)
263 				errormsg(SH_DICT,ERROR_system(1),e_open,script);
264 			filename = path_fullname(stakptr(PATH_OFFSET));
265 		}
266 	}
267 	*prevscope = shp->st;
268 	if(filename)
269 		shp->st.filename = filename;
270 	shp->st.prevst = prevscope;
271 	shp->st.self = &savst;
272 	shp->topscope = (Shscope_t*)shp->st.self;
273 	prevscope->save_tree = shp->var_tree;
274 	shp->st.cmdname = argv[0];
275 	if(np)
276 		shp->st.filename = np->nvalue.rp->fname;
277 	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
278 	shp->posix_fun = 0;
279 	if(np || argv[1])
280 		argsave = sh_argnew(argv,&saveargfor);
281 	sh_pushcontext(&buff,SH_JMPDOT);
282 	jmpval = sigsetjmp(buff.buff,0);
283 	if(jmpval == 0)
284 	{
285 		if(np)
286 			sh_exec((Shnode_t*)(nv_funtree(np)),sh_isstate(SH_ERREXIT));
287 		else
288 		{
289 			char buff[IOBSIZE+1];
290 			iop = sfnew(NIL(Sfio_t*),buff,IOBSIZE,fd,SF_READ);
291 			sh_eval(iop,0);
292 		}
293 	}
294 	sh_popcontext(&buff);
295 	if(!np)
296 		free((void*)shp->st.filename);
297 	shp->dot_depth--;
298 	if((np || argv[1]) && jmpval!=SH_JMPSCRIPT)
299 		sh_argreset(argsave,saveargfor);
300 	else
301 	{
302 		prevscope->dolc = shp->st.dolc;
303 		prevscope->dolv = shp->st.dolv;
304 	}
305 	if (shp->st.self != &savst)
306 		*shp->st.self = shp->st;
307 	/* only restore the top Shscope_t portion for posix functions */
308 	memcpy((void*)&shp->st, (void*)prevscope, sizeof(Shscope_t));
309 	shp->topscope = (Shscope_t*)prevscope;
310 	nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE);
311 	if(shp->exitval > SH_EXITSIG)
312 		sh_fault(shp->exitval&SH_EXITMASK);
313 	if(jmpval && jmpval!=SH_JMPFUN)
314 		siglongjmp(*shp->jmplist,jmpval);
315 	return(shp->exitval);
316 }
317 
318 /*
319  * null, true  command
320  */
321 int    b_true(int argc,register char *argv[],void *extra)
322 {
323 	NOT_USED(argc);
324 	NOT_USED(argv[0]);
325 	NOT_USED(extra);
326 	return(0);
327 }
328 
329 /*
330  * false  command
331  */
332 int    b_false(int argc,register char *argv[], void *extra)
333 {
334 	NOT_USED(argc);
335 	NOT_USED(argv[0]);
336 	NOT_USED(extra);
337 	return(1);
338 }
339 
340 int    b_shift(register int n, register char *argv[], void *extra)
341 {
342 	register char *arg;
343 	register Shell_t *shp = (Shell_t*)extra;
344 	while((n = optget(argv,sh_optshift))) switch(n)
345 	{
346 		case ':':
347 			errormsg(SH_DICT,2, "%s", opt_info.arg);
348 			break;
349 		case '?':
350 			errormsg(SH_DICT,ERROR_usage(0), "%s",opt_info.arg);
351 			return(2);
352 	}
353 	if(error_info.errors)
354 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
355 	argv += opt_info.index;
356 	n = ((arg= *argv)?(int)sh_arith(arg):1);
357 	if(n<0 || shp->st.dolc<n)
358 		errormsg(SH_DICT,ERROR_exit(1),e_number,arg);
359 	else
360 	{
361 		shp->st.dolv += n;
362 		shp->st.dolc -= n;
363 	}
364 	return(0);
365 }
366 
367 int    b_wait(int n,register char *argv[],void *extra)
368 {
369 	register Shell_t *shp = (Shell_t*)extra;
370 	while((n = optget(argv,sh_optwait))) switch(n)
371 	{
372 		case ':':
373 			errormsg(SH_DICT,2, "%s", opt_info.arg);
374 			break;
375 		case '?':
376 			errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
377 			break;
378 	}
379 	if(error_info.errors)
380 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
381 	argv += opt_info.index;
382 	job_bwait(argv);
383 	return(shp->exitval);
384 }
385 
386 #ifdef JOBS
387 #   if 0
388     /* for the dictionary generator */
389 	int    b_fg(int n,char *argv[],void *extra){}
390 	int    b_disown(int n,char *argv[],void *extra){}
391 #   endif
392 int    b_bg(register int n,register char *argv[],void *extra)
393 {
394 	register int flag = **argv;
395 	register Shell_t *shp = (Shell_t*)extra;
396 	register const char *optstr = sh_optbg;
397 	if(*argv[0]=='f')
398 		optstr = sh_optfg;
399 	else if(*argv[0]=='d')
400 		optstr = sh_optdisown;
401 	while((n = optget(argv,optstr))) switch(n)
402 	{
403 	    case ':':
404 		errormsg(SH_DICT,2, "%s", opt_info.arg);
405 		break;
406 	    case '?':
407 		errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
408 		break;
409 	}
410 	if(error_info.errors)
411 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
412 	argv += opt_info.index;
413 	if(!sh_isoption(SH_MONITOR) || !job.jobcontrol)
414 	{
415 		if(sh_isstate(SH_INTERACTIVE))
416 			errormsg(SH_DICT,ERROR_exit(1),e_no_jctl);
417 		return(1);
418 	}
419 	if(flag=='d' && *argv==0)
420 		argv = (char**)0;
421 	if(job_walk(sfstdout,job_switch,flag,argv))
422 		errormsg(SH_DICT,ERROR_exit(1),e_no_job);
423 	return(shp->exitval);
424 }
425 
426 int    b_jobs(register int n,char *argv[],void *extra)
427 {
428 	register int flag = 0;
429 	register Shell_t *shp = (Shell_t*)extra;
430 	while((n = optget(argv,sh_optjobs))) switch(n)
431 	{
432 	    case 'l':
433 		flag = JOB_LFLAG;
434 		break;
435 	    case 'n':
436 		flag = JOB_NFLAG;
437 		break;
438 	    case 'p':
439 		flag = JOB_PFLAG;
440 		break;
441 	    case ':':
442 		errormsg(SH_DICT,2, "%s", opt_info.arg);
443 		break;
444 	    case '?':
445 		errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
446 		break;
447 	}
448 	argv += opt_info.index;
449 	if(error_info.errors)
450 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
451 	if(*argv==0)
452 		argv = (char**)0;
453 	if(job_walk(sfstdout,job_list,flag,argv))
454 		errormsg(SH_DICT,ERROR_exit(1),e_no_job);
455 	job_wait((pid_t)0);
456 	return(shp->exitval);
457 }
458 #endif
459 
460 #ifdef _cmd_universe
461 /*
462  * There are several universe styles that are masked by the getuniv(),
463  * setuniv() calls.
464  */
465 int	b_universe(int argc, char *argv[],void *extra)
466 {
467 	register char *arg;
468 	register int n;
469 	NOT_USED(extra);
470 	while((n = optget(argv,sh_optuniverse))) switch(n)
471 	{
472 	    case ':':
473 		errormsg(SH_DICT,2, "%s", opt_info.arg);
474 		break;
475 	    case '?':
476 		errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
477 		break;
478 	}
479 	argv += opt_info.index;
480 	argc -= opt_info.index;
481 	if(error_info.errors || argc>1)
482 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
483 	if(arg = argv[0])
484 	{
485 		if(!astconf("UNIVERSE",0,arg))
486 			errormsg(SH_DICT,ERROR_exit(1), e_badname,arg);
487 	}
488 	else
489 	{
490 		if(!(arg=astconf("UNIVERSE",0,0)))
491 			errormsg(SH_DICT,ERROR_exit(1),e_nouniverse);
492 		else
493 			sfputr(sfstdout,arg,'\n');
494 	}
495 	return(0);
496 }
497 #endif /* cmd_universe */
498 
499 #if SHOPT_FS_3D
500 #   if 0
501     /* for the dictionary generator */
502     int	b_vmap(int argc,char *argv[], void *extra){}
503 #   endif
504     int	b_vpath(register int argc,char *argv[], void *extra)
505     {
506 	register int flag, n;
507 	register const char *optstr;
508 	register char *vend;
509 	register Shell_t *shp = (Shell_t*)extra;
510 	if(argv[0][1]=='p')
511 	{
512 		optstr = sh_optvpath;
513 		flag = FS3D_VIEW;
514 	}
515 	else
516 	{
517 		optstr = sh_optvmap;
518 		flag = FS3D_VERSION;
519 	}
520 	while(n = optget(argv, optstr)) switch(n)
521 	{
522 	    case ':':
523 		errormsg(SH_DICT,2, "%s", opt_info.arg);
524 		break;
525 	    case '?':
526 		errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg);
527 		break;
528 	}
529 	if(error_info.errors)
530 		errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
531 	if(!shp->lim.fs3d)
532 		goto failed;
533 	argv += opt_info.index;
534 	argc -= opt_info.index;
535 	switch(argc)
536 	{
537 	    case 0:
538 	    case 1:
539 		flag |= FS3D_GET;
540 		if((n = mount(*argv,(char*)0,flag,0)) >= 0)
541 		{
542 			vend = stakalloc(++n);
543 			n = mount(*argv,vend,flag|FS3D_SIZE(n),0);
544 		}
545 		if(n < 0)
546 			goto failed;
547 		if(argc==1)
548 		{
549 			sfprintf(sfstdout,"%s\n",vend);
550 			break;
551 		}
552 		n = 0;
553 		while(flag = *vend++)
554 		{
555 			if(flag==' ')
556 			{
557 				flag  = e_sptbnl[n+1];
558 				n = !n;
559 			}
560 			sfputc(sfstdout,flag);
561 		}
562 		if(n)
563 			sfputc(sfstdout,'\n');
564 		break;
565 	     default:
566 		if((argc&1))
567 			errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0));
568 		/*FALLTHROUGH*/
569 	     case 2:
570 		if(!shp->lim.fs3d)
571 			goto failed;
572 		if(shp->subshell)
573 			sh_subfork();
574  		for(n=0;n<argc;n+=2)
575 		{
576 			if(mount(argv[n+1],argv[n],flag,0)<0)
577 				goto failed;
578 		}
579 	}
580 	return(0);
581 failed:
582 	if(argc>1)
583 		errormsg(SH_DICT,ERROR_exit(1),e_cantset,flag==2?e_mapping:e_versions);
584 	else
585 		errormsg(SH_DICT,ERROR_exit(1),e_cantget,flag==2?e_mapping:e_versions);
586 	return(1);
587     }
588 #endif /* SHOPT_FS_3D */
589 
590