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