1 /*********************************************************************** 2 * * 3 * This software is part of the ast package * 4 * Copyright (c) 1982-2012 AT&T Intellectual Property * 5 * and is licensed under the * 6 * Eclipse Public License, Version 1.0 * 7 * by AT&T Intellectual Property * 8 * * 9 * A copy of the License is available at * 10 * http://www.eclipse.org/org/documents/epl-v10.html * 11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) * 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 __unused, char *argv[], Shbltin_t *context) 61 { 62 struct login logdata; 63 register int n; 64 logdata.clear = 0; 65 logdata.arg0 = 0; 66 logdata.sh = context->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,(Shbltin_t*)&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[],Shbltin_t *context) 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 = context->shp; 106 else 107 { 108 logp = (struct login*)context; 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(shp,pname,argv,NIL(struct argnod*)); 154 sh_done(shp,0); 155 } 156 return(1); 157 } 158 159 int b_let(int argc,char *argv[],Shbltin_t *context) 160 { 161 register int r; 162 register char *arg; 163 Shell_t *shp = context->shp; 164 NOT_USED(argc); 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(shp,arg); 179 return(r); 180 } 181 182 int b_eval(int argc,char *argv[], Shbltin_t *context) 183 { 184 register int r; 185 register Shell_t *shp = context->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[],Shbltin_t *context) 208 { 209 register char *script; 210 register Namval_t *np; 211 register int jmpval; 212 register Shell_t *shp = context->shp; 213 struct sh_scoped savst, *prevscope = shp->st.self; 214 char *filename=0, *buffer=0; 215 int fd; 216 struct dolnod *saveargfor; 217 volatile struct dolnod *argsave=0; 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(shp,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(shp,script,path_get(shp,script))) < 0) 259 errormsg(SH_DICT,ERROR_system(1),e_open,script); 260 filename = path_fullname(shp,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 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(shp,&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 buffer = malloc(IOBSIZE+1); 293 iop = sfnew(NIL(Sfio_t*),buffer,IOBSIZE,fd,SF_READ); 294 sh_offstate(SH_NOFORK); 295 sh_eval(iop,sh_isstate(SH_PROFILE)?SH_FUNEVAL:0); 296 } 297 } 298 sh_popcontext(shp,&buff); 299 if(buffer) 300 free(buffer); 301 if(!np) 302 free((void*)shp->st.filename); 303 shp->dot_depth--; 304 if((np || argv[1]) && jmpval!=SH_JMPSCRIPT) 305 sh_argreset(shp,(struct dolnod*)argsave,saveargfor); 306 else 307 { 308 prevscope->dolc = shp->st.dolc; 309 prevscope->dolv = shp->st.dolv; 310 } 311 if (shp->st.self != &savst) 312 *shp->st.self = shp->st; 313 /* only restore the top Shscope_t portion for posix functions */ 314 memcpy((void*)&shp->st, (void*)prevscope, sizeof(Shscope_t)); 315 shp->topscope = (Shscope_t*)prevscope; 316 nv_putval(SH_PATHNAMENOD, shp->st.filename ,NV_NOFREE); 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[],Shbltin_t *context) 326 { 327 NOT_USED(argc); 328 NOT_USED(argv[0]); 329 NOT_USED(context); 330 return(0); 331 } 332 333 /* 334 * false command 335 */ 336 int b_false(int argc,register char *argv[], Shbltin_t *context) 337 { 338 NOT_USED(argc); 339 NOT_USED(argv[0]); 340 NOT_USED(context); 341 return(1); 342 } 343 344 int b_shift(register int n, register char *argv[], Shbltin_t *context) 345 { 346 register char *arg; 347 register Shell_t *shp = context->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(shp,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[],Shbltin_t *context) 372 { 373 register Shell_t *shp = context->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[],Shbltin_t *context){} 394 int b_disown(int n,char *argv[],Shbltin_t *context){} 395 # endif 396 int b_bg(register int n,register char *argv[],Shbltin_t *context) 397 { 398 register int flag = **argv; 399 register Shell_t *shp = context->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[],Shbltin_t *context) 431 { 432 register int flag = 0; 433 register Shell_t *shp = context->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[],Shbltin_t *context) 470 { 471 register char *arg; 472 register int n; 473 NOT_USED(context); 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 _UWIN 505 #include <sys/mount.h> 506 #endif 507 # if 0 508 /* for the dictionary generator */ 509 int b_vmap(int argc,char *argv[], Shbltin_t *context){} 510 # endif 511 int b_vpath(register int argc,char *argv[], Shbltin_t *context) 512 { 513 register int flag, n; 514 register const char *optstr; 515 register char *vend; 516 register Shell_t *shp = context->shp; 517 if(argv[0][1]=='p') 518 { 519 optstr = sh_optvpath; 520 flag = FS3D_VIEW; 521 } 522 else 523 { 524 optstr = sh_optvmap; 525 flag = FS3D_VERSION; 526 } 527 while(n = optget(argv, optstr)) switch(n) 528 { 529 case ':': 530 errormsg(SH_DICT,2, "%s", opt_info.arg); 531 break; 532 case '?': 533 errormsg(SH_DICT,ERROR_usage(2), "%s",opt_info.arg); 534 break; 535 } 536 if(error_info.errors) 537 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); 538 #ifdef MS_3D 539 flag |= MS_3D; 540 #else 541 if(!shp->gd->lim.fs3d) 542 goto failed; 543 #endif 544 argv += opt_info.index; 545 argc -= opt_info.index; 546 switch(argc) 547 { 548 case 0: 549 case 1: 550 flag |= FS3D_GET; 551 if((n = mount(*argv,(char*)0,flag,0)) >= 0) 552 { 553 vend = stkalloc(shp->stk,++n); 554 n = mount(*argv,vend,flag|FS3D_SIZE(n),0); 555 } 556 if(n < 0) 557 goto failed; 558 if(argc==1) 559 { 560 sfprintf(sfstdout,"%s\n",vend); 561 break; 562 } 563 n = 0; 564 while(flag = *vend++) 565 { 566 if(flag==' ') 567 { 568 flag = e_sptbnl[n+1]; 569 n = !n; 570 } 571 sfputc(sfstdout,flag); 572 } 573 if(n) 574 sfputc(sfstdout,'\n'); 575 break; 576 default: 577 if((argc&1)) 578 errormsg(SH_DICT,ERROR_usage(2),"%s",optusage((char*)0)); 579 /*FALLTHROUGH*/ 580 case 2: 581 if(shp->subshell && !shp->subshare) 582 sh_subfork(); 583 for(n=0;n<argc;n+=2) 584 if(mount(argv[n+1],argv[n],flag,0)<0) 585 goto failed; 586 } 587 return(0); 588 failed: 589 errormsg(SH_DICT,ERROR_exit(1),(argc>1)?e_cantset:e_cantget,(flag&FS3D_VIEW)?e_mapping:e_versions); 590 return(1); 591 } 592 #endif /* SHOPT_FS_3D */ 593 594