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 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