1 /* @(#)builtin.c 1.1 */ 2 3 /* 4 * builtin routines for the shell 5 * 6 * David Korn 7 * AT&T Bell Laboratories 8 * Room 5D-112 9 * Murray Hill, N. J. 07974 10 * Tel. x7975 11 * 12 */ 13 14 #include "defs.h" 15 #include "sym.h" 16 #include "io.h" 17 #include "history.h" 18 #include "builtins.h" 19 #include "flags.h" 20 #include "name.h" 21 #include "mode.h" 22 #include "brkincr.h" 23 #include "shtype.h" 24 #include "stak.h" 25 #ifdef JOBS 26 #include "jobs.h" 27 #endif /* JOBS */ 28 29 #ifdef BSD_4_2 30 #include <sys/time.h> /* needed for ulimit */ 31 #include <sys/resource.h>/* needed for ulimit */ 32 #define LIM_FSIZE RLIMIT_FSIZE 33 #define LIM_DATA RLIMIT_DATA 34 #define LIM_STACK RLIMIT_STACK 35 #define LIM_CORE RLIMIT_CORE 36 #define LIM_CPU RLIMIT_CPU 37 #define LIM_MAXRSS RLIMIT_RSS 38 #define INFINITY RLIM_INFINITY 39 #endif /* BSD_4_2 */ 40 41 /* This module defines these routines */ 42 void builtin(); 43 int execexp(); 44 45 /* This module references these external routines */ 46 extern long aeval(); 47 extern void arg_set(); 48 extern void await(); 49 extern void cannon_path(); 50 extern char *catpath(); 51 extern NAMPTR checkfor(); 52 extern FILE *chkopen(); 53 extern void clrsig(); 54 extern TREPTR cmd(); 55 extern void do_whence(); 56 extern void done(); 57 #ifdef ECHO_N 58 extern char *echo_mode(); 59 #endif /* ECHO_N */ 60 extern int estabf(); 61 extern void execa(); 62 extern void exitsh(); 63 extern void failed(); 64 extern void fassign(); 65 extern void free(); 66 extern char *getpwd(); 67 extern void getsig(); 68 extern void gscan_all(); 69 extern char *heap(); 70 extern void hist_cancel(); 71 extern void hist_close(); 72 extern histloc hist_find(); 73 extern void hist_flush(); 74 extern long hist_list(); 75 extern void hist_open(); 76 extern void hist_subst(); 77 extern long hist_position(); 78 extern void initf(); 79 extern char *movstr(); 80 extern void oldsigs(); 81 extern void p_flush(); 82 extern void p_list(); 83 extern void p_num(); 84 extern void p_setout(); 85 extern void p_str(); 86 extern void p_time(); 87 extern FILE *pathopen(); 88 extern void pipe_close(); 89 extern void printflg(); 90 extern void prinscan(); 91 extern int printnam(); 92 extern char *realias(); 93 extern char *strcat(); 94 extern char *strchr(); 95 extern char *strcpy(); 96 extern char *substitute(); 97 extern FILE *tmp_open(); 98 extern void trace_command(); 99 extern void unassign(); 100 extern char *utos(); 101 extern char *valup(); 102 103 static int flagset(); 104 static char *cmd_name; 105 static int sig_number(); 106 static char *mycom[2]; 107 #ifdef JOBS 108 static void sig_list(); 109 #endif /* JOBS */ 110 111 void builtin(xbuiltin, argn, com,t) 112 int argn; 113 register char *com[]; 114 TREPTR t; 115 { 116 register char *a1 = com[1]; 117 register int flag = 0; 118 struct Amemory *troot; 119 int scoped = 0; 120 int aflag; 121 cmd_name = com[0]; 122 switch(xbuiltin) 123 { 124 case SYSEXEC: 125 com++; 126 ioset = 0; 127 if(a1==0) 128 break; 129 130 case SYSLOGIN: 131 132 if(is_option(RSHFLG)) 133 failed(cmd_name,restricted); 134 else 135 { 136 #ifdef JOBS 137 if(close_jobs() < 0) 138 { 139 exitval=1; 140 break; 141 } 142 #endif /* JOBS */ 143 /* force bad exec to terminate shell */ 144 states &= ~(TTYFLG|BUILTIN); 145 oldsigs(); 146 hist_close(); 147 rmtemp(0); 148 execa(com,(ARGPTR)NULL); 149 done(0); 150 } 151 152 case SYSTEST: /* test expression */ 153 exitval = testfn(argn, com); 154 break; 155 156 157 case SYSPWD: /* pwd routine */ 158 argn = 1; 159 if((*mycom = getpwd(1))==NULL) 160 failed(cmd_name,pwderr); 161 com = mycom-1; 162 163 case SYSECHO: /* system V echo routine */ 164 /* equivalent to print - */ 165 com--; 166 argn++; 167 #ifdef ECHO_N 168 /* This mess is because /bin/echo on BSD is archaic */ 169 a1 = echo_mode(); 170 #else 171 a1 = minus; 172 #endif /* ECHO_N */ 173 174 case SYSPRINT: /* print routine */ 175 { 176 register FILE *fd; 177 int raw = 0; 178 wdnum = 1; 179 while(a1 && *a1 == '-') 180 { 181 int c = *(a1+1); 182 /* handle the -R flag for BSD style echo */ 183 if(flag&R_JUST) 184 { 185 if(strcmp(a1,"-n")==0) 186 c = 0; 187 else 188 break; 189 } 190 flag |= flagset(a1,~(N_FLAG|R_FLAG|P_FLAG|U_FLAG|S_FLAG|R_JUST)); 191 com++; 192 argn--; 193 if(c==0) 194 break; 195 a1 = com[1]; 196 } 197 wdnum %= 10; 198 if(flag&(R_FLAG|R_JUST)) 199 raw = 1; 200 if(flag&S_FLAG) 201 { 202 /* print to history file */ 203 hist_open(); 204 if(fc_fix==NULL) 205 failed(cmd_name,nohistory); 206 fd = fc_fix->fixfd; 207 states |= FIXFLG; 208 goto skip; 209 } 210 else if(flag&P_FLAG) 211 { 212 if((fd=cpipe[OTPIPE])==NULL) 213 failed(cmd_name,noquery); 214 } 215 else if(flag&U_FLAG) 216 { 217 fd = file_fd(wdnum); 218 if(!fiswrite(fd)) 219 failed(cmd_name,badfile); 220 } 221 else 222 fd = standout; 223 224 clearerr(fd); 225 p_setout(fd); 226 skip: 227 if(echo_list(raw,com+1,fd) && (flag&N_FLAG)==0) 228 putc(NL,fd); 229 if(flag&S_FLAG) 230 hist_flush(); 231 break; 232 } 233 234 case SYSLET: 235 { 236 if(argn < 2) 237 failed(cmd_name,argcount); 238 while(--argn) 239 exitval = !aeval(*++com); 240 break; 241 } 242 243 /* 244 * The following few builtins are provided to set,print, 245 * and test attributes and variables for shell variables, 246 * aliases, and functions. 247 * In addition, typeset -f can be used to test whether a 248 * function has been defined or to list all defined functions 249 * Note readonly is same as typeset -r. 250 * Note export is same as typeset -x. 251 */ 252 case SYSRDONLY: 253 flag = R_FLAG; 254 aflag = '-'; 255 goto typset; 256 257 case SYSXPORT: 258 flag = X_FLAG; 259 aflag = '-'; 260 goto typset; 261 262 case SYSALIAS: 263 case SYSTYPESET: 264 { 265 FILE *fd; 266 int type; /* 0 for typeset, non-zero for alias */ 267 flag = 0; 268 aflag = (a1?*a1:0); 269 wdnum = 0; 270 if(aflag == '-' || aflag == '+') 271 { 272 flag = flagset(a1,~(L_JUST|R_JUST|Z_FILL|INT_GER|L_TO_U 273 |U_TO_L|X_FLAG|R_FLAG|F_FLAG|P_FLAG|T_FLAG 274 |A_FLAG)); 275 com++; 276 } 277 if((flag&INT_GER) && (flag&(L_JUST|R_JUST|Z_FILL))) 278 failed(cmd_name,badopt); 279 /* S_FLAG forces name to be in newest scope */ 280 if(fn_depth) 281 scoped = S_FLAG; 282 283 typset: 284 type = 0; 285 if(xbuiltin == SYSALIAS) 286 { 287 if(flag&~(N_EXPORT|T_FLAG)) 288 failed(cmd_name,badopt); 289 troot = alias; 290 /* setname treats this value specially */ 291 type = V_FLAG; 292 } 293 else if(flag&F_FLAG) 294 { 295 if(flag&~(N_EXPORT|F_FLAG|T_FLAG)) 296 failed(cmd_name,badopt); 297 troot = prnames; 298 flag &= ~F_FLAG; 299 } 300 else 301 troot = namep; 302 if(flag&P_FLAG) 303 { 304 flag &= ~P_FLAG; 305 if((fd=cpipe[OTPIPE])==NULL) 306 failed(cmd_name,noquery); 307 } 308 else 309 fd = standout; 310 p_setout(fd); 311 if(aflag == 0) 312 { 313 if(type) 314 prinscan(fd,0,troot,0); 315 else 316 gscan_all(printflg,troot); 317 break; 318 } 319 if(com[1]) 320 { 321 while(a1 = *++com) 322 { 323 register unsigned newflag; 324 register struct Namnod *np; 325 struct Namnod *setname(); 326 unsigned curflag; 327 if(troot == prnames) 328 { 329 /* 330 *functions can be exported or 331 * traced but not set 332 */ 333 if(np=checkfor(a1,prnames)) 334 { 335 if((flag&(N_EXPORT|T_FLAG))==0) 336 { 337 printnam(np,0); 338 continue; 339 } 340 if(aflag=='-') 341 attrib(np,flag); 342 else if(aflag=='+') 343 pattrib(np,~flag); 344 } 345 else 346 exitval++; 347 continue; 348 } 349 np = setname (a1,(type|scoped)); 350 /* tracked alias */ 351 if(type && (flag&T_FLAG) && aflag=='-') 352 { 353 attrib(np,flag|N_EXPORT); 354 realias(np); 355 continue; 356 } 357 if(flag==0 && aflag!='-' && strchr(a1,'=') == NULL) 358 { 359 /* type==0 for TYPESET */ 360 if(type==0) 361 { 362 if(valup(np)) 363 printflg(np); 364 else 365 exitval++; 366 continue; 367 } 368 if(printnam(np,0) == 0) 369 { 370 fputs(a1,fd); 371 p_str(noalias,NL); 372 exitval++; 373 } 374 continue; 375 } 376 curflag = namflag(np); 377 if (aflag == '-') 378 { 379 newflag = curflag | flag; 380 if (flag & INT_GER) 381 newflag &= ~(R_JUST|L_JUST); 382 else if (flag & (L_JUST|R_JUST)) 383 { 384 newflag &= ~INT_GER; 385 if (flag & L_JUST) 386 newflag &= ~R_JUST; 387 else 388 newflag &= ~L_JUST; 389 } 390 if (flag & U_TO_L) 391 newflag &= ~L_TO_U; 392 else if (flag & L_TO_U) 393 newflag &= ~U_TO_L; 394 } 395 else 396 newflag = curflag & ~flag; 397 if (aflag && (wdnum>0 || (curflag!=newflag))) 398 { 399 #ifdef apollo 400 /* keep aliases from going 401 into environment */ 402 if(type) 403 namflag(np) = newflag; 404 else 405 chattrib (np, newflag,wdnum); 406 #endif /* apollo */ 407 chattrib (np, newflag,wdnum); 408 } 409 } 410 } 411 else 412 prinscan(fd,flag,troot,aflag=='+'); 413 break; 414 } 415 416 417 /* 418 * The removing of Shell variable names, aliases, and functions 419 * is performed here. 420 * Unset functions with unset -f 421 * Non-existent items being deleted give non-zero exit status 422 */ 423 case SYSUNALIAS: 424 case SYSUNSET: 425 { 426 register NAMPTR np; 427 #ifdef apollo 428 short namlen; 429 #endif /* apollo */ 430 if(xbuiltin == SYSUNALIAS) 431 { 432 troot = alias; 433 goto unall; 434 } 435 if(a1 && *a1 == '-') 436 { 437 flag = flagset(a1,~F_FLAG); 438 com++; 439 argn--; 440 troot = prnames; 441 } 442 else 443 troot = namep; 444 unall: 445 if(argn < 2) 446 failed(cmd_name,argcount); 447 while(--argn) 448 { 449 a1 = *++com; 450 np=checkfor(a1,troot); 451 if(np) 452 { 453 if(troot==namep) 454 { 455 if(attest(np,ARRAY) && ( 456 (a1=strchr(a1,']'))==NIL 457 || astchar(a1[-1]))) 458 arayp(np)->adot = NO_SUBSCRIPT; 459 if (attest (np, N_RDONLY)) 460 failed(np->namid,wtfailed); 461 #ifdef apollo 462 namlen =strlen(np->namid); 463 ev_$delete_var(np->namid,&namlen); 464 #endif /* apollo */ 465 } 466 unassign(np); 467 } 468 else 469 exitval = 1; 470 } 471 break; 472 } 473 474 case SYSDOT: 475 if(a1) 476 { 477 register FILE *f; 478 if((f=pathopen(a1)) == NULL) 479 failed(a1,notfound); 480 else 481 { 482 if(argn > 2) 483 arg_set(com+1); 484 execexp((char*)0,f); 485 } 486 } 487 break; 488 489 case SYSTIMES: 490 { 491 long int t[4]; 492 times(t); 493 p_setout(standout); 494 p_time(t[0],' '); 495 p_time(t[1],NL); 496 p_time(t[2],' '); 497 p_time(t[3],NL); 498 break; 499 } 500 501 case SYSRETURN: /* return from a subroutine */ 502 if(freturn) 503 { 504 exitval = (a1?atoi(a1):oldexit); 505 longjmp(*freturn,1); 506 } 507 508 case SYSEXIT: 509 #ifdef JOBS 510 if(close_jobs()<0) 511 break; 512 #endif 513 states &= ~(TTYFLG|BUILTIN); /* force exit */ 514 exitsh(a1?atoi(a1):oldexit); 515 516 case SYSNULL: 517 break; 518 519 case SYSCONT: 520 if(loopcnt) 521 { 522 execbrk = breakcnt = 1; 523 if(a1) 524 breakcnt = atoi(a1); 525 if(breakcnt > loopcnt) 526 breakcnt = loopcnt; 527 else 528 breakcnt = -breakcnt; 529 } 530 break; 531 532 case SYSBREAK: 533 if(loopcnt) 534 { 535 execbrk = breakcnt = 1; 536 if(a1) 537 breakcnt = atoi(a1); 538 if(breakcnt > loopcnt) 539 breakcnt = loopcnt; 540 } 541 break; 542 543 case SYSTRAP: 544 if(a1) 545 { 546 register BOOL clear; 547 char *action = a1; 548 if((clear=isdigit(*a1))==0) 549 { 550 ++com; 551 if(*a1=='-') 552 clear++; 553 } 554 while(a1 = *++com) 555 { 556 flag = sig_number(a1); 557 if(flag>MAXTRAP || flag<MINTRAP) 558 failed(a1,badtrap); 559 else if(clear) 560 clrsig(flag); 561 else 562 { 563 free(trapcom[flag]); 564 trapcom[flag] = heap(action); 565 if(*action) 566 getsig(flag); 567 else 568 ignsig(flag); 569 } 570 } 571 } 572 else /* print out current traps */ 573 { 574 p_setout(standout); 575 for(flag=0; flag<=MAXTRAP; flag++) 576 if(trapcom[flag]) 577 { 578 p_num(flag,':'); 579 p_str(trapcom[flag],NL); 580 } 581 } 582 break; 583 584 case SYSCD: 585 { 586 register char *dp; 587 register char *cdpath = nullstr; 588 char newdir[256]; /* enough for any pathname */ 589 char *oldpwd; 590 if(is_option(RSHFLG)) 591 failed(cmd_name,restricted); 592 else if(argn >3) 593 failed(cmd_name, argcount); 594 if(argn==3) 595 a1 = substitute(getpwd(0),a1,com[2],newdir); 596 else if(a1==0 || *a1==0) 597 a1 = valup(HOME); 598 else if(*a1 == '-' && *(a1+1) == 0) 599 a1 = valup(OLDPWDNOD); 600 if(a1==0 || *a1==0) 601 failed(cmd_name,argn==3?badsub:baddir); 602 if(*a1 != '/') 603 cdpath = valup(CDPNOD); 604 if(cdpath==0) 605 cdpath = nullstr; 606 if(*a1=='.') 607 { 608 /* test for pathname . ./ .. or ../ */ 609 if(*(dp=a1+1) == '.') 610 dp++; 611 if(*dp==0 || *dp=='/') 612 cdpath = nullstr; 613 } 614 do 615 { 616 dp = cdpath; 617 cdpath=catpath(dp,a1); 618 } 619 while((flag=chdir(curstak()))<0 && cdpath); 620 if(flag<0) 621 failed(a1,baddir); 622 if(a1 == valup(OLDPWDNOD) || argn==3) 623 dp = a1; /* print out directory for cd - */ 624 a1 = (char*)fixstak(); 625 if(*dp && *dp!= ':' && (states&PROMPT) && strchr(a1,'/')) 626 { 627 p_setout(standout); 628 p_str(a1,NL); 629 } 630 oldpwd = getpwd(0); 631 fassign(OLDPWDNOD,oldpwd); 632 if(*a1 == '/') 633 strcpy(newdir,a1); 634 else 635 { 636 dp = movstr(oldpwd,newdir); 637 *dp++ = '/'; 638 movstr(a1,dp); 639 } 640 /* eliminate redundant / */ 641 a1 = newdir; 642 cannon_path(a1); 643 fassign(PWDNOD,a1); 644 #ifndef INT16 645 /* Because of possible symbolic links, make sure we are where 646 * we think we are. 647 */ 648 if(!eq_inode(dot,a1)) 649 chdir(a1); 650 #endif /* INT16 */ 651 break; 652 } 653 654 case SYSSHFT: 655 { 656 flag = (a1?aeval(a1):1); 657 if(flag<0 || dolc<flag) 658 failed(cmd_name,badnum); 659 else 660 { 661 dolv += flag; 662 dolc -= flag; 663 } 664 break; 665 } 666 667 case SYSWAIT: 668 await(a1?atoi(a1):-1,1); 669 break; 670 671 case SYSREAD: 672 { 673 register FILE *fd; 674 wdnum = 0; 675 while(a1 && *a1 == '-') 676 { 677 flag |= flagset(a1,~(R_FLAG|P_FLAG|U_FLAG|S_FLAG)); 678 com++; 679 argn--; 680 if(*(a1+1)==0) 681 break; 682 a1 = com[1]; 683 } 684 if(flag&P_FLAG) 685 { 686 fd = cpipe[INPIPE]; 687 states |= PROMPT; 688 } 689 else if(flag&U_FLAG) 690 fd = file_fd(wdnum); 691 else 692 fd = stdin; 693 if(!fisread(fd)) 694 failed(cmd_name,badfile); 695 if(isatty(fileno(fd))) 696 { 697 FILE *fdo; 698 p_setout(output); 699 states |= PROMPT; 700 /* look for prompt */ 701 if(a1=strchr(a1,'?')) 702 { 703 if(fiswrite(fd)==0 || 704 (fdo=fdopen(dup(fileno(fd)),"w"))==NULL) 705 fdo = stderr; 706 p_setout(fdo); 707 fputs(a1+1,fdo); 708 if(fdo!=stderr) 709 fclose(fdo); 710 } 711 } 712 readvar(&com[1],fd,flag&(R_FLAG|S_FLAG)); 713 if(feof(fd)) 714 { 715 exitval=1; 716 if(flag&P_FLAG) 717 { 718 pipe_close(cpipe); 719 cpipe[INPIPE]=0; 720 cpid = 0; 721 } 722 } 723 clearerr(fd); 724 break; 725 } 726 727 case SYSSET: 728 flag = is_option(EXECPR); 729 if(a1) 730 { 731 register int argc; 732 argc = arg_opts(argn,com); 733 /* RWAIT is set if -- flag is given */ 734 if(argc>1 || (states&RWAIT)) 735 arg_set(com+argn-argc); 736 states &= ~(RWAIT|READPR|MONITOR); 737 states |= is_option(READPR|MONITOR); 738 } 739 if(flag) 740 trace_command(com); 741 if(a1==0 && ((COMPTR) t)->comset==0) 742 /*scan name chain and print*/ 743 prinscan(standout,0,namep,0); 744 break; 745 746 case SYSEVAL: 747 if(a1) 748 execexp(a1,(FILE*)&com[2]); 749 break; 750 751 case SYSFC: 752 { 753 register struct fixcmd *fp; 754 FILE *fdo; 755 char *argv[2]; 756 char fname[TMPSIZ]; 757 int index2; 758 int indx = -1; /* used as subscript for range */ 759 char *edit = NULL; /* name of editor */ 760 char *replace = NULL; /* replace old=new */ 761 int incr; 762 int range[2]; /* upper and lower range of commands */ 763 int lflag = 0; 764 int nflag = 0; 765 int rflag = 0; 766 histloc location; 767 wdnum = 0; 768 hist_open(); 769 if((fp=fc_fix)==NULL) 770 failed(cmd_name,nohistory); 771 while((a1=com[1]) && *a1 == '-') 772 { 773 flag = flagset(a1,~(E_FLAG|L_FLAG|N_FLAG|R_FLAG)); 774 if(flag==0) 775 { 776 range[++indx] = fp->fixind - wdnum-1; 777 wdnum = 0; 778 if(indx==1) 779 break; 780 } 781 else 782 { 783 if(flag&E_FLAG) 784 { 785 /* name of editor specified */ 786 com++; 787 if((edit=com[1]) == NULL) 788 failed(cmd_name,argexp); 789 } 790 if(flag&N_FLAG) 791 nflag++; 792 if(flag&L_FLAG) 793 lflag++; 794 if(flag&R_FLAG) 795 rflag++; 796 } 797 com++; 798 } 799 flag = indx; 800 while(flag<1 && (a1=com[1])) 801 { 802 if(isdigit(*a1) || *a1 == '-') 803 { 804 /* see if completely numeric */ 805 do a1++; 806 while(isdigit(*a1)); 807 if(*a1==0) 808 { 809 a1 = com[1]; 810 range[++flag] = atoi(a1); 811 if(*a1 == '-') 812 range[flag] += (fp->fixind-1); 813 com++; 814 continue; 815 } 816 } 817 /* look for old=new argument */ 818 else if(replace==NULL && strchr(a1+1,'=')) 819 { 820 replace = a1; 821 com++; 822 continue; 823 } 824 /* search for last line starting with string */ 825 location = hist_find(com[1],fp->fixind-1,0,-1); 826 if((range[++flag] = location.his_command) < 0) 827 failed(com[1],notfound); 828 com++; 829 } 830 if(flag <0) 831 { 832 /* set default starting range */ 833 if(lflag) 834 { 835 flag = fp->fixind-16; 836 if(flag<1) 837 flag = 1; 838 } 839 else 840 flag = fp->fixind-2; 841 range[0] = flag; 842 flag = 0; 843 } 844 if(flag==0) 845 /* set default termination range */ 846 range[1] = (lflag?fp->fixind-1:range[0]); 847 if((index2 = fp->fixind - fp->fixmax) <=0) 848 index2 = 1; 849 /* check for valid ranges */ 850 for(flag=0;flag<2;flag++) 851 if(range[flag]<index2 || 852 range[flag]>=(fp->fixind-(lflag==0))) 853 failed(cmd_name,badnum); 854 if(edit && *edit=='-' && range[0]!=range[1]) 855 failed(cmd_name,badnum); 856 /* now list commands from range[rflag] to range[1-rflag] */ 857 incr = 1; 858 flag = rflag>0; 859 if(range[1-flag] < range[flag]) 860 incr = -1; 861 if(lflag) 862 { 863 fdo = standout; 864 a1 = "\n\t"; 865 } 866 else 867 { 868 fdo = tmp_open(fname); 869 a1 = "\n"; 870 nflag++; 871 } 872 p_setout(fdo); 873 while(1) 874 { 875 if(nflag==0) 876 p_num(range[flag],'\t'); 877 else if(lflag) 878 putc('\t',fdo); 879 hist_list(hist_position(range[flag]),EOF,a1); 880 if(lflag && (trapnote&SIGSET)) 881 exitsh(SIGFAIL); 882 if(range[flag] == range[1-flag]) 883 break; 884 range[flag] += incr; 885 } 886 fseek(fp->fixfd,0L,2); 887 if(lflag) 888 return; 889 p_setout(stderr); 890 a1 = edit; 891 if(a1==NULL && (a1=valup(FCEDNOD)) == NULL) 892 a1 = defedit; 893 if(*a1 != '-') 894 { 895 argv[0] = fname; 896 argv[1] = NULL; 897 execexp(a1,(FILE*)argv); 898 } 899 closefd(fdo); 900 fdo = chkopen(fname); 901 unlink(fname); 902 /* don't history fc itself */ 903 hist_cancel(); 904 states |= (READPR|FIXFLG); /* echo lines as read */ 905 if(replace!=NULL) 906 hist_subst(cmd_name,fdo,replace); 907 else if(exitval == 0) 908 execexp((char*)0,fdo); 909 else 910 { 911 fclose(fdo); 912 if(is_option(READPR)==0) 913 states &= ~(READPR|FIXFLG); 914 } 915 break; 916 } 917 918 case SYSWHENCE: 919 { 920 if(a1 && *a1 == '-') 921 { 922 flag = flagset(a1,~V_FLAG); 923 com++; 924 argn--; 925 } 926 if(argn < 2) 927 failed(cmd_name,argcount); 928 p_setout(standout); 929 do_whence(com,flag); 930 break; 931 } 932 933 934 case SYSUMASK: 935 { 936 if(a1) 937 { 938 register int c; 939 flag = 0; 940 while(c = *a1++) 941 { 942 if (c>='0' && c<='7') 943 flag = (flag<<3) + (c-'0'); 944 else 945 failed(cmd_name,badnum); 946 } 947 umask(flag); 948 } 949 else 950 { 951 p_setout(standout); 952 #ifdef pdp11 953 a1 = utos((long)(argn=umask(0)),8); 954 #else 955 a1 = utos((unsigned long)(argn=umask(0)),8); 956 #endif /* pdp11 */ 957 umask(argn); 958 *++a1 = '0'; 959 p_str(a1,NL); 960 } 961 break; 962 } 963 964 #ifndef apollo 965 966 #ifdef BSD 967 #define BLK_SIZ 512 968 #define KBYTE 1024 969 #ifdef BSD_4_2 970 #else 971 #include <sys/vlimit.h> 972 #endif 973 case SYSULIMIT: 974 { 975 #ifdef BSD_4_2 976 struct rlimit rlp; 977 #endif 978 long i; 979 char *opts = 0; 980 char label=0; 981 int n; 982 int unit = BLK_SIZ; 983 flag = LIM_FSIZE; 984 if(a1 && *a1 == '-') 985 opts = ++a1; 986 do 987 { 988 if(opts) 989 { 990 switch(*opts) 991 { 992 case 'a': 993 label++; 994 opts = "tmdsfc"; 995 case 't': 996 flag = LIM_CPU; 997 unit = 1; 998 n = 0; 999 break; 1000 case 'c': 1001 flag = LIM_CORE; 1002 n = 5; 1003 break; 1004 case 'f': 1005 flag = LIM_FSIZE; 1006 n = 4; 1007 break; 1008 case 'd': 1009 flag = LIM_DATA; 1010 unit = KBYTE; 1011 n = 2; 1012 break; 1013 case 's': 1014 flag = LIM_STACK; 1015 unit = KBYTE; 1016 n = 3; 1017 break; 1018 case 'm': 1019 flag = LIM_MAXRSS; 1020 unit = KBYTE; 1021 n = 1; 1022 break; 1023 default: 1024 failed(cmd_name,badopt); 1025 } 1026 if((a1 && *++a1)||(label&&com[2])) 1027 failed(cmd_name,badopt); 1028 a1 = com[2]; 1029 } 1030 if(a1) 1031 { 1032 if((i=aeval(a1)) < 0) 1033 failed(cmd_name,badnum); 1034 i *= unit; 1035 #ifdef BSD_4_2 1036 if(getrlimit(flag,&rlp) <0) 1037 failed(cmd_name,badnum); 1038 rlp.rlim_cur = i; 1039 if(setrlimit(flag,&rlp) <0) 1040 failed(cmd_name,badnum); 1041 #endif 1042 } 1043 else 1044 { 1045 #ifdef BSD_4_2 1046 if(getrlimit(flag,&rlp) <0) 1047 failed(cmd_name,badnum); 1048 i = rlp.rlim_cur; 1049 #else 1050 i = -1; 1051 } 1052 if((i=vlimit(flag,i)) < 0) 1053 failed(cmd_name,badnum); 1054 if(a1==0) 1055 { 1056 #endif 1057 p_setout(standout); 1058 if(label) 1059 p_str(limit_names[n],SP); 1060 if(i!=INFINITY) 1061 { 1062 i = (i+unit-1)/unit; 1063 p_str(utos((unsigned long)i,10),NL); 1064 } 1065 else 1066 p_str(unlimited,NL); 1067 } 1068 } 1069 while(opts && *++opts); 1070 break; 1071 } 1072 #else 1073 case SYSULIMIT: 1074 { 1075 #ifndef VENIX 1076 long i; 1077 long ulimit(); 1078 register int mode = 2; 1079 if(a1 && *a1 == '-') 1080 { 1081 #ifdef RT 1082 flag = flagset(a1,~(F_FLAG|P_FLAG)); 1083 #else 1084 flag = flagset(a1,~F_FLAG); 1085 #endif /* RT */ 1086 a1 = com[2]; 1087 } 1088 if(flag&P_FLAG) 1089 mode = 5; 1090 if(a1) 1091 { 1092 if((i=aeval(a1)) < 0) 1093 failed(cmd_name,badnum); 1094 } 1095 else 1096 { 1097 mode--; 1098 i = -1; 1099 } 1100 if((i=ulimit(mode,i)) < 0) 1101 failed(cmd_name,badnum); 1102 if(a1==0) 1103 { 1104 p_setout(standout); 1105 # ifdef pdp11 1106 p_str(utos((long)i,10),NL); 1107 # else 1108 p_str(utos((unsigned long)i,10),NL); 1109 # endif /* pdp11 */ 1110 } 1111 #endif /* VENIX */ 1112 break; 1113 } 1114 #endif 1115 #endif /* apollo */ 1116 1117 #ifdef JOBS 1118 # if BSD || SXT 1119 case SYSBG: 1120 flag = 1; 1121 case SYSFG: 1122 if((states&MONITOR)==0) 1123 { 1124 exitval = 1; 1125 if(states&PROMPT) 1126 failed(cmd_name,j_no_jctl); 1127 break; 1128 } 1129 if(argn==1) 1130 a1 = nullstr; 1131 if(switch_jobs(a1,flag)==0) 1132 failed(cmd_name,j_no_job); 1133 break; 1134 # endif 1135 1136 case SYSJOBS: 1137 if(a1 && *a1 == '-') 1138 flag = flagset(a1,~L_FLAG); 1139 list_jobs(flag); 1140 break; 1141 1142 case SYSKILL: 1143 { 1144 if(argn < 2) 1145 failed(cmd_name,argcount); 1146 /* just in case we send a kill -9 $$ */ 1147 p_flush(); 1148 flag = 15; 1149 if(*a1 == '-') 1150 { 1151 a1++; 1152 if(*a1 == 'l') 1153 { 1154 sig_list(); 1155 break; 1156 } 1157 flag = sig_number(a1); 1158 if(flag <0 || flag >= NSIG) 1159 failed(cmd_name,badopt); 1160 com++; 1161 argn--; 1162 } 1163 while(--argn) 1164 { 1165 a1 = *++com; 1166 exitval += job_kill(a1,flag); 1167 } 1168 break; 1169 } 1170 #endif 1171 1172 #ifdef apollo 1173 /* 1174 * Apollo system support library loads into the virtual address space 1175 */ 1176 case SYSINLIB: 1177 { 1178 int status,xfer; 1179 short len; 1180 std_$call void pm_$load(); 1181 std_$call void pm_$call(); 1182 if(a1) 1183 { 1184 len = strlen(a1); 1185 pm_$load(*a1, len, 2 , 0, xfer,status); 1186 if(status!=0) 1187 failed(a1,"cannot inlib"); 1188 else if(xfer) 1189 pm_$call(xfer); 1190 } 1191 break; 1192 } 1193 1194 case SYSINPROCESS: 1195 if(argn < 2) 1196 on_option(INPROC); 1197 else 1198 exitval = exec_here(com); 1199 break; 1200 #endif /* apollo */ 1201 } 1202 } 1203 1204 static const char flgchar[] = "efilmnprstuvwxzHLRZ"; 1205 static const int flgval[] = {E_FLAG,F_FLAG,I_FLAG,L_FLAG,M_FLAG, 1206 N_FLAG,P_FLAG,R_FLAG,S_FLAG,T_FLAG,U_FLAG,V_FLAG, 1207 W_FLAG,X_FLAG,Z_FLAG,A_FLAG,L_JUST,R_JUST,R_JUST|Z_FILL}; 1208 /* 1209 * process option flags for built-ins 1210 * flagmask are the invalid options 1211 */ 1212 1213 static int flagset(flaglist,flagmask) 1214 char *flaglist; 1215 { 1216 register int flag = 0; 1217 register int c; 1218 register char *cp,*sp; 1219 1220 for(cp=flaglist+1;c = *cp;cp++) 1221 { 1222 if(isdigit(c)) 1223 wdnum = 10*wdnum + (c - '0'); 1224 else if(sp=strchr(flgchar,c)) 1225 flag |= flgval[sp-flgchar]; 1226 else 1227 goto badoption; 1228 } 1229 if((flag&flagmask)==0) 1230 return(flag); 1231 badoption: 1232 failed(cmd_name,badopt); 1233 /* NOTREACHED */ 1234 } 1235 1236 1237 int execexp(s,f) 1238 register char *s; 1239 register FILE *f; 1240 { 1241 FILEBLK fb; 1242 FILE fd; 1243 TREPTR t; 1244 char inbuf[BUFSIZ]; 1245 push(&fb); 1246 if(s) 1247 { 1248 estabf(s,&fd); 1249 fb.feval=(char **)(f); 1250 } 1251 else if(f!=NULL) 1252 { 1253 initf(f); 1254 setbuf(f,inbuf); 1255 } 1256 exec_flag++; 1257 t = cmd(NL,NLFLG|MTFLG); 1258 exec_flag--; 1259 if(is_option(READPR)==0) 1260 states &= ~READPR; 1261 if(s==NULL && fc_fix) 1262 hist_flush(); 1263 pop(0); 1264 execute(t,states&ERRFLG); 1265 } 1266 1267 1268 /* 1269 * Given the name or number of a signal return the signal number 1270 */ 1271 1272 static int sig_number(string) 1273 register char *string; 1274 { 1275 register int n; 1276 if(isdigit(*string)) 1277 n = atoi(string); 1278 else 1279 { 1280 n = syslook(string,signal_names); 1281 n &= (1<<SIGBITS)-1; 1282 n--; 1283 } 1284 return(n); 1285 } 1286 1287 #ifdef JOBS 1288 /* 1289 * list all the possible signals 1290 */ 1291 static void sig_list() 1292 { 1293 register SYSPTR syscan; 1294 register int n = MAXTRAP+1; 1295 char *names[MAXTRAP+1]; 1296 syscan=signal_names; 1297 p_setout(standout); 1298 /* not all signals may be defined */ 1299 while(--n >= 0) 1300 names[n] = badtrap; 1301 while(*syscan->sysnam) 1302 { 1303 n = syscan->sysval; 1304 n &= ((1<<SIGBITS)-1); 1305 names[n] = syscan->sysnam; 1306 syscan++; 1307 } 1308 n = MAXTRAP; 1309 while(names[--n]==badtrap); 1310 names[n+1] = NULL; 1311 p_list(n-1,names+2); 1312 } 1313 #endif /* JOBS */ 1314