├── LICENSE ├── README.md └── sh.c /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions 5 | are met: 6 | 1. Redistributions of source code and documentation must retain the above 7 | copyright notice, this list of conditions and the following disclaimer. 8 | 2. Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | 3. All advertising materials mentioning features or use of this software 12 | must display the following acknowledgement: 13 | This product includes software developed or owned by Caldera 14 | International, Inc. 15 | 4. Neither the name of Caldera International, Inc. nor the names of other 16 | contributors may be used to endorse or promote products derived from 17 | this software without specific prior written permission. 18 | 19 | USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 20 | INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 21 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 | IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 24 | INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 25 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 | STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 | POSSIBILITY OF SUCH DAMAGE. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #sh.c 2 | ####Original source code for the Sixth Edition (V6) UNIX Thompson shell 3 | From: Sixth Edition (V6) UNIX /usr/source/s2/sh.c 4 | -------------------------------------------------------------------------------- /sh.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sh.c - original source code for the Sixth Edition (V6) UNIX Thompson shell 3 | * 4 | * From: Sixth Edition (V6) UNIX /usr/source/s2/sh.c 5 | * 6 | * NOTE: The first 43 lines of this file have been added by 7 | * Jeffrey Allen Neitzel 8 | * in order to comply with the license. The file is 9 | * otherwise unmodified. 10 | */ 11 | /*- 12 | * Copyright (C) Caldera International Inc. 2001-2002. All rights reserved. 13 | * 14 | * Redistribution and use in source and binary forms, with or without 15 | * modification, are permitted provided that the following conditions 16 | * are met: 17 | * 1. Redistributions of source code and documentation must retain the above 18 | * copyright notice, this list of conditions and the following disclaimer. 19 | * 2. Redistributions in binary form must reproduce the above copyright 20 | * notice, this list of conditions and the following disclaimer in the 21 | * documentation and/or other materials provided with the distribution. 22 | * 3. All advertising materials mentioning features or use of this software 23 | * must display the following acknowledgement: 24 | * This product includes software developed or owned by Caldera 25 | * International, Inc. 26 | * 4. Neither the name of Caldera International, Inc. nor the names of other 27 | * contributors may be used to endorse or promote products derived from 28 | * this software without specific prior written permission. 29 | * 30 | * USE OF THE SOFTWARE PROVIDED FOR UNDER THIS LICENSE BY CALDERA 31 | * INTERNATIONAL, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR 32 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 33 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 34 | * IN NO EVENT SHALL CALDERA INTERNATIONAL, INC. BE LIABLE FOR ANY DIRECT, 35 | * INDIRECT INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 36 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 37 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 | * POSSIBILITY OF SUCH DAMAGE. 42 | */ 43 | 44 | # 45 | /* 46 | */ 47 | 48 | #define INTR 2 49 | #define QUIT 3 50 | #define LINSIZ 1000 51 | #define ARGSIZ 50 52 | #define TRESIZ 100 53 | 54 | #define QUOTE 0200 55 | #define FAND 1 56 | #define FCAT 2 57 | #define FPIN 4 58 | #define FPOU 8 59 | #define FPAR 16 60 | #define FINT 32 61 | #define FPRS 64 62 | #define TCOM 1 63 | #define TPAR 2 64 | #define TFIL 3 65 | #define TLST 4 66 | #define DTYP 0 67 | #define DLEF 1 68 | #define DRIT 2 69 | #define DFLG 3 70 | #define DSPR 4 71 | #define DCOM 5 72 | #define ENOMEM 12 73 | #define ENOEXEC 8 74 | 75 | char *dolp; 76 | char pidp[6]; 77 | int ldivr; 78 | char **dolv; 79 | int dolc; 80 | char *promp; 81 | char *linep; 82 | char *elinep; 83 | char **argp; 84 | char **eargp; 85 | int *treep; 86 | int *treeend; 87 | char peekc; 88 | char gflg; 89 | char error; 90 | char acctf; 91 | char uid; 92 | char setintr; 93 | char *arginp; 94 | int onelflg; 95 | 96 | char *mesg[] { 97 | 0, 98 | "Hangup", 99 | 0, 100 | "Quit", 101 | "Illegal instruction", 102 | "Trace/BPT trap", 103 | "IOT trap", 104 | "EMT trap", 105 | "Floating exception", 106 | "Killed", 107 | "Bus error", 108 | "Memory fault", 109 | "Bad system call", 110 | 0, 111 | "Sig 14", 112 | "Sig 15", 113 | "Sig 16", 114 | "Sig 17", 115 | "Sig 18", 116 | "Sig 19", 117 | }; 118 | 119 | struct stime { 120 | int proct[2]; 121 | int cputim[2]; 122 | int systim[2]; 123 | } timeb; 124 | 125 | char line[LINSIZ]; 126 | char *args[ARGSIZ]; 127 | int trebuf[TRESIZ]; 128 | 129 | main(c, av) 130 | int c; 131 | char **av; 132 | { 133 | register f; 134 | register char *acname, **v; 135 | 136 | for(f=2; f<15; f++) 137 | close(f); 138 | if((f=dup(1)) != 2) 139 | close(f); 140 | dolc = getpid(); 141 | for(f=4; f>=0; f--) { 142 | dolc = ldiv(0, dolc, 10); 143 | pidp[f] = ldivr+'0'; 144 | } 145 | v = av; 146 | acname = "/usr/adm/sha"; 147 | promp = "% "; 148 | if(((uid = getuid())&0377) == 0) 149 | promp = "# "; 150 | acctf = open(acname, 1); 151 | if(c > 1) { 152 | promp = 0; 153 | if (*v[1]=='-') { 154 | **v = '-'; 155 | if (v[1][1]=='c' && c>2) 156 | arginp = v[2]; 157 | else if (v[1][1]=='t') 158 | onelflg = 2; 159 | } else { 160 | close(0); 161 | f = open(v[1], 0); 162 | if(f < 0) { 163 | prs(v[1]); 164 | err(": cannot open"); 165 | } 166 | } 167 | } 168 | if(**v == '-') { 169 | setintr++; 170 | signal(QUIT, 1); 171 | signal(INTR, 1); 172 | } 173 | dolv = v+1; 174 | dolc = c-1; 175 | 176 | loop: 177 | if(promp != 0) 178 | prs(promp); 179 | peekc = getc(); 180 | main1(); 181 | goto loop; 182 | } 183 | 184 | main1() 185 | { 186 | register char c, *cp; 187 | register *t; 188 | 189 | argp = args; 190 | eargp = args+ARGSIZ-5; 191 | linep = line; 192 | elinep = line+LINSIZ-5; 193 | error = 0; 194 | gflg = 0; 195 | do { 196 | cp = linep; 197 | word(); 198 | } while(*cp != '\n'); 199 | treep = trebuf; 200 | treeend = &trebuf[TRESIZ]; 201 | if(gflg == 0) { 202 | if(error == 0) { 203 | setexit(); 204 | if (error) 205 | return; 206 | t = syntax(args, argp); 207 | } 208 | if(error != 0) 209 | err("syntax error"); else 210 | execute(t); 211 | } 212 | } 213 | 214 | word() 215 | { 216 | register char c, c1; 217 | 218 | *argp++ = linep; 219 | 220 | loop: 221 | switch(c = getc()) { 222 | 223 | case ' ': 224 | case '\t': 225 | goto loop; 226 | 227 | case '\'': 228 | case '"': 229 | c1 = c; 230 | while((c=readc()) != c1) { 231 | if(c == '\n') { 232 | error++; 233 | peekc = c; 234 | return; 235 | } 236 | *linep++ = c|QUOTE; 237 | } 238 | goto pack; 239 | 240 | case '&': 241 | case ';': 242 | case '<': 243 | case '>': 244 | case '(': 245 | case ')': 246 | case '|': 247 | case '^': 248 | case '\n': 249 | *linep++ = c; 250 | *linep++ = '\0'; 251 | return; 252 | } 253 | 254 | peekc = c; 255 | 256 | pack: 257 | for(;;) { 258 | c = getc(); 259 | if(any(c, " '\"\t;&<>()|^\n")) { 260 | peekc = c; 261 | if(any(c, "\"'")) 262 | goto loop; 263 | *linep++ = '\0'; 264 | return; 265 | } 266 | *linep++ = c; 267 | } 268 | } 269 | 270 | tree(n) 271 | int n; 272 | { 273 | register *t; 274 | 275 | t = treep; 276 | treep =+ n; 277 | if (treep>treeend) { 278 | prs("Command line overflow\n"); 279 | error++; 280 | reset(); 281 | } 282 | return(t); 283 | } 284 | 285 | getc() 286 | { 287 | register char c; 288 | 289 | if(peekc) { 290 | c = peekc; 291 | peekc = 0; 292 | return(c); 293 | } 294 | if(argp > eargp) { 295 | argp =- 10; 296 | while((c=getc()) != '\n'); 297 | argp =+ 10; 298 | err("Too many args"); 299 | gflg++; 300 | return(c); 301 | } 302 | if(linep > elinep) { 303 | linep =- 10; 304 | while((c=getc()) != '\n'); 305 | linep =+ 10; 306 | err("Too many characters"); 307 | gflg++; 308 | return(c); 309 | } 310 | getd: 311 | if(dolp) { 312 | c = *dolp++; 313 | if(c != '\0') 314 | return(c); 315 | dolp = 0; 316 | } 317 | c = readc(); 318 | if(c == '\\') { 319 | c = readc(); 320 | if(c == '\n') 321 | return(' '); 322 | return(c|QUOTE); 323 | } 324 | if(c == '$') { 325 | c = readc(); 326 | if(c>='0' && c<='9') { 327 | if(c-'0' < dolc) 328 | dolp = dolv[c-'0']; 329 | goto getd; 330 | } 331 | if(c == '$') { 332 | dolp = pidp; 333 | goto getd; 334 | } 335 | } 336 | return(c&0177); 337 | } 338 | 339 | readc() 340 | { 341 | char cc; 342 | register c; 343 | 344 | if (arginp) { 345 | if (arginp == 1) 346 | exit(); 347 | if ((c = *arginp++) == 0) { 348 | arginp = 1; 349 | c = '\n'; 350 | } 351 | return(c); 352 | } 353 | if (onelflg==1) 354 | exit(); 355 | if(read(0, &cc, 1) != 1) 356 | exit(); 357 | if (cc=='\n' && onelflg) 358 | onelflg--; 359 | return(cc); 360 | } 361 | 362 | /* 363 | * syntax 364 | * empty 365 | * syn1 366 | */ 367 | 368 | syntax(p1, p2) 369 | char **p1, **p2; 370 | { 371 | 372 | while(p1 != p2) { 373 | if(any(**p1, ";&\n")) 374 | p1++; else 375 | return(syn1(p1, p2)); 376 | } 377 | return(0); 378 | } 379 | 380 | /* 381 | * syn1 382 | * syn2 383 | * syn2 & syntax 384 | * syn2 ; syntax 385 | */ 386 | 387 | syn1(p1, p2) 388 | char **p1, **p2; 389 | { 390 | register char **p; 391 | register *t, *t1; 392 | int l; 393 | 394 | l = 0; 395 | for(p=p1; p!=p2; p++) 396 | switch(**p) { 397 | 398 | case '(': 399 | l++; 400 | continue; 401 | 402 | case ')': 403 | l--; 404 | if(l < 0) 405 | error++; 406 | continue; 407 | 408 | case '&': 409 | case ';': 410 | case '\n': 411 | if(l == 0) { 412 | l = **p; 413 | t = tree(4); 414 | t[DTYP] = TLST; 415 | t[DLEF] = syn2(p1, p); 416 | t[DFLG] = 0; 417 | if(l == '&') { 418 | t1 = t[DLEF]; 419 | t1[DFLG] =| FAND|FPRS|FINT; 420 | } 421 | t[DRIT] = syntax(p+1, p2); 422 | return(t); 423 | } 424 | } 425 | if(l == 0) 426 | return(syn2(p1, p2)); 427 | error++; 428 | } 429 | 430 | /* 431 | * syn2 432 | * syn3 433 | * syn3 | syn2 434 | */ 435 | 436 | syn2(p1, p2) 437 | char **p1, **p2; 438 | { 439 | register char **p; 440 | register int l, *t; 441 | 442 | l = 0; 443 | for(p=p1; p!=p2; p++) 444 | switch(**p) { 445 | 446 | case '(': 447 | l++; 448 | continue; 449 | 450 | case ')': 451 | l--; 452 | continue; 453 | 454 | case '|': 455 | case '^': 456 | if(l == 0) { 457 | t = tree(4); 458 | t[DTYP] = TFIL; 459 | t[DLEF] = syn3(p1, p); 460 | t[DRIT] = syn2(p+1, p2); 461 | t[DFLG] = 0; 462 | return(t); 463 | } 464 | } 465 | return(syn3(p1, p2)); 466 | } 467 | 468 | /* 469 | * syn3 470 | * ( syn1 ) [ < in ] [ > out ] 471 | * word word* [ < in ] [ > out ] 472 | */ 473 | 474 | syn3(p1, p2) 475 | char **p1, **p2; 476 | { 477 | register char **p; 478 | char **lp, **rp; 479 | register *t; 480 | int n, l, i, o, c, flg; 481 | 482 | flg = 0; 483 | if(**p2 == ')') 484 | flg =| FPAR; 485 | lp = 0; 486 | rp = 0; 487 | i = 0; 488 | o = 0; 489 | n = 0; 490 | l = 0; 491 | for(p=p1; p!=p2; p++) 492 | switch(c = **p) { 493 | 494 | case '(': 495 | if(l == 0) { 496 | if(lp != 0) 497 | error++; 498 | lp = p+1; 499 | } 500 | l++; 501 | continue; 502 | 503 | case ')': 504 | l--; 505 | if(l == 0) 506 | rp = p; 507 | continue; 508 | 509 | case '>': 510 | p++; 511 | if(p!=p2 && **p=='>') 512 | flg =| FCAT; else 513 | p--; 514 | 515 | case '<': 516 | if(l == 0) { 517 | p++; 518 | if(p == p2) { 519 | error++; 520 | p--; 521 | } 522 | if(any(**p, "<>(")) 523 | error++; 524 | if(c == '<') { 525 | if(i != 0) 526 | error++; 527 | i = *p; 528 | continue; 529 | } 530 | if(o != 0) 531 | error++; 532 | o = *p; 533 | } 534 | continue; 535 | 536 | default: 537 | if(l == 0) 538 | p1[n++] = *p; 539 | } 540 | if(lp != 0) { 541 | if(n != 0) 542 | error++; 543 | t = tree(5); 544 | t[DTYP] = TPAR; 545 | t[DSPR] = syn1(lp, rp); 546 | goto out; 547 | } 548 | if(n == 0) 549 | error++; 550 | p1[n++] = 0; 551 | t = tree(n+5); 552 | t[DTYP] = TCOM; 553 | for(l=0; l= 0) { 682 | seek(i, 0, 2); 683 | goto f1; 684 | } 685 | } 686 | i = creat(t[DRIT], 0666); 687 | if(i < 0) { 688 | prs(t[DRIT]); 689 | err(": cannot create"); 690 | exit(); 691 | } 692 | f1: 693 | close(1); 694 | dup(i); 695 | close(i); 696 | } 697 | if((f&FPIN) != 0) { 698 | close(0); 699 | dup(pf1[0]); 700 | close(pf1[0]); 701 | close(pf1[1]); 702 | } 703 | if((f&FPOU) != 0) { 704 | close(1); 705 | dup(pf2[1]); 706 | close(pf2[0]); 707 | close(pf2[1]); 708 | } 709 | if((f&FINT)!=0 && t[DLEF]==0 && (f&FPIN)==0) { 710 | close(0); 711 | open("/dev/null", 0); 712 | } 713 | if((f&FINT) == 0 && setintr) { 714 | signal(INTR, 0); 715 | signal(QUIT, 0); 716 | } 717 | if(t[DTYP] == TPAR) { 718 | if(t1 = t[DSPR]) 719 | t1[DFLG] =| f&FINT; 720 | execute(t1); 721 | exit(); 722 | } 723 | close(acctf); 724 | gflg = 0; 725 | scan(t, &tglob); 726 | if(gflg) { 727 | t[DSPR] = "/etc/glob"; 728 | execv(t[DSPR], t+DSPR); 729 | prs("glob: cannot execute\n"); 730 | exit(); 731 | } 732 | scan(t, &trim); 733 | *linep = 0; 734 | texec(t[DCOM], t); 735 | cp1 = linep; 736 | cp2 = "/usr/bin/"; 737 | while(*cp1 = *cp2++) 738 | cp1++; 739 | cp2 = t[DCOM]; 740 | while(*cp1++ = *cp2++); 741 | texec(linep+4, t); 742 | texec(linep, t); 743 | prs(t[DCOM]); 744 | err(": not found"); 745 | exit(); 746 | 747 | case TFIL: 748 | f = t[DFLG]; 749 | pipe(pv); 750 | t1 = t[DLEF]; 751 | t1[DFLG] =| FPOU | (f&(FPIN|FINT|FPRS)); 752 | execute(t1, pf1, pv); 753 | t1 = t[DRIT]; 754 | t1[DFLG] =| FPIN | (f&(FPOU|FINT|FAND|FPRS)); 755 | execute(t1, pv, pf2); 756 | return; 757 | 758 | case TLST: 759 | f = t[DFLG]&FINT; 760 | if(t1 = t[DLEF]) 761 | t1[DFLG] =| f; 762 | execute(t1); 763 | if(t1 = t[DRIT]) 764 | t1[DFLG] =| f; 765 | execute(t1); 766 | return; 767 | 768 | } 769 | } 770 | 771 | texec(f, at) 772 | int *at; 773 | { 774 | extern errno; 775 | register int *t; 776 | 777 | t = at; 778 | execv(f, t+DCOM); 779 | if (errno==ENOEXEC) { 780 | if (*linep) 781 | t[DCOM] = linep; 782 | t[DSPR] = "/bin/sh"; 783 | execv(t[DSPR], t+DSPR); 784 | prs("No shell!\n"); 785 | exit(); 786 | } 787 | if (errno==ENOMEM) { 788 | prs(t[DCOM]); 789 | err(": too large"); 790 | exit(); 791 | } 792 | } 793 | 794 | err(s) 795 | char *s; 796 | { 797 | 798 | prs(s); 799 | prs("\n"); 800 | if(promp == 0) { 801 | seek(0, 0, 2); 802 | exit(); 803 | } 804 | } 805 | 806 | prs(as) 807 | char *as; 808 | { 809 | register char *s; 810 | 811 | s = as; 812 | while(*s) 813 | putc(*s++); 814 | } 815 | 816 | putc(c) 817 | { 818 | 819 | write(2, &c, 1); 820 | } 821 | 822 | prn(n) 823 | int n; 824 | { 825 | register a; 826 | 827 | if(a=ldiv(0,n,10)) 828 | prn(a); 829 | putc(lrem(0,n,10)+'0'); 830 | } 831 | 832 | any(c, as) 833 | int c; 834 | char *as; 835 | { 836 | register char *s; 837 | 838 | s = as; 839 | while(*s) 840 | if(*s++ == c) 841 | return(1); 842 | return(0); 843 | } 844 | 845 | equal(as1, as2) 846 | char *as1, *as2; 847 | { 848 | register char *s1, *s2; 849 | 850 | s1 = as1; 851 | s2 = as2; 852 | while(*s1++ == *s2) 853 | if(*s2++ == '\0') 854 | return(1); 855 | return(0); 856 | } 857 | 858 | pwait(i, t) 859 | int i, *t; 860 | { 861 | register p, e; 862 | int s; 863 | 864 | if(i != 0) 865 | for(;;) { 866 | times(&timeb); 867 | time(timeb.proct); 868 | p = wait(&s); 869 | if(p == -1) 870 | break; 871 | e = s&0177; 872 | if(mesg[e] != 0) { 873 | if(p != i) { 874 | prn(p); 875 | prs(": "); 876 | } 877 | prs(mesg[e]); 878 | if(s&0200) 879 | prs(" -- Core dumped"); 880 | } 881 | if(e != 0) 882 | err(""); 883 | if(i == p) { 884 | acct(t); 885 | break; 886 | } else 887 | acct(0); 888 | } 889 | } 890 | 891 | acct(t) 892 | int *t; 893 | { 894 | if(t == 0) 895 | enacct("**gok"); else 896 | if(*t == TPAR) 897 | enacct("()"); else 898 | enacct(t[DCOM]); 899 | } 900 | 901 | enacct(as) 902 | char *as; 903 | { 904 | struct stime timbuf; 905 | struct { 906 | char cname[14]; 907 | char shf; 908 | char uid; 909 | int datet[2]; 910 | int realt[2]; 911 | int bcput[2]; 912 | int bsyst[2]; 913 | } tbuf; 914 | register i; 915 | register char *np, *s; 916 | 917 | s = as; 918 | times(&timbuf); 919 | time(timbuf.proct); 920 | lsub(tbuf.realt, timbuf.proct, timeb.proct); 921 | lsub(tbuf.bcput, timbuf.cputim, timeb.cputim); 922 | lsub(tbuf.bsyst, timbuf.systim, timeb.systim); 923 | do { 924 | np = s; 925 | while (*s != '\0' && *s != '/') 926 | s++; 927 | } while (*s++ != '\0'); 928 | for (i=0; i<14; i++) { 929 | tbuf.cname[i] = *np; 930 | if (*np) 931 | np++; 932 | } 933 | tbuf.datet[0] = timbuf.proct[0]; 934 | tbuf.datet[1] = timbuf.proct[1]; 935 | tbuf.uid = uid; 936 | tbuf.shf = 0; 937 | if (promp==0) 938 | tbuf.shf = 1; 939 | seek(acctf, 0, 2); 940 | write(acctf, &tbuf, sizeof(tbuf)); 941 | } 942 | --------------------------------------------------------------------------------