Home | History | Annotate | Download | only in bltins
      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 (at) 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