1 /* 2 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 7 /* All Rights Reserved */ 8 9 /* 10 * Copyright (c) 1980 Regents of the University of California. 11 * All rights reserved. The Berkeley Software License Agreement 12 * specifies the terms and conditions for redistribution. 13 */ 14 15 #pragma ident "%Z%%M% %I% %E% SMI" 16 17 #include <locale.h> 18 #include "sh.h" 19 /* #include <sys/ioctl.h> */ 20 #include <fcntl.h> 21 #include <sys/filio.h> 22 #include "sh.tconst.h" 23 #include <pwd.h> 24 #include <stdlib.h> 25 #include "sh_policy.h" /* for pfcsh */ 26 27 /* 28 * We use these csh(1) private versions of the select macros, (see select(3C)) 29 * so as not to be limited by the size of struct fd_set (ie 1024). 30 */ 31 #define CSH_FD_SET(n, p) ((*((p) + ((n)/NFDBITS))) |= (1 << ((n) % NFDBITS))) 32 #define CSH_FD_CLR(n, p) ((*((p) + ((n)/NFDBITS))) &= ~(1 << ((n) % NFDBITS))) 33 #define CSH_FD_ISSET(n, p) ((*((p) + ((n)/NFDBITS))) & (1 << ((n) % NFDBITS))) 34 #define CSH_FD_ZERO(p, n) memset((void *)(p), 0, (n)) 35 36 tchar *pathlist[] = { S_usrbin/*"/usr/bin"*/, S_DOT /*"."*/, 0 }; 37 tchar *dumphist[] = { S_history /*"history"*/, S_h /*"-h"*/, 0, 0 }; 38 tchar *loadhist[] = { S_source /*"source"*/, S_h /*"-h"*/, S_NDOThistory /*"~/.history"*/, 0 }; 39 tchar HIST = '!'; 40 tchar HISTSUB = '^'; 41 int nofile; 42 bool reenter; 43 bool nverbose; 44 bool nexececho; 45 bool quitit; 46 bool fast; 47 bool batch; 48 bool prompt = 1; 49 bool enterhist = 0; 50 51 extern gid_t getegid(), getgid(); 52 extern uid_t geteuid(), getuid(); 53 extern tchar **strblktotsblk(/* char **, int */); 54 55 int siglwp(); 56 int sigwaiting(); 57 58 main(c, av) 59 int c; 60 char **av; 61 { 62 register tchar **v, *cp, *p, *q, *r; 63 register int f; 64 struct sigvec osv; 65 struct sigaction sa; 66 tchar s_prompt[MAXHOSTNAMELEN+3]; 67 68 pfcshflag = 0; 69 70 /* 71 * set up the error exit, if there is an error before 72 * this is done, it will core dump, and we don't 73 * tolerate core dumps 74 */ 75 haderr = 0; 76 setexit(); 77 if ( haderr ) { 78 /* 79 * if were here, there was an error in the csh 80 * startup so just punt 81 */ 82 printf("csh startup error, csh exiting...\n"); 83 flush(); 84 exitstat(); 85 } 86 87 88 (void) setlocale(LC_ALL, ""); 89 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 90 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */ 91 #endif 92 (void) textdomain(TEXT_DOMAIN); 93 94 /* 95 * This is a profile shell if the simple name of argv[0] is 96 * pfcsh or -pfcsh 97 */ 98 p = strtots(NOSTR, "pfcsh"); 99 r = strtots(NOSTR, "-pfcsh"); 100 if ((p != NOSTR) && (r != NOSTR) && 101 ((q = strtots(NOSTR, *av)) != NOSTR)) { 102 if (c > 0 && (eq(p, simple(q)) || eq(r, simple(q)))) { 103 pfcshflag = 1; 104 } 105 XFREE(q); 106 } 107 108 if (p != NOSTR) 109 XFREE(p); 110 if (r != NOSTR) 111 XFREE(r); 112 113 if (pfcshflag == 1) { 114 secpolicy_init(); 115 } 116 117 /* Copy arguments */ 118 v = strblktotsblk(av, c); 119 120 /* 121 * Initialize paraml list 122 */ 123 paraml.next = paraml.prev = ¶ml; 124 125 settimes(); /* Immed. estab. timing base */ 126 127 if (eq(v[0], S_aout/*"a.out"*/)) /* A.out's are quittable */ 128 quitit = 1; 129 uid = getuid(); 130 loginsh = **v == '-'; 131 if (loginsh) 132 (void) time(&chktim); 133 134 /* 135 * Move the descriptors to safe places. 136 * The variable didfds is 0 while we have only FSH* to work with. 137 * When didfds is true, we have 0,1,2 and prefer to use these. 138 * 139 * Also, setup data for csh internal file descriptor book keeping. 140 */ 141 initdesc(c, av); 142 143 /* 144 * Initialize the shell variables. 145 * ARGV and PROMPT are initialized later. 146 * STATUS is also munged in several places. 147 * CHILD is munged when forking/waiting 148 */ 149 150 /* don't do globbing here, just set exact copies */ 151 setNS(S_noglob); 152 153 set(S_status /* "status" */, S_0 /* "0" */); 154 dinit(cp = getenvs_("HOME")); /* dinit thinks that HOME==cwd in a */ 155 /* login shell */ 156 if (cp == NOSTR) 157 fast++; /* No home -> can't read scripts */ 158 else { 159 if (strlen_(cp) >= BUFSIZ - 10) { 160 cp = NOSTR; 161 fast++; 162 printf("%s\n", gettext("Pathname too long")); 163 set(S_home /* "home" */, savestr(cp)); 164 local_setenv(S_HOME, savestr(cp)); 165 } 166 set(S_home /* "home" */, savestr(cp)); 167 } 168 /* 169 * Grab other useful things from the environment. 170 * Should we grab everything?? 171 */ 172 if ((cp = getenvs_("USER")) != NOSTR) 173 set(S_user/*"user"*/, savestr(cp)); 174 else { 175 /* 176 * If USER is not defined, set it here. 177 */ 178 struct passwd *pw; 179 pw = getpwuid(getuid()); 180 181 if (pw != NULL) { 182 set(S_user, strtots((tchar *)0, pw->pw_name )); 183 local_setenv(S_USER, strtots((tchar *)0, pw->pw_name)); 184 } 185 else if (loginsh) { /* Give up setting USER variable. */ 186 printf("Warning: USER environment variable could not be set.\n"); 187 } 188 } 189 if ((cp = getenvs_("TERM")) != NOSTR) 190 set(S_term/*"term"*/, savestr(cp)); 191 /* 192 * Re-initialize path if set in environment 193 */ 194 if ((cp = getenvs_("PATH")) == NOSTR) 195 set1(S_path/*"path"*/, saveblk(pathlist), &shvhed); 196 else 197 importpath(cp); 198 set(S_shell/*"shell"*/, S_SHELLPATH); 199 200 doldol = putn(getpid()); /* For $$ */ 201 202 /* restore globbing until the user says otherwise */ 203 unsetv(S_noglob); 204 205 /* 206 * Record the interrupt states from the parent process. 207 * If the parent is non-interruptible our hand must be forced 208 * or we (and our children) won't be either. 209 * Our children inherit termination from our parent. 210 * We catch it only if we are the login shell. 211 */ 212 /* parents interruptibility */ 213 (void) sigvec(SIGINT, (struct sigvec *)0, &osv); 214 parintr = osv.sv_handler; 215 /* parents terminability */ 216 (void) sigvec(SIGTERM, (struct sigvec *)0, &osv); 217 parterm = osv.sv_handler; 218 219 _signal(SIGLWP, siglwp); 220 _signal(SIGWAITING, sigwaiting); 221 if (loginsh) { 222 (void) signal(SIGHUP, phup); /* exit processing on HUP */ 223 (void) signal(SIGXCPU, phup); /* ...and on XCPU */ 224 (void) signal(SIGXFSZ, phup); /* ...and on XFSZ */ 225 } 226 227 /* 228 * Process the arguments. 229 * 230 * Note that processing of -v/-x is actually delayed till after 231 * script processing. 232 */ 233 c--, v++; 234 while (c > 0 && (cp = v[0])[0] == '-' && *++cp != '\0' && !batch) { 235 do switch (*cp++) { 236 237 case 'b': /* -b Next arg is input file */ 238 batch++; 239 break; 240 241 case 'c': /* -c Command input from arg */ 242 if (c == 1) 243 exit(0); 244 c--, v++; 245 arginp = v[0]; 246 prompt = 0; 247 nofile++; 248 cflg++; 249 break; 250 251 case 'e': /* -e Exit on any error */ 252 exiterr++; 253 break; 254 255 case 'f': /* -f Fast start */ 256 fast++; 257 break; 258 259 case 'i': /* -i Interactive, even if !intty */ 260 intact++; 261 nofile++; 262 break; 263 264 case 'n': /* -n Don't execute */ 265 noexec++; 266 break; 267 268 case 'q': /* -q (Undoc'd) ... die on quit */ 269 quitit = 1; 270 break; 271 272 case 's': /* -s Read from std input */ 273 nofile++; 274 break; 275 276 case 't': /* -t Read one line from input */ 277 onelflg = 2; 278 prompt = 0; 279 nofile++; 280 break; 281 #ifdef TRACE 282 case 'T': /* -T trace switch on */ 283 trace_init(); 284 break; 285 #endif 286 287 case 'v': /* -v Echo hist expanded input */ 288 nverbose = 1; /* ... later */ 289 break; 290 291 case 'x': /* -x Echo just before execution */ 292 nexececho = 1; /* ... later */ 293 break; 294 295 case 'V': /* -V Echo hist expanded input */ 296 setNS(S_verbose/*"verbose"*/); /* NOW! */ 297 break; 298 299 case 'X': /* -X Echo just before execution */ 300 setNS(S_echo/*"echo"*/); /* NOW! */ 301 break; 302 303 } while (*cp); 304 v++, c--; 305 } 306 307 if (quitit) /* With all due haste, for debugging */ 308 (void) signal(SIGQUIT, SIG_DFL); 309 310 /* 311 * Unless prevented by -c, -i, -s, or -t, if there 312 * are remaining arguments the first of them is the name 313 * of a shell file from which to read commands. 314 */ 315 if (!batch && (uid != geteuid() || getgid() != getegid())) { 316 errno = EACCES; 317 child++; /* So this ... */ 318 Perror(S_csh/*"csh"*/); /* ... doesn't return */ 319 } 320 321 if (nofile == 0 && c > 0) { 322 nofile = open_(v[0], 0); 323 if (nofile < 0) { 324 child++; /* So this ... */ 325 Perror(v[0]); /* ... doesn't return */ 326 } 327 file = v[0]; 328 SHIN = dmove(nofile, FSHIN); /* Replace FSHIN */ 329 (void) fcntl(SHIN, F_SETFD, 1); 330 prompt = 0; 331 c--, v++; 332 } 333 334 /* 335 * Consider input a tty if it really is or we are interactive. 336 */ 337 intty = intact || isatty(SHIN); 338 339 /* 340 * Decide whether we should play with signals or not. 341 * If we are explicitly told (via -i, or -) or we are a login 342 * shell (arg0 starts with -) or the input and output are both 343 * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 344 * Note that in only the login shell is it likely that parent 345 * may have set signals to be ignored 346 */ 347 if (loginsh || intact || intty && isatty(SHOUT)) 348 setintr = 1; 349 #ifdef TELL 350 settell(); 351 #endif 352 /* 353 * Save the remaining arguments in argv. 354 */ 355 setq(S_argv/*"argv"*/, v, &shvhed); 356 357 /* 358 * Set up the prompt. 359 */ 360 if (prompt) { 361 gethostname_(s_prompt, MAXHOSTNAMELEN); 362 strcat_(s_prompt, uid == 0 ? S_SHARPSP/*"# "*/ : S_PERSENTSP/*"% "*/); 363 set(S_prompt/*"prompt"*/, s_prompt); 364 } 365 366 /* 367 * If we are an interactive shell, then start fiddling 368 * with the signals; this is a tricky game. 369 */ 370 shpgrp = getpgid(0); 371 opgrp = tpgrp = -1; 372 if (setintr) { 373 **av = '-'; 374 if (!quitit) /* Wary! */ 375 (void) signal(SIGQUIT, SIG_IGN); 376 (void) signal(SIGINT, pintr); 377 (void) sigblock(sigmask(SIGINT)); 378 (void) signal(SIGTERM, SIG_IGN); 379 if (quitit == 0 && arginp == 0) { 380 (void) signal(SIGTSTP, SIG_IGN); 381 (void) signal(SIGTTIN, SIG_IGN); 382 (void) signal(SIGTTOU, SIG_IGN); 383 /* 384 * Wait till in foreground, in case someone 385 * stupidly runs 386 * csh & 387 * dont want to try to grab away the tty. 388 */ 389 if (isatty(FSHDIAG)) 390 f = FSHDIAG; 391 else if (isatty(FSHOUT)) 392 f = FSHOUT; 393 else if (isatty(OLDSTD)) 394 f = OLDSTD; 395 else 396 f = -1; 397 retry: 398 if (ioctl(f, TIOCGPGRP, (char *)&tpgrp) == 0 && 399 tpgrp != -1) { 400 if (tpgrp != shpgrp) { 401 void (*old)() = (void (*)())signal(SIGTTIN, SIG_DFL); 402 (void) kill(0, SIGTTIN); 403 (void) signal(SIGTTIN, old); 404 goto retry; 405 } 406 opgrp = shpgrp; 407 shpgrp = getpid(); 408 tpgrp = shpgrp; 409 (void) setpgid(0, shpgrp); 410 (void) ioctl(f, TIOCSPGRP, (char *)&shpgrp); 411 (void) fcntl(dcopy(f, FSHTTY), F_SETFD, 1); 412 } else { 413 notty: 414 printf("Warning: no access to tty; thus no job control in this shell...\n"); 415 tpgrp = -1; 416 } 417 } 418 } 419 if (setintr == 0 && parintr == SIG_DFL) 420 setintr++; 421 422 /* 423 * Set SIGCHLD handler, making sure that reads restart after it runs. 424 */ 425 sigemptyset(&sa.sa_mask); 426 sa.sa_handler = pchild; 427 sa.sa_flags = SA_RESTART; 428 (void) sigaction(SIGCHLD, &sa, (struct sigaction *) NULL); 429 430 /* 431 * Set an exit here in case of an interrupt or error reading 432 * the shell start-up scripts. 433 */ 434 setexit(); 435 haderr = 0; /* In case second time through */ 436 if (!fast && reenter == 0) { 437 reenter++; 438 439 /* 440 * If this is a login csh, and /etc/.login exists, 441 * source /etc/.login first. 442 */ 443 if (loginsh) { 444 tchar tmp_etc[4+1]; /*strlen("/etc")+1 */ 445 tchar tmp_login[7+1]; /*strlen("/.login")+1*/ 446 447 strtots(tmp_etc, "/etc"); 448 strtots(tmp_login, "/.login"); 449 srccat_inlogin(tmp_etc, tmp_login); 450 } 451 452 /* Will have value("home") here because set fast if don't */ 453 srccat(value(S_home/*"home"*/), S_SLADOTcshrc/*"/.cshrc"*/); 454 455 /*Hash path*/ 456 if (!fast && !arginp && !onelflg && !havhash) 457 dohash(xhash); 458 459 460 /* 461 * Reconstruct the history list now, so that it's 462 * available from within .login. 463 */ 464 dosource(loadhist); 465 if (loginsh) { 466 srccat_inlogin(value(S_home/*"home"*/), S_SLADOTlogin/*"/.login"*/); 467 } 468 469 /* 470 * To get cdpath hashing $cdpath must have a 471 * value, not $CDPATH. So if after reading 472 * the startup files ( .cshrc ), and 473 * user has specified a value for cdpath, then 474 * cache $cdpath paths. xhash2 is global array 475 * for $cdpath caching. 476 */ 477 if (!fast && !arginp && !onelflg && !havhash2 ) 478 dohash(xhash2); 479 } 480 481 /* 482 * Now are ready for the -v and -x flags 483 */ 484 if (nverbose) 485 setNS(S_verbose/*"verbose"*/); 486 if (nexececho) 487 setNS(S_echo/*"echo"*/); 488 489 /* 490 * All the rest of the world is inside this call. 491 * The argument to process indicates whether it should 492 * catch "error unwinds". Thus if we are a interactive shell 493 * our call here will never return by being blown past on an error. 494 */ 495 process(setintr); 496 497 /* 498 * Mop-up. 499 */ 500 if (loginsh) { 501 printf("logout\n"); 502 (void) close(SHIN); /* No need for unsetfd(). */ 503 child++; 504 goodbye(); 505 } 506 rechist(); 507 exitstat(); 508 } 509 510 untty() 511 { 512 513 if (tpgrp > 0) { 514 (void) setpgid(0, opgrp); 515 (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&opgrp); 516 } 517 } 518 519 importpath(cp) 520 tchar *cp; 521 { 522 register int i = 0; 523 register tchar *dp; 524 register tchar **pv; 525 int c; 526 static tchar dot[2] = {'.', 0}; 527 528 for (dp = cp; *dp; dp++) 529 if (*dp == ':') 530 i++; 531 /* 532 * i+2 where i is the number of colons in the path. 533 * There are i+1 directories in the path plus we need 534 * room for a zero terminator. 535 */ 536 pv = (tchar **) calloc((unsigned) (i + 2), sizeof (tchar **)); 537 dp = cp; 538 i = 0; 539 if (*dp) 540 for (;;) { 541 if ((c = *dp) == ':' || c == 0) { 542 *dp = 0; 543 pv[i++] = savestr(*cp ? cp : dot); 544 if (c) { 545 cp = dp + 1; 546 *dp = ':'; 547 } else 548 break; 549 } 550 dp++; 551 } 552 pv[i] = 0; 553 set1(S_path /*"path"*/, pv, &shvhed); 554 } 555 556 /* 557 * Source to the file which is the catenation of the argument names. 558 */ 559 srccat(cp, dp) 560 tchar *cp, *dp; 561 { 562 register tchar *ep = strspl(cp, dp); 563 register int unit = dmove(open_(ep, 0), -1); 564 565 (void) fcntl(unit, F_SETFD, 1); 566 xfree(ep); 567 #ifdef INGRES 568 srcunit(unit, 0, 0); 569 #else 570 srcunit(unit, 1, 0); 571 #endif 572 } 573 574 /* 575 * Source to the file which is the catenation of the argument names. 576 * This one does not check the ownership. 577 */ 578 srccat_inlogin(cp, dp) 579 tchar *cp, *dp; 580 { 581 register tchar *ep = strspl(cp, dp); 582 register int unit = dmove(open_(ep, 0), -1); 583 584 (void) fcntl(unit, F_SETFD, 1); 585 xfree(ep); 586 srcunit(unit, 0, 0); 587 } 588 589 /* 590 * Source to a unit. If onlyown it must be our file or our group or 591 * we don't chance it. This occurs on ".cshrc"s and the like. 592 */ 593 srcunit(unit, onlyown, hflg) 594 register int unit; 595 bool onlyown; 596 bool hflg; 597 { 598 /* We have to push down a lot of state here */ 599 /* All this could go into a structure */ 600 int oSHIN = -1, oldintty = intty; 601 struct whyle *oldwhyl = whyles; 602 tchar *ogointr = gointr, *oarginp = arginp; 603 tchar *oevalp = evalp, **oevalvec = evalvec; 604 int oonelflg = onelflg; 605 bool oenterhist = enterhist; 606 tchar OHIST = HIST; 607 #ifdef TELL 608 bool otell = cantell; 609 #endif 610 struct Bin saveB; 611 612 /* The (few) real local variables */ 613 jmp_buf oldexit; 614 int reenter, omask; 615 616 if (unit < 0) 617 return; 618 if (didfds) 619 donefds(); 620 if (onlyown) { 621 struct stat stb; 622 623 if (fstat(unit, &stb) < 0 || 624 (stb.st_uid != uid && stb.st_gid != getgid())) { 625 (void) close(unit); 626 unsetfd(unit); 627 return; 628 } 629 } 630 631 /* 632 * There is a critical section here while we are pushing down the 633 * input stream since we have stuff in different structures. 634 * If we weren't careful an interrupt could corrupt SHIN's Bin 635 * structure and kill the shell. 636 * 637 * We could avoid the critical region by grouping all the stuff 638 * in a single structure and pointing at it to move it all at 639 * once. This is less efficient globally on many variable references 640 * however. 641 */ 642 getexit(oldexit); 643 reenter = 0; 644 if (setintr) 645 omask = sigblock(sigmask(SIGINT)); 646 setexit(); 647 reenter++; 648 if (reenter == 1) { 649 /* Setup the new values of the state stuff saved above */ 650 copy( (char *)&saveB, (char *)&B, sizeof saveB); 651 fbuf = (tchar **) 0; 652 fseekp = feobp = fblocks = 0; 653 oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0; 654 intty = isatty(SHIN), whyles = 0, gointr = 0; 655 evalvec = 0; evalp = 0; 656 enterhist = hflg; 657 if (enterhist) 658 HIST = '\0'; 659 /* 660 * Now if we are allowing commands to be interrupted, 661 * we let ourselves be interrupted. 662 */ 663 if (setintr) 664 (void) sigsetmask(omask); 665 #ifdef TELL 666 settell(); 667 #endif 668 process(0); /* 0 -> blow away on errors */ 669 } 670 if (setintr) 671 (void) sigsetmask(omask); 672 if (oSHIN >= 0) { 673 register int i; 674 675 /* We made it to the new state... free up its storage */ 676 /* This code could get run twice but xfree doesn't care */ 677 for (i = 0; i < fblocks; i++) 678 xfree(fbuf[i]); 679 xfree( (char *)fbuf); 680 681 /* Reset input arena */ 682 copy( (char *)&B, (char *)&saveB, sizeof B); 683 684 (void) close(SHIN), SHIN = oSHIN; 685 unsetfd(SHIN); 686 arginp = oarginp, onelflg = oonelflg; 687 evalp = oevalp, evalvec = oevalvec; 688 intty = oldintty, whyles = oldwhyl, gointr = ogointr; 689 if (enterhist) 690 HIST = OHIST; 691 enterhist = oenterhist; 692 #ifdef TELL 693 cantell = otell; 694 #endif 695 } 696 697 resexit(oldexit); 698 /* 699 * If process reset() (effectively an unwind) then 700 * we must also unwind. 701 */ 702 if (reenter >= 2) 703 error(NULL); 704 } 705 706 rechist() 707 { 708 tchar buf[BUFSIZ]; 709 int fp, ftmp, oldidfds; 710 711 if (!fast) { 712 if (value(S_savehist/*"savehist"*/)[0] == '\0') 713 return; 714 (void) strcpy_(buf, value(S_home/*"home"*/)); 715 (void) strcat_(buf, S_SLADOThistory/*"/.history"*/); 716 fp = creat_(buf, 0666); 717 if (fp == -1) 718 return; 719 oldidfds = didfds; 720 didfds = 0; 721 ftmp = SHOUT; 722 SHOUT = fp; 723 (void) strcpy_(buf, value(S_savehist/*"savehist"*/)); 724 dumphist[2] = buf; 725 dohist(dumphist); 726 (void) close(fp); 727 unsetfd(fp); 728 SHOUT = ftmp; 729 didfds = oldidfds; 730 } 731 } 732 733 goodbye() 734 { 735 if (loginsh) { 736 (void) signal(SIGQUIT, SIG_IGN); 737 (void) signal(SIGINT, SIG_IGN); 738 (void) signal(SIGTERM, SIG_IGN); 739 setintr = 0; /* No interrupts after "logout" */ 740 if (adrof(S_home/*"home"*/)) 741 srccat(value(S_home/*"home"*/), S_SLADOTlogout/*"/.logout"*/); 742 } 743 rechist(); 744 exitstat(); 745 } 746 747 exitstat() 748 { 749 750 #ifdef PROF 751 monitor(0); 752 #endif 753 /* 754 * Note that if STATUS is corrupted (i.e. getn bombs) 755 * then error will exit directly because we poke child here. 756 * Otherwise we might continue unwarrantedly (sic). 757 */ 758 child++; 759 untty(); 760 exit(getn(value(S_status/*"status"*/))); 761 } 762 763 /* 764 * in the event of a HUP we want to save the history 765 */ 766 void 767 phup() 768 { 769 rechist(); 770 exit(1); 771 } 772 773 tchar *jobargv[2] = { S_jobs/*"jobs"*/, 0 }; 774 /* 775 * Catch an interrupt, e.g. during lexical input. 776 * If we are an interactive shell, we reset the interrupt catch 777 * immediately. In any case we drain the shell output, 778 * and finally go through the normal error mechanism, which 779 * gets a chance to make the shell go away. 780 */ 781 void 782 pintr() 783 { 784 pintr1(1); 785 } 786 787 pintr1(wantnl) 788 bool wantnl; 789 { 790 register tchar **v; 791 int omask; 792 793 omask = sigblock(0); 794 if (setintr) { 795 (void) sigsetmask(omask & ~sigmask(SIGINT)); 796 if (pjobs) { 797 pjobs = 0; 798 printf("\n"); 799 dojobs(jobargv); 800 bferr("Interrupted"); 801 } 802 } 803 (void) sigsetmask(omask & ~sigmask(SIGCHLD)); 804 draino(); 805 806 /* 807 * If we have an active "onintr" then we search for the label. 808 * Note that if one does "onintr -" then we shan't be interruptible 809 * so we needn't worry about that here. 810 */ 811 if (gointr) { 812 search(ZGOTO, 0, gointr); 813 timflg = 0; 814 if (v = pargv) 815 pargv = 0, blkfree(v); 816 if (v = gargv) 817 gargv = 0, blkfree(v); 818 reset(); 819 } else if (intty && wantnl) 820 printf("\n"); /* Some like this, others don't */ 821 error(NULL); 822 } 823 824 /* 825 * Process is the main driving routine for the shell. 826 * It runs all command processing, except for those within { ... } 827 * in expressions (which is run by a routine evalav in sh.exp.c which 828 * is a stripped down process), and `...` evaluation which is run 829 * also by a subset of this code in sh.glob.c in the routine backeval. 830 * 831 * The code here is a little strange because part of it is interruptible 832 * and hence freeing of structures appears to occur when none is necessary 833 * if this is ignored. 834 * 835 * Note that if catch is not set then we will unwind on any error. 836 * If an end-of-file occurs, we return. 837 */ 838 process(catch) 839 bool catch; 840 { 841 jmp_buf osetexit; 842 register struct command *t; 843 844 getexit(osetexit); 845 for (;;) { 846 pendjob(); 847 paraml.next = paraml.prev = ¶ml; 848 paraml.word = S_ /*""*/; 849 t = 0; 850 setexit(); 851 justpr = enterhist; /* execute if not entering history */ 852 853 /* 854 * Interruptible during interactive reads 855 */ 856 if (setintr) 857 (void) sigsetmask(sigblock(0) & ~sigmask(SIGINT)); 858 859 /* 860 * For the sake of reset() 861 */ 862 freelex(¶ml), freesyn(t), t = 0; 863 864 if (haderr) { 865 if (!catch) { 866 /* unwind */ 867 doneinp = 0; 868 resexit(osetexit); 869 reset(); 870 } 871 haderr = 0; 872 /* 873 * Every error is eventually caught here or 874 * the shell dies. It is at this 875 * point that we clean up any left-over open 876 * files, by closing all but a fixed number 877 * of pre-defined files. Thus routines don't 878 * have to worry about leaving files open due 879 * to deeper errors... they will get closed here. 880 */ 881 closem(); 882 continue; 883 } 884 if (doneinp) { 885 doneinp = 0; 886 break; 887 } 888 if (chkstop) 889 chkstop--; 890 if (neednote) 891 pnote(); 892 if (intty && prompt && evalvec == 0) { 893 mailchk(); 894 /* 895 * If we are at the end of the input buffer 896 * then we are going to read fresh stuff. 897 * Otherwise, we are rereading input and don't 898 * need or want to prompt. 899 */ 900 if (fseekp == feobp) 901 printprompt(); 902 } 903 err = 0; 904 905 /* 906 * Echo not only on VERBOSE, but also with history expansion. 907 */ 908 if (lex(¶ml) && intty || 909 adrof(S_verbose /*"verbose"*/)) { 910 haderr = 1; 911 prlex(¶ml); 912 haderr = 0; 913 } 914 915 /* 916 * The parser may lose space if interrupted. 917 */ 918 if (setintr) 919 (void) sigblock(sigmask(SIGINT)); 920 921 /* 922 * Save input text on the history list if 923 * reading in old history, or it 924 * is from the terminal at the top level and not 925 * in a loop. 926 */ 927 if (enterhist || catch && intty && !whyles) 928 savehist(¶ml); 929 930 /* 931 * Print lexical error messages, except when sourcing 932 * history lists. 933 */ 934 if (!enterhist && err) 935 error("%s", gettext(err)); 936 937 /* 938 * If had a history command :p modifier then 939 * this is as far as we should go 940 */ 941 if (justpr) 942 reset(); 943 944 alias(¶ml); 945 946 /* 947 * Parse the words of the input into a parse tree. 948 */ 949 t = syntax(paraml.next, ¶ml, 0); 950 if (err) 951 error("%s", gettext(err)); 952 953 /* 954 * Execute the parse tree 955 */ 956 { 957 /* 958 * POSIX requires SIGCHLD to be held 959 * until all processes have joined the 960 * process group in order to avoid race 961 * condition. 962 */ 963 int omask; 964 965 omask = sigblock(sigmask(SIGCHLD)); 966 execute(t, tpgrp); 967 (void)sigsetmask(omask &~ sigmask(SIGCHLD)); 968 } 969 970 if (err) 971 error("%s", gettext(err)); 972 /* 973 * Made it! 974 */ 975 freelex(¶ml), freesyn(t); 976 } 977 resexit(osetexit); 978 } 979 980 dosource(t) 981 register tchar **t; 982 { 983 register tchar *f; 984 register int u; 985 bool hflg = 0; 986 tchar buf[BUFSIZ]; 987 988 t++; 989 if (*t && eq(*t, S_h /*"-h"*/)) { 990 if (*++t == NOSTR) 991 bferr("Too few arguments."); 992 hflg++; 993 } 994 (void) strcpy_(buf, *t); 995 f = globone(buf); 996 u = dmove(open_(f, 0), -1); 997 xfree(f); 998 freelex(¶ml); 999 if (u < 0 && !hflg) 1000 Perror(f); 1001 (void) fcntl(u, F_SETFD, 1); 1002 srcunit(u, 0, hflg); 1003 } 1004 1005 /* 1006 * Check for mail. 1007 * If we are a login shell, then we don't want to tell 1008 * about any mail file unless its been modified 1009 * after the time we started. 1010 * This prevents us from telling the user things he already 1011 * knows, since the login program insists on saying 1012 * "You have mail." 1013 */ 1014 mailchk() 1015 { 1016 register struct varent *v; 1017 register tchar **vp; 1018 time_t t; 1019 int intvl, cnt; 1020 struct stat stb; 1021 bool new; 1022 1023 v = adrof(S_mail /*"mail"*/); 1024 if (v == 0) 1025 return; 1026 (void) time(&t); 1027 vp = v->vec; 1028 cnt = blklen(vp); 1029 intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 1030 if (intvl < 1) 1031 intvl = 1; 1032 if (chktim + intvl > t) 1033 return; 1034 for (; *vp; vp++) { 1035 if (stat_(*vp, &stb) < 0) 1036 continue; 1037 new = stb.st_mtime > time0.tv_sec; 1038 if (stb.st_size == 0 || stb.st_atime >= stb.st_mtime || 1039 (stb.st_atime <= chktim && stb.st_mtime <= chktim) || 1040 loginsh && !new) 1041 continue; 1042 if (cnt == 1) 1043 printf("You have %smail.\n", new ? "new " : ""); 1044 else 1045 printf("%s in %t.\n", new ? "New mail" : "Mail", *vp); 1046 } 1047 chktim = t; 1048 } 1049 1050 /* 1051 * Extract a home directory from the password file 1052 * The argument points to a buffer where the name of the 1053 * user whose home directory is sought is currently. 1054 * We write the home directory of the user back there. 1055 */ 1056 gethdir(home) 1057 tchar *home; 1058 { 1059 /* getpwname will not be modified, so we need temp. buffer */ 1060 char home_str[BUFSIZ]; 1061 tchar home_ts[BUFSIZ]; 1062 register struct passwd *pp /*= getpwnam(home)*/; 1063 1064 pp = getpwnam(tstostr(home_str, home)); 1065 if (pp == 0) 1066 return (1); 1067 (void) strcpy_(home, strtots(home_ts, pp->pw_dir)); 1068 return (0); 1069 } 1070 1071 1072 /* 1073 #ifdef PROF 1074 done(i) 1075 #else 1076 exit(i) 1077 #endif 1078 int i; 1079 { 1080 1081 untty(); 1082 _exit(i); 1083 } 1084 */ 1085 1086 printprompt() 1087 { 1088 register tchar *cp; 1089 1090 if (!whyles) { 1091 /* 1092 * Print the prompt string 1093 */ 1094 for (cp = value(S_prompt /*"prompt"*/); *cp; cp++) 1095 if (*cp == HIST) 1096 printf("%d", eventno + 1); 1097 else { 1098 if (*cp == '\\' && cp[1] == HIST) 1099 cp++; 1100 Putchar(*cp | QUOTE); 1101 } 1102 } else 1103 /* 1104 * Prompt for forward reading loop 1105 * body content. 1106 */ 1107 printf("? "); 1108 flush(); 1109 } 1110 1111 /* 1112 * Save char * block. 1113 */ 1114 tchar ** 1115 strblktotsblk(v, num) 1116 register char **v; 1117 int num; 1118 { 1119 register tchar **newv = 1120 (tchar **) calloc((unsigned) (num+ 1), sizeof (tchar **)); 1121 tchar **onewv = newv; 1122 1123 while (*v && num--) 1124 *newv++ = strtots(NOSTR,*v++); 1125 *newv = 0; 1126 return (onewv); 1127 } 1128 1129 1130 sigwaiting() 1131 { 1132 _signal(SIGWAITING, sigwaiting); 1133 } 1134 1135 siglwp() 1136 { 1137 _signal(SIGLWP, siglwp); 1138 } 1139 1140 1141 /* 1142 * Following functions and data are used for csh to do its 1143 * file descriptors book keeping. 1144 */ 1145 1146 static int *fdinuse = NULL; /* The list of files opened by csh */ 1147 static int nbytesused = 0; /* no of bytes allocated to fdinuse */ 1148 static int max_fd = 0; /* The maximum descriptor in fdinuse */ 1149 static int my_pid; /* The process id set in initdesc() */ 1150 static int NoFile = NOFILE; /* The number of files I can use. */ 1151 1152 /* 1153 * Get the number of files this csh can use. 1154 * 1155 * Move the initial descriptors to their eventual 1156 * resting places, closing all other units. 1157 * 1158 * Also, reserve 0/1/2, so NIS+ routines do not get 1159 * hold of them. And initialize fdinuse list and set 1160 * the current process id. 1161 * 1162 * If this csh was invoked from setuid'ed script file, 1163 * do not close the third argument passed. The file 1164 * must be one of /dev/fd/0,1,2,,, 1165 * (execv() always passes three arguments when it execs a script 1166 * file in a form of #! /bin/csh -b.) 1167 * 1168 * If is_reinit is set in initdesc_x(), then we only close the file 1169 * descriptors that we actually opened (as recorded in fdinuse). 1170 */ 1171 initdesc(argc, argv) 1172 int argc; 1173 char *argv[]; 1174 { 1175 initdesc_x(argc, argv, 0); 1176 } 1177 1178 reinitdesc(argc, argv) 1179 int argc; 1180 char *argv[]; 1181 { 1182 initdesc_x(argc, argv, 1); 1183 } 1184 1185 /* 1186 * Callback functions for closing all file descriptors. 1187 */ 1188 static int 1189 close_except(void *cd, int fd) 1190 { 1191 int script_fd = *(int *)cd; 1192 1193 if (fd >= 3 && fd < NoFile && fd != script_fd) 1194 (void) close(fd); 1195 return (0); 1196 } 1197 1198 static int 1199 close_inuse(void *cd, int fd) 1200 { 1201 int script_fd = *(int *)cd; 1202 1203 if (fd >= 3 && fd < NoFile && fd != script_fd && 1204 CSH_FD_ISSET(fd, fdinuse)) { 1205 (void) close(fd); 1206 unsetfd(fd); 1207 } 1208 return (0); 1209 } 1210 1211 initdesc_x(argc, argv, is_reinit) 1212 int argc; 1213 char *argv[]; 1214 int is_reinit; 1215 { 1216 1217 int script_fd = -1; 1218 struct stat buf; 1219 struct rlimit rlp; 1220 1221 /* 1222 * Get pid of this shell 1223 */ 1224 my_pid = getpid(); 1225 1226 /* 1227 * Get the hard limit numbers of descriptors 1228 * this csh can use. 1229 */ 1230 if (getrlimit(RLIMIT_NOFILE, &rlp) == 0) 1231 NoFile = rlp.rlim_cur; 1232 1233 /* 1234 * If this csh was invoked for executing setuid script file, 1235 * the third argument passed is the special file name 1236 * which should not be closed. This special file name is 1237 * in the form /dev/fd/X. 1238 */ 1239 if (argc >= 3) 1240 if (sscanf(argv[2], "/dev/fd/%d", &script_fd) != 1) 1241 script_fd = -1; 1242 else 1243 fcntl(script_fd, F_SETFD, 1); /* Make sure to close 1244 * this file on exec. 1245 */ 1246 1247 if (fdinuse == NULL) { 1248 nbytesused = sizeof(int) * howmany(NoFile, sizeof(int) * NBBY); 1249 fdinuse = (int *) xalloc(nbytesused); 1250 } 1251 1252 /* 1253 * Close all files except 0/1/2 to get a clean 1254 * file descritor space. 1255 */ 1256 if (!is_reinit) 1257 (void) fdwalk(close_except, &script_fd); 1258 else 1259 (void) fdwalk(close_inuse, &script_fd); 1260 1261 didfds = 0; /* 0, 1, 2 aren't set up */ 1262 1263 if (fstat(0, &buf) < 0) 1264 open("/dev/null", 0); 1265 1266 (void) fcntl(SHIN = dcopy(0, FSHIN), F_SETFD, 1); 1267 (void) fcntl(SHOUT = dcopy(1, FSHOUT), F_SETFD, 1); 1268 (void) fcntl(SHDIAG = dcopy(2, FSHDIAG), F_SETFD, 1); 1269 (void) fcntl(OLDSTD = dcopy(SHIN, FOLDSTD), F_SETFD, 1); 1270 1271 /* 1272 * Open 0/1/2 to avoid Nis+ functions to pick them up. 1273 * Now, 0/1/2 are saved, close them and open them. 1274 */ 1275 close(0); close(1); close(2); 1276 open("/dev/null", 0); 1277 dup(0); 1278 dup(0); 1279 1280 /* 1281 * Clear fd_set mask 1282 */ 1283 if ( ! is_reinit) 1284 CSH_FD_ZERO(fdinuse, nbytesused); 1285 } 1286 1287 /* 1288 * This routine is called after an error to close up 1289 * any units which may have been left open accidentally. 1290 * 1291 * You only need to remove files in fdinuse list. 1292 * After you have removed the files, you can clear the 1293 * list and max_fd. 1294 */ 1295 closem() 1296 { 1297 register int f; 1298 1299 for (f = 3; f <= max_fd; f++) { 1300 if (CSH_FD_ISSET(f, fdinuse) && 1301 f != SHIN && f != SHOUT && f != SHDIAG && 1302 f != OLDSTD && f != FSHTTY) 1303 close(f); 1304 } 1305 CSH_FD_ZERO(fdinuse, nbytesused); 1306 max_fd = 0; 1307 } 1308 1309 /* 1310 * Reset my_pid when a new process is created. Only call this 1311 * if you want the process to affect fdinuse (e.g., fork, but 1312 * not vfork). 1313 */ 1314 new_process() 1315 { 1316 my_pid = getpid(); 1317 } 1318 1319 1320 /* 1321 * Whenever Csh open/create/dup/pipe a file or files, 1322 * Csh keeps track of its open files. The open files 1323 * are kept in "fdinuse, Fd In Use" list. 1324 * 1325 * When a file descriptor is newly allocated, setfd() is 1326 * used to mark the fact in "fdinuse" list. 1327 * For example, 1328 * fd = open("newfile", 0); 1329 * setfd(fd); 1330 * 1331 * When a file is freed by close() function, unsetfd() is 1332 * used to remove the fd from "fdinuse" list. 1333 * For example, 1334 * close(fd); 1335 * unsetfd(fd); 1336 */ 1337 setfd(fd) 1338 int fd; 1339 { 1340 /* 1341 * Because you want to avoid 1342 * conflict due to vfork(). 1343 */ 1344 if (my_pid != getpid()) 1345 return; 1346 1347 if (fd >= NoFile || fd < 0) 1348 return; 1349 1350 if (fd > max_fd) 1351 max_fd = fd; 1352 CSH_FD_SET(fd, fdinuse); 1353 } 1354 1355 unsetfd(fd) 1356 int fd; 1357 { 1358 register int i; 1359 1360 /* 1361 * Because you want to avoid 1362 * conflict due to vfork(). 1363 */ 1364 if (my_pid != getpid()) 1365 return; 1366 1367 if (fd >= NoFile || fd < 0) 1368 return; 1369 1370 CSH_FD_CLR(fd, fdinuse); 1371 if (fd == max_fd) { 1372 for (i = max_fd-1; i >= 3; i--) 1373 if (CSH_FD_ISSET(i, fdinuse)) { 1374 max_fd = i; 1375 return; 1376 } 1377 max_fd = 0; 1378 } 1379 } 1380 1381 /* 1382 * A generic call back routine to output error messages from the 1383 * policy backing functions called by pfcsh. 1384 */ 1385 void 1386 secpolicy_print(int level, const char *msg) 1387 { 1388 switch (level) { 1389 case SECPOLICY_WARN: 1390 default: 1391 haderr = 1; 1392 printf("%s: ", msg); /* printf() does gettext() */ 1393 break; 1394 case SECPOLICY_ERROR: 1395 bferr(msg); /* bferr() does gettext() */ 1396 break; 1397 } 1398 } 1399