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