1 /* $Header: /src/pub/tcsh/sh.c,v 3.105 2002/07/05 16:28:16 christos Exp $ */ 2 /* 3 * sh.c: Main shell routines 4 */ 5 /*- 6 * Copyright (c) 1980, 1991 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 #define EXTERN /* Intern */ 34 #include "sh.h" 35 36 #ifndef lint 37 char copyright[] = 38 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 39 All rights reserved.\n"; 40 #endif /* not lint */ 41 42 RCSID("$Id: sh.c,v 3.105 2002/07/05 16:28:16 christos Exp $") 43 44 #include "tc.h" 45 #include "ed.h" 46 #include "tw.h" 47 48 extern bool MapsAreInited; 49 extern bool NLSMapsAreInited; 50 extern bool NoNLSRebind; 51 52 /* 53 * C Shell 54 * 55 * Bill Joy, UC Berkeley, California, USA 56 * October 1978, May 1980 57 * 58 * Jim Kulp, IIASA, Laxenburg, Austria 59 * April 1980 60 * 61 * Filename recognition added: 62 * Ken Greer, Ind. Consultant, Palo Alto CA 63 * October 1983. 64 * 65 * Karl Kleinpaste, Computer Consoles, Inc. 66 * Added precmd, periodic/tperiod, prompt changes, 67 * directory stack hack, and login watch. 68 * Sometime March 1983 - Feb 1984. 69 * 70 * Added scheduled commands, including the "sched" command, 71 * plus the call to sched_run near the precmd et al 72 * routines. 73 * Upgraded scheduled events for running events while 74 * sitting idle at command input. 75 * 76 * Paul Placeway, Ohio State 77 * added stuff for running with twenex/inputl 9 Oct 1984. 78 * 79 * ported to Apple Unix (TM) (OREO) 26 -- 29 Jun 1987 80 */ 81 82 jmp_buf_t reslab INIT_ZERO_STRUCT; 83 84 static const char tcshstr[] = "tcsh"; 85 #ifdef WINNT_NATIVE 86 static const char tcshstr_nt[] = "tcsh.exe"; 87 #endif /* WINNT_NATIVE */ 88 89 signalfun_t parintr = 0; /* Parents interrupt catch */ 90 signalfun_t parterm = 0; /* Parents terminate catch */ 91 92 #ifdef TESLA 93 int do_logout = 0; 94 #endif /* TESLA */ 95 96 97 bool use_fork = 0; /* use fork() instead of vfork()? */ 98 99 /* 100 * Magic pointer values. Used to specify other invalid conditions aside 101 * from null. 102 */ 103 static Char INVCHAR; 104 Char *INVPTR = &INVCHAR; 105 Char **INVPPTR = &INVPTR; 106 107 static int nofile = 0; 108 static bool reenter = 0; 109 static bool nverbose = 0; 110 static bool nexececho = 0; 111 static bool quitit = 0; 112 static bool rdirs = 0; 113 bool fast = 0; 114 static bool batch = 0; 115 static bool mflag = 0; 116 static bool prompt = 1; 117 static int enterhist = 0; 118 bool tellwhat = 0; 119 time_t t_period; 120 Char *ffile = NULL; 121 bool dolzero = 0; 122 int insource = 0; 123 int exitset = 0; 124 static time_t chktim; /* Time mail last checked */ 125 char *progname; 126 int tcsh; 127 extern char **environ; 128 129 /* 130 * This preserves the input state of the shell. It is used by 131 * st_save and st_restore to manupulate shell state. 132 */ 133 struct saved_state { 134 int insource; 135 int OLDSTD; 136 int SHIN; 137 int SHOUT; 138 int SHDIAG; 139 int intty; 140 struct whyle *whyles; 141 Char *gointr; 142 Char *arginp; 143 Char *evalp; 144 Char **evalvec; 145 Char *alvecp; 146 Char **alvec; 147 int onelflg; 148 bool enterhist; 149 Char **argv; 150 Char HIST; 151 bool cantell; 152 struct Bin B; 153 /* These keep signal state and setjump state */ 154 #ifdef BSDSIGS 155 sigmask_t mask; 156 #endif 157 jmp_buf_t oldexit; 158 int reenter; 159 }; 160 161 static int srccat __P((Char *, Char *)); 162 #ifndef WINNT_NATIVE 163 static int srcfile __P((char *, bool, int, Char **)); 164 #else 165 int srcfile __P((char *, bool, int, Char **)); 166 #endif /*WINNT_NATIVE*/ 167 static sigret_t phup __P((int)); 168 static void srcunit __P((int, bool, int, Char **)); 169 static void mailchk __P((void)); 170 #ifndef _PATH_DEFPATH 171 static Char **defaultpath __P((void)); 172 #endif 173 static void record __P((void)); 174 static void st_save __P((struct saved_state *, int, int, 175 Char **, Char **)); 176 static void st_restore __P((struct saved_state *, Char **)); 177 178 int main __P((int, char **)); 179 180 int 181 main(argc, argv) 182 int argc; 183 char **argv; 184 { 185 register Char *cp; 186 #ifdef AUTOLOGOUT 187 register Char *cp2; 188 #endif 189 register char *tcp, *ttyn; 190 register int f; 191 register char **tempv; 192 193 #ifdef BSDSIGS 194 sigvec_t osv; 195 #endif /* BSDSIGS */ 196 197 #ifdef WINNT_NATIVE 198 nt_init(); 199 #endif /* WINNT_NATIVE */ 200 #if defined(NLS_CATALOGS) && defined(LC_MESSAGES) 201 (void) setlocale(LC_MESSAGES, ""); 202 #endif /* NLS_CATALOGS && LC_MESSAGES */ 203 204 #ifdef NLS 205 # ifdef LC_CTYPE 206 (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 207 # endif /* LC_CTYPE */ 208 #endif /* NLS */ 209 210 nlsinit(); 211 212 #ifdef MALLOC_TRACE 213 mal_setstatsfile(fdopen(dup2(open("/tmp/tcsh.trace", 214 O_WRONLY|O_CREAT, 0666), 25), "w")); 215 mal_trace(1); 216 #endif /* MALLOC_TRACE */ 217 218 #if !(defined(BSDTIMES) || defined(_SEQUENT_)) && defined(POSIX) 219 # ifdef _SC_CLK_TCK 220 clk_tck = (clock_t) sysconf(_SC_CLK_TCK); 221 # else /* ! _SC_CLK_TCK */ 222 # ifdef CLK_TCK 223 clk_tck = CLK_TCK; 224 # else /* !CLK_TCK */ 225 clk_tck = HZ; 226 # endif /* CLK_TCK */ 227 # endif /* _SC_CLK_TCK */ 228 #endif /* !BSDTIMES && POSIX */ 229 230 settimes(); /* Immed. estab. timing base */ 231 #ifdef TESLA 232 do_logout = 0; 233 #endif /* TESLA */ 234 235 /* 236 * Make sure we have 0, 1, 2 open 237 * Otherwise `` jobs will not work... (From knaff@poly.polytechnique.fr) 238 */ 239 { 240 do 241 if ((f = open(_PATH_DEVNULL, O_RDONLY)) == -1 && 242 (f = open("/", O_RDONLY)) == -1) 243 exit(1); 244 while (f < 3); 245 (void) close(f); 246 } 247 248 osinit(); /* Os dependent initialization */ 249 250 251 { 252 char *t; 253 254 t = strrchr(argv[0], '/'); 255 #ifdef WINNT_NATIVE 256 { 257 char *s = strrchr(argv[0], '\\'); 258 if (s) 259 t = s; 260 } 261 #endif /* WINNT_NATIVE */ 262 t = t ? t + 1 : argv[0]; 263 if (*t == '-') t++; 264 progname = strsave((t && *t) ? t : tcshstr); /* never want a null */ 265 tcsh = strcmp(progname, tcshstr) == 0; 266 } 267 268 /* 269 * Initialize non constant strings 270 */ 271 #ifdef _PATH_BSHELL 272 STR_BSHELL = SAVE(_PATH_BSHELL); 273 #endif 274 #ifdef _PATH_TCSHELL 275 STR_SHELLPATH = SAVE(_PATH_TCSHELL); 276 #else 277 # ifdef _PATH_CSHELL 278 STR_SHELLPATH = SAVE(_PATH_CSHELL); 279 # endif 280 #endif 281 STR_environ = blk2short(environ); 282 environ = short2blk(STR_environ); /* So that we can free it */ 283 STR_WORD_CHARS = SAVE(WORD_CHARS); 284 285 HIST = '!'; 286 HISTSUB = '^'; 287 PRCH = '>'; 288 PRCHROOT = '#'; 289 word_chars = STR_WORD_CHARS; 290 bslash_quote = 0; /* PWP: do tcsh-style backslash quoting? */ 291 292 /* Default history size to 100 */ 293 set(STRhistory, SAVE("100"), VAR_READWRITE); 294 295 tempv = argv; 296 ffile = SAVE(tempv[0]); 297 dolzero = 0; 298 if (eq(ffile, STRaout)) /* A.out's are quittable */ 299 quitit = 1; 300 uid = getuid(); 301 gid = getgid(); 302 euid = geteuid(); 303 egid = getegid(); 304 /* 305 * We are a login shell if: 1. we were invoked as -<something> with 306 * optional arguments 2. or we were invoked only with the -l flag 307 */ 308 loginsh = (**tempv == '-') || (argc == 2 && 309 tempv[1][0] == '-' && tempv[1][1] == 'l' && 310 tempv[1][2] == '\0'); 311 #ifdef _VMS_POSIX 312 /* No better way to find if we are a login shell */ 313 if (!loginsh) { 314 loginsh = (argc == 1 && getppid() == 1); 315 **tempv = '-'; /* Avoid giving VMS an acidic stomach */ 316 } 317 #endif /* _VMS_POSIX */ 318 319 if (loginsh && **tempv != '-') { 320 /* 321 * Mangle the argv space 322 */ 323 tempv[1][0] = '\0'; 324 tempv[1][1] = '\0'; 325 tempv[1] = NULL; 326 for (tcp = *tempv; *tcp++;) 327 continue; 328 for (tcp--; tcp >= *tempv; tcp--) 329 tcp[1] = tcp[0]; 330 *++tcp = '-'; 331 argc--; 332 } 333 if (loginsh) { 334 (void) time(&chktim); 335 set(STRloginsh, Strsave(STRNULL), VAR_READWRITE); 336 } 337 338 AsciiOnly = 1; 339 NoNLSRebind = getenv("NOREBIND") != NULL; 340 #ifdef NLS 341 # ifdef SETLOCALEBUG 342 dont_free = 1; 343 # endif /* SETLOCALEBUG */ 344 (void) setlocale(LC_ALL, ""); 345 # ifdef LC_COLLATE 346 (void) setlocale(LC_COLLATE, ""); 347 # endif 348 # ifdef SETLOCALEBUG 349 dont_free = 0; 350 # endif /* SETLOCALEBUG */ 351 # ifdef STRCOLLBUG 352 fix_strcoll_bug(); 353 # endif /* STRCOLLBUG */ 354 355 { 356 int k; 357 358 for (k = 0200; k <= 0377 && !Isprint(k); k++) 359 continue; 360 AsciiOnly = k > 0377; 361 } 362 #else 363 AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL; 364 #endif /* NLS */ 365 if (MapsAreInited && !NLSMapsAreInited) 366 ed_InitNLSMaps(); 367 ResetArrowKeys(); 368 369 /* 370 * Initialize for periodic command intervals. Also, initialize the dummy 371 * tty list for login-watch. 372 */ 373 (void) time(&t_period); 374 #ifndef HAVENOUTMP 375 initwatch(); 376 #endif /* !HAVENOUTMP */ 377 378 #if defined(alliant) 379 /* 380 * From: Jim Pace <jdp@research.att.com> 381 * tcsh does not work properly on the alliants through an rlogin session. 382 * The shell generally hangs. Also, reference to the controlling terminal 383 * does not work ( ie: echo foo > /dev/tty ). 384 * 385 * A security feature was added to rlogind affecting FX/80's Concentrix 386 * from revision 5.5.xx upwards (through 5.7 where this fix was implemented) 387 * This security change also affects the FX/2800 series. 388 * The security change to rlogind requires the process group of an rlogin 389 * session become disassociated with the tty in rlogind. 390 * 391 * The changes needed are: 392 * 1. set the process group 393 * 2. reenable the control terminal 394 */ 395 if (loginsh && isatty(SHIN)) { 396 ttyn = (char *) ttyname(SHIN); 397 (void) close(SHIN); 398 SHIN = open(ttyn, O_RDWR); 399 shpgrp = getpid(); 400 (void) ioctl (SHIN, TIOCSPGRP, (ioctl_t) &shpgrp); 401 (void) setpgid(0, shpgrp); 402 } 403 #endif /* alliant */ 404 405 /* 406 * Move the descriptors to safe places. The variable didfds is 0 while we 407 * have only FSH* to work with. When didfds is true, we have 0,1,2 and 408 * prefer to use these. 409 */ 410 initdesc(); 411 412 /* 413 * Get and set the tty now 414 */ 415 if ((ttyn = ttyname(SHIN)) != NULL) { 416 /* 417 * Could use rindex to get rid of other possible path components, but 418 * hpux preserves the subdirectory /pty/ when storing the tty name in 419 * utmp, so we keep it too. 420 */ 421 if (strncmp(ttyn, "/dev/", 5) == 0) 422 set(STRtty, cp = SAVE(ttyn + 5), VAR_READWRITE); 423 else 424 set(STRtty, cp = SAVE(ttyn), VAR_READWRITE); 425 } 426 else 427 set(STRtty, cp = SAVE(""), VAR_READWRITE); 428 /* 429 * Initialize the shell variables. ARGV and PROMPT are initialized later. 430 * STATUS is also munged in several places. CHILD is munged when 431 * forking/waiting 432 */ 433 434 /* 435 * 7-10-87 Paul Placeway autologout should be set ONLY on login shells and 436 * on shells running as root. Out of these, autologout should NOT be set 437 * for any psudo-terminals (this catches most window systems) and not for 438 * any terminal running X windows. 439 * 440 * At Ohio State, we have had problems with a user having his X session 441 * drop out from under him (on a Sun) because the shell in his master 442 * xterm timed out and exited. 443 * 444 * Really, this should be done with a program external to the shell, that 445 * watches for no activity (and NO running programs, such as dump) on a 446 * terminal for a long peroid of time, and then SIGHUPS the shell on that 447 * terminal. 448 * 449 * bugfix by Rich Salz <rsalz@PINEAPPLE.BBN.COM>: For root rsh things 450 * allways first check to see if loginsh or really root, then do things 451 * with ttyname() 452 * 453 * Also by Jean-Francois Lamy <lamy%ai.toronto.edu@RELAY.CS.NET>: check the 454 * value of cp before using it! ("root can rsh too") 455 * 456 * PWP: keep the nested ifs; the order of the tests matters and a good 457 * (smart) C compiler might re-arange things wrong. 458 */ 459 #ifdef AUTOLOGOUT 460 # ifdef convex 461 if (uid == 0) { 462 /* root always has a 15 minute autologout */ 463 set(STRautologout, Strsave(STRrootdefautologout), VAR_READWRITE); 464 } 465 else 466 if (loginsh) 467 /* users get autologout set to 0 */ 468 set(STRautologout, Strsave(STR0), VAR_READWRITE); 469 # else /* convex */ 470 if (loginsh || (uid == 0)) { 471 if (*cp) { 472 /* only for login shells or root and we must have a tty */ 473 if ((cp2 = Strrchr(cp, (Char) '/')) != NULL) { 474 cp = cp2 + 1; 475 } 476 else 477 cp2 = cp; 478 if (!(((Strncmp(cp2, STRtty, 3) == 0) && Isalpha(cp2[3])) || 479 ((Strncmp(cp, STRpts, 3) == 0) && cp[3] == '/'))) { 480 if (getenv("DISPLAY") == NULL) { 481 /* NOT on X window shells */ 482 set(STRautologout, Strsave(STRdefautologout), 483 VAR_READWRITE); 484 } 485 } 486 } 487 } 488 # endif /* convex */ 489 #endif /* AUTOLOGOUT */ 490 491 (void) sigset(SIGALRM, alrmcatch); 492 493 set(STRstatus, Strsave(STR0), VAR_READWRITE); 494 495 /* 496 * get and set machine specific environment variables 497 */ 498 getmachine(); 499 500 501 /* 502 * Publish the selected echo style 503 */ 504 #if ECHO_STYLE != BSD_ECHO 505 if (tcsh) { 506 # if ECHO_STYLE == NONE_ECHO 507 set(STRecho_style, Strsave(STRnone), VAR_READWRITE); 508 # endif /* ECHO_STYLE == NONE_ECHO */ 509 # if ECHO_STYLE == SYSV_ECHO 510 set(STRecho_style, Strsave(STRsysv), VAR_READWRITE); 511 # endif /* ECHO_STYLE == SYSV_ECHO */ 512 # if ECHO_STYLE == BOTH_ECHO 513 set(STRecho_style, Strsave(STRboth), VAR_READWRITE); 514 # endif /* ECHO_STYLE == BOTH_ECHO */ 515 } else 516 #endif /* ECHO_STYLE != BSD_ECHO */ 517 set(STRecho_style, Strsave(STRbsd), VAR_READWRITE); 518 519 /* 520 * increment the shell level. 521 */ 522 shlvl(1); 523 524 if ((tcp = getenv("HOME")) != NULL) { 525 if (strlen(tcp) >= MAXPATHLEN) { 526 struct passwd *pw; 527 if ((pw = getpwuid(getuid())) != NULL) 528 cp = quote(SAVE(pw->pw_dir)); 529 else { 530 tcp[MAXPATHLEN-1] = '\0'; 531 cp = quote(SAVE(tcp)); 532 } 533 } else { 534 cp = quote(SAVE(tcp)); 535 } 536 } else 537 cp = NULL; 538 539 if (cp == NULL) 540 fast = 1; /* No home -> can't read scripts */ 541 else 542 set(STRhome, cp, VAR_READWRITE); 543 544 dinit(cp); /* dinit thinks that HOME == cwd in a login 545 * shell */ 546 /* 547 * Grab other useful things from the environment. Should we grab 548 * everything?? 549 */ 550 { 551 char *cln, *cus, *cgr; 552 Char buff[BUFSIZE]; 553 struct passwd *pw; 554 struct group *gr; 555 556 557 #ifdef apollo 558 int oid = getoid(); 559 560 (void) Itoa(oid, buff, 0, 0); 561 set(STRoid, Strsave(buff), VAR_READWRITE); 562 #endif /* apollo */ 563 564 (void) Itoa(uid, buff, 0, 0); 565 set(STRuid, Strsave(buff), VAR_READWRITE); 566 567 (void) Itoa(gid, buff, 0, 0); 568 set(STRgid, Strsave(buff), VAR_READWRITE); 569 570 cln = getenv("LOGNAME"); 571 cus = getenv("USER"); 572 if (cus != NULL) 573 set(STRuser, quote(SAVE(cus)), VAR_READWRITE); 574 else if (cln != NULL) 575 set(STRuser, quote(SAVE(cln)), VAR_READWRITE); 576 else if ((pw = getpwuid(uid)) == NULL) 577 set(STRuser, SAVE("unknown"), VAR_READWRITE); 578 else 579 set(STRuser, SAVE(pw->pw_name), VAR_READWRITE); 580 if (cln == NULL) 581 tsetenv(STRLOGNAME, varval(STRuser)); 582 if (cus == NULL) 583 tsetenv(STRKUSER, varval(STRuser)); 584 585 cgr = getenv("GROUP"); 586 if (cgr != NULL) 587 set(STRgroup, quote(SAVE(cgr)), VAR_READWRITE); 588 else if ((gr = getgrgid(gid)) == NULL) 589 set(STRgroup, SAVE("unknown"), VAR_READWRITE); 590 else 591 set(STRgroup, SAVE(gr->gr_name), VAR_READWRITE); 592 if (cgr == NULL) 593 tsetenv(STRKGROUP, varval(STRgroup)); 594 } 595 596 /* 597 * HOST may be wrong, since rexd transports the entire environment on sun 598 * 3.x Just set it again 599 */ 600 { 601 char cbuff[MAXHOSTNAMELEN]; 602 603 if (gethostname(cbuff, sizeof(cbuff)) >= 0) { 604 cbuff[sizeof(cbuff) - 1] = '\0'; /* just in case */ 605 tsetenv(STRHOST, str2short(cbuff)); 606 } 607 else 608 tsetenv(STRHOST, str2short("unknown")); 609 } 610 611 612 #ifdef REMOTEHOST 613 /* 614 * Try to determine the remote host we were logged in from. 615 */ 616 remotehost(); 617 #endif /* REMOTEHOST */ 618 619 #ifdef apollo 620 if ((tcp = getenv("SYSTYPE")) == NULL) 621 tcp = "bsd4.3"; 622 tsetenv(STRSYSTYPE, quote(str2short(tcp))); 623 #endif /* apollo */ 624 625 /* 626 * set editing on by default, unless running under Emacs as an inferior 627 * shell. 628 * We try to do this intelligently. If $TERM is available, then it 629 * should determine if we should edit or not. $TERM is preserved 630 * across rlogin sessions, so we will not get confused if we rlogin 631 * under an emacs shell. Another advantage is that if we run an 632 * xterm under an emacs shell, then the $TERM will be set to 633 * xterm, so we are going to want to edit. Unfortunately emacs 634 * does not restore all the tty modes, so xterm is not very well 635 * set up. But this is not the shell's fault. 636 * Also don't edit if $TERM == wm, for when we're running under an ATK app. 637 * Finally, emacs compiled under terminfo, sets the terminal to dumb, 638 * so disable editing for that too. 639 * 640 * Unfortunately, in some cases the initial $TERM setting is "unknown", 641 * "dumb", or "network" which is then changed in the user's startup files. 642 * We fix this by setting noediting here if $TERM is unknown/dumb and 643 * if noediting is set, we switch on editing if $TERM is changed. 644 */ 645 if ((tcp = getenv("TERM")) != NULL) { 646 set(STRterm, quote(SAVE(tcp)), VAR_READWRITE); 647 noediting = strcmp(tcp, "unknown") == 0 || strcmp(tcp, "dumb") == 0 || 648 strcmp(tcp, "network") == 0; 649 editing = strcmp(tcp, "emacs") != 0 && strcmp(tcp, "wm") != 0 && 650 !noediting; 651 } 652 else { 653 noediting = 0; 654 editing = ((tcp = getenv("EMACS")) == NULL || strcmp(tcp, "t") != 0); 655 } 656 657 /* 658 * The 'edit' variable is either set or unset. It doesn't 659 * need a value. Making it 'emacs' might be confusing. 660 */ 661 if (editing) 662 set(STRedit, Strsave(STRNULL), VAR_READWRITE); 663 664 665 /* 666 * still more mutability: make the complete routine automatically add the 667 * suffix of file names... 668 */ 669 set(STRaddsuffix, Strsave(STRNULL), VAR_READWRITE); 670 671 /* 672 * Random default kill ring size 673 */ 674 set(STRkillring, SAVE("30"), VAR_READWRITE); 675 676 /* 677 * Re-initialize path if set in environment 678 */ 679 if ((tcp = getenv("PATH")) == NULL) 680 #ifdef _PATH_DEFPATH 681 importpath(str2short(_PATH_DEFPATH)); 682 #else /* !_PATH_DEFPATH */ 683 setq(STRpath, defaultpath(), &shvhed, VAR_READWRITE); 684 #endif /* _PATH_DEFPATH */ 685 else 686 /* Importpath() allocates memory for the path, and the 687 * returned pointer from SAVE() was discarded, so 688 * this was a memory leak.. (sg) 689 * 690 * importpath(SAVE(tcp)); 691 */ 692 importpath(str2short(tcp)); 693 694 695 { 696 /* If the SHELL environment variable ends with "tcsh", set 697 * STRshell to the same path. This is to facilitate using 698 * the executable in environments where the compiled-in 699 * default isn't appropriate (sg). 700 */ 701 702 int sh_len = 0; 703 704 if ((tcp = getenv("SHELL")) != NULL) { 705 sh_len = strlen(tcp); 706 if ((sh_len >= 5 && strcmp(tcp + (sh_len - 5), "/tcsh") == 0) || 707 (!tcsh && sh_len >= 4 && strcmp(tcp + (sh_len - 4), "/csh") == 0)) 708 set(STRshell, quote(SAVE(tcp)), VAR_READWRITE); 709 else 710 sh_len = 0; 711 } 712 if (sh_len == 0) 713 set(STRshell, Strsave(STR_SHELLPATH), VAR_READWRITE); 714 } 715 716 #ifdef COLOR_LS_F 717 if ((tcp = getenv("LS_COLORS")) != NULL) 718 parseLS_COLORS(str2short(tcp)); 719 #endif /* COLOR_LS_F */ 720 721 doldol = putn((int) getpid()); /* For $$ */ 722 #ifdef WINNT_NATIVE 723 { 724 char *strtmp1, strtmp2[MAXPATHLEN]; 725 if ((strtmp1 = getenv("TMP")) != NULL) 726 wsprintf(strtmp2, "%s/%s", strtmp1, "sh"); 727 shtemp = Strspl(SAVE(strtmp2), doldol); /* For << */ 728 } 729 #else /* !WINNT_NATIVE */ 730 shtemp = Strspl(STRtmpsh, doldol); /* For << */ 731 #endif /* WINNT_NATIVE */ 732 733 /* 734 * Record the interrupt states from the parent process. If the parent is 735 * non-interruptible our hand must be forced or we (and our children) won't 736 * be either. Our children inherit termination from our parent. We catch it 737 * only if we are the login shell. 738 */ 739 #ifdef BSDSIGS 740 /* 741 * PURIFY-2 claims that osv does not get 742 * initialized after the sigvec call 743 */ 744 setzero((char*) &osv, sizeof(osv)); 745 /* parents interruptibility */ 746 (void) mysigvec(SIGINT, NULL, &osv); 747 parintr = (signalfun_t) osv.sv_handler; 748 (void) mysigvec(SIGTERM, NULL, &osv); 749 parterm = (signalfun_t) osv.sv_handler; 750 #else /* BSDSIGS */ 751 parintr = signal(SIGINT, SIG_IGN); /* parents interruptibility */ 752 (void) sigset(SIGINT, parintr); /* ... restore */ 753 754 # ifdef COHERENT 755 if (loginsh) /* it seems that SIGTERM is always set to SIG_IGN by */ 756 /* init/getty so it should be set to SIG_DFL - there may be */ 757 /* a better fix for this. */ 758 parterm = SIG_DFL; 759 else 760 # else /* !COHERENT */ 761 parterm = signal(SIGTERM, SIG_IGN); /* parents terminability */ 762 # endif /* COHERENT */ 763 (void) sigset(SIGTERM, parterm); /* ... restore */ 764 765 #endif /* BSDSIGS */ 766 767 768 #ifdef TCF 769 /* Enable process migration on ourselves and our progeny */ 770 (void) signal(SIGMIGRATE, SIG_DFL); 771 #endif /* TCF */ 772 773 /* 774 * dspkanji/dspmbyte autosetting 775 */ 776 /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 777 #if defined(DSPMBYTE) 778 #if defined(NLS) && defined(LC_CTYPE) 779 if (((tcp = setlocale(LC_CTYPE, NULL)) != NULL || (tcp = getenv("LANG")) != NULL) && !adrof(CHECK_MBYTEVAR)) { 780 #else 781 if ((tcp = getenv("LANG")) != NULL && !adrof(CHECK_MBYTEVAR)) { 782 #endif 783 autoset_dspmbyte(str2short(tcp)); 784 } 785 #if defined(WINNT_NATIVE) 786 else if (!adrof(CHECK_MBYTEVAR)) 787 nt_autoset_dspmbyte(); 788 #endif /* WINNT_NATIVE */ 789 #endif 790 791 fix_version(); /* publish the shell version */ 792 793 if (argc > 1 && strcmp(argv[1], "--version") == 0) { 794 xprintf("%S\n", varval(STRversion)); 795 xexit(0); 796 } 797 /* 798 * Process the arguments. 799 * 800 * Note that processing of -v/-x is actually delayed till after script 801 * processing. 802 * 803 * We set the first character of our name to be '-' if we are a shell 804 * running interruptible commands. Many programs which examine ps'es 805 * use this to filter such shells out. 806 */ 807 argc--, tempv++; 808 while (argc > 0 && (tcp = tempv[0])[0] == '-' && 809 *++tcp != '\0' && !batch) { 810 do 811 switch (*tcp++) { 812 813 case 0: /* - Interruptible, no prompt */ 814 prompt = 0; 815 setintr = 1; 816 nofile = 1; 817 break; 818 819 case 'b': /* -b Next arg is input file */ 820 batch = 1; 821 break; 822 823 case 'c': /* -c Command input from arg */ 824 if (argc == 1) 825 xexit(0); 826 argc--, tempv++; 827 #ifdef M_XENIX 828 /* Xenix Vi bug: 829 it relies on a 7 bit environment (/bin/sh), so it 830 pass ascii arguments with the 8th bit set */ 831 if (!strcmp(argv[0], "sh")) 832 { 833 char *p; 834 835 for (p = tempv[0]; *p; ++p) 836 *p &= ASCII; 837 } 838 #endif 839 arginp = SAVE(tempv[0]); 840 841 /* 842 * we put the command into a variable 843 */ 844 if (arginp != NULL) 845 set(STRcommand, quote(Strsave(arginp)), VAR_READWRITE); 846 847 /* 848 * * Give an error on -c arguments that end in * backslash to 849 * ensure that you don't make * nonportable csh scripts. 850 */ 851 { 852 register int count; 853 854 cp = arginp + Strlen(arginp); 855 count = 0; 856 while (cp > arginp && *--cp == '\\') 857 ++count; 858 if ((count & 1) != 0) { 859 exiterr = 1; 860 stderror(ERR_ARGC); 861 } 862 } 863 prompt = 0; 864 nofile = 1; 865 break; 866 case 'd': /* -d Load directory stack from file */ 867 rdirs = 1; 868 break; 869 870 #ifdef apollo 871 case 'D': /* -D Define environment variable */ 872 { 873 register Char *dp; 874 875 cp = str2short(tcp); 876 if (dp = Strchr(cp, '=')) { 877 *dp++ = '\0'; 878 tsetenv(cp, dp); 879 } 880 else 881 tsetenv(cp, STRNULL); 882 } 883 *tcp = '\0'; /* done with this argument */ 884 break; 885 #endif /* apollo */ 886 887 case 'e': /* -e Exit on any error */ 888 exiterr = 1; 889 break; 890 891 case 'f': /* -f Fast start */ 892 fast = 1; 893 break; 894 895 case 'i': /* -i Interactive, even if !intty */ 896 intact = 1; 897 nofile = 1; 898 break; 899 900 case 'm': /* -m read .cshrc (from su) */ 901 mflag = 1; 902 break; 903 904 case 'n': /* -n Don't execute */ 905 noexec = 1; 906 break; 907 908 case 'q': /* -q (Undoc'd) ... die on quit */ 909 quitit = 1; 910 break; 911 912 case 's': /* -s Read from std input */ 913 nofile = 1; 914 break; 915 916 case 't': /* -t Read one line from input */ 917 onelflg = 2; 918 prompt = 0; 919 nofile = 1; 920 break; 921 922 case 'v': /* -v Echo hist expanded input */ 923 nverbose = 1; /* ... later */ 924 break; 925 926 case 'x': /* -x Echo just before execution */ 927 nexececho = 1; /* ... later */ 928 break; 929 930 case 'V': /* -V Echo hist expanded input */ 931 setNS(STRverbose); /* NOW! */ 932 break; 933 934 case 'X': /* -X Echo just before execution */ 935 setNS(STRecho); /* NOW! */ 936 break; 937 938 case 'F': /* Undocumented flag */ 939 /* 940 * This will cause children to be created using fork instead of 941 * vfork. 942 */ 943 use_fork = 1; 944 break; 945 946 case ' ': 947 case '\t': 948 /* 949 * for O/S's that don't do the argument parsing right in 950 * "#!/foo -f " scripts 951 */ 952 break; 953 954 default: /* Unknown command option */ 955 exiterr = 1; 956 stderror(ERR_TCSHUSAGE, tcp-1, progname); 957 break; 958 959 } while (*tcp); 960 tempv++, argc--; 961 } 962 963 if (quitit) /* With all due haste, for debugging */ 964 (void) signal(SIGQUIT, SIG_DFL); 965 966 /* 967 * Unless prevented by -, -c, -i, -s, or -t, if there are remaining 968 * arguments the first of them is the name of a shell file from which to 969 * read commands. 970 */ 971 if (nofile == 0 && argc > 0) { 972 nofile = open(tempv[0], O_RDONLY); 973 if (nofile < 0) { 974 child = 1; /* So this ... */ 975 /* ... doesn't return */ 976 stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 977 } 978 if (ffile != NULL) 979 xfree((ptr_t) ffile); 980 dolzero = 1; 981 ffile = SAVE(tempv[0]); 982 /* 983 * Replace FSHIN. Handle /dev/std{in,out,err} specially 984 * since once they are closed we cannot open them again. 985 * In that case we use our own saved descriptors 986 */ 987 if ((SHIN = dmove(nofile, FSHIN)) < 0) 988 switch(nofile) { 989 case 0: 990 SHIN = FSHIN; 991 break; 992 case 1: 993 SHIN = FSHOUT; 994 break; 995 case 2: 996 SHIN = FSHDIAG; 997 break; 998 default: 999 stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 1000 break; 1001 } 1002 (void) close_on_exec(SHIN, 1); 1003 prompt = 0; 1004 /* argc not used any more */ tempv++; 1005 } 1006 1007 /* 1008 * Call to closem() used to be part of initdesc(). Now called below where 1009 * the script name argument has become stdin. Kernel may have used a file 1010 * descriptor to hold the name of the script (setuid case) and this name 1011 * mustn't be lost by closing the fd too soon. 1012 */ 1013 closem(); 1014 1015 /* 1016 * Consider input a tty if it really is or we are interactive. but not for 1017 * editing (christos) 1018 */ 1019 if (!(intty = isatty(SHIN))) { 1020 if (adrof(STRedit)) 1021 unsetv(STRedit); 1022 editing = 0; 1023 } 1024 intty |= intact; 1025 #ifndef convex 1026 if (intty || (intact && isatty(SHOUT))) { 1027 if (!batch && (uid != euid || gid != egid)) { 1028 errno = EACCES; 1029 child = 1; /* So this ... */ 1030 /* ... doesn't return */ 1031 stderror(ERR_SYSTEM, progname, strerror(errno)); 1032 } 1033 } 1034 #endif /* convex */ 1035 isoutatty = isatty(SHOUT); 1036 isdiagatty = isatty(SHDIAG); 1037 /* 1038 * Decide whether we should play with signals or not. If we are explicitly 1039 * told (via -i, or -) or we are a login shell (arg0 starts with -) or the 1040 * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 1041 * Note that in only the login shell is it likely that parent may have set 1042 * signals to be ignored 1043 */ 1044 if (loginsh || intact || (intty && isatty(SHOUT))) 1045 setintr = 1; 1046 settell(); 1047 /* 1048 * Save the remaining arguments in argv. 1049 */ 1050 setq(STRargv, blk2short(tempv), &shvhed, VAR_READWRITE); 1051 1052 /* 1053 * Set up the prompt. 1054 */ 1055 if (prompt) { 1056 if (tcsh) 1057 set(STRprompt, Strsave(STRdeftcshprompt), VAR_READWRITE); 1058 else 1059 set(STRprompt, Strsave(STRdefcshprompt), VAR_READWRITE); 1060 /* that's a meta-questionmark */ 1061 set(STRprompt2, Strsave(STRmquestion), VAR_READWRITE); 1062 set(STRprompt3, Strsave(STRKCORRECT), VAR_READWRITE); 1063 } 1064 1065 /* 1066 * If we are an interactive shell, then start fiddling with the signals; 1067 * this is a tricky game. 1068 */ 1069 shpgrp = mygetpgrp(); 1070 opgrp = tpgrp = -1; 1071 if (setintr) { 1072 signalfun_t osig; 1073 **argv = '-'; 1074 if (!quitit) /* Wary! */ 1075 (void) signal(SIGQUIT, SIG_IGN); 1076 (void) sigset(SIGINT, pintr); 1077 (void) sighold(SIGINT); 1078 (void) signal(SIGTERM, SIG_IGN); 1079 1080 /* 1081 * No reason I can see not to save history on all these events.. 1082 * Most usual occurrence is in a window system, where we're not a login 1083 * shell, but might as well be... (sg) 1084 * But there might be races when lots of shells exit together... 1085 * [this is also incompatible]. 1086 * We have to be mre careful here. If the parent wants to 1087 * ignore the signals then we leave them untouched... 1088 * We also only setup the handlers for shells that are trully 1089 * interactive. 1090 */ 1091 osig = signal(SIGHUP, phup); /* exit processing on HUP */ 1092 if (!loginsh && osig == SIG_IGN) 1093 (void) signal(SIGHUP, osig); 1094 #ifdef SIGXCPU 1095 osig = signal(SIGXCPU, phup); /* exit processing on XCPU */ 1096 if (!loginsh && osig == SIG_IGN) 1097 (void) signal(SIGXCPU, osig); 1098 #endif 1099 #ifdef SIGXFSZ 1100 osig = signal(SIGXFSZ, phup); /* exit processing on XFSZ */ 1101 if (!loginsh && osig == SIG_IGN) 1102 (void) signal(SIGXFSZ, osig); 1103 #endif 1104 1105 if (quitit == 0 && arginp == 0) { 1106 #ifdef SIGTSTP 1107 (void) signal(SIGTSTP, SIG_IGN); 1108 #endif 1109 #ifdef SIGTTIN 1110 (void) signal(SIGTTIN, SIG_IGN); 1111 #endif 1112 #ifdef SIGTTOU 1113 (void) signal(SIGTTOU, SIG_IGN); 1114 #endif 1115 /* 1116 * Wait till in foreground, in case someone stupidly runs csh & 1117 * dont want to try to grab away the tty. 1118 */ 1119 if (isatty(FSHDIAG)) 1120 f = FSHDIAG; 1121 else if (isatty(FSHOUT)) 1122 f = FSHOUT; 1123 else if (isatty(OLDSTD)) 1124 f = OLDSTD; 1125 else 1126 f = -1; 1127 1128 #ifdef NeXT 1129 /* NeXT 2.0 /usr/etc/rlogind, does not set our process group! */ 1130 if (shpgrp == 0) { 1131 shpgrp = getpid(); 1132 (void) setpgid(0, shpgrp); 1133 (void) tcsetpgrp(f, shpgrp); 1134 } 1135 #endif /* NeXT */ 1136 #ifdef BSDJOBS /* if we have tty job control */ 1137 retry: 1138 if ((tpgrp = tcgetpgrp(f)) != -1) { 1139 if (tpgrp != shpgrp) { 1140 signalfun_t old = signal(SIGTTIN, SIG_DFL); 1141 (void) kill(0, SIGTTIN); 1142 (void) signal(SIGTTIN, old); 1143 goto retry; 1144 } 1145 /* 1146 * Thanks to Matt Day for the POSIX references, and to 1147 * Paul Close for the SGI clarification. 1148 */ 1149 if (setdisc(f) != -1) { 1150 opgrp = shpgrp; 1151 shpgrp = getpid(); 1152 tpgrp = shpgrp; 1153 if (tcsetpgrp(f, shpgrp) == -1) { 1154 /* 1155 * On hpux 7.03 this fails with EPERM. This happens on 1156 * the 800 when opgrp != shpgrp at this point. (we were 1157 * forked from a non job control shell) 1158 * POSIX 7.2.4, says we failed because the process 1159 * group specified did not belong to a process 1160 * in the same session with the tty. So we set our 1161 * process group and try again. 1162 */ 1163 if (setpgid(0, shpgrp) == -1) { 1164 xprintf("setpgid:"); 1165 goto notty; 1166 } 1167 if (tcsetpgrp(f, shpgrp) == -1) { 1168 xprintf("tcsetpgrp:"); 1169 goto notty; 1170 } 1171 } 1172 /* 1173 * We check the process group now. If it is the same, then 1174 * we don't need to set it again. On hpux 7.0 on the 300's 1175 * if we set it again it fails with EPERM. This is the 1176 * correct behavior according to POSIX 4.3.3 if the process 1177 * was a session leader . 1178 */ 1179 else if (shpgrp != mygetpgrp()) { 1180 if(setpgid(0, shpgrp) == -1) { 1181 xprintf("setpgid:"); 1182 goto notty; 1183 } 1184 } 1185 #ifdef IRIS4D 1186 /* 1187 * But on irix 3.3 we need to set it again, even if it is 1188 * the same. We do that to tell the system that we 1189 * need BSD process group compatibility. 1190 */ 1191 else 1192 (void) setpgid(0, shpgrp); 1193 #endif 1194 (void) close_on_exec(dcopy(f, FSHTTY), 1); 1195 } 1196 else 1197 tpgrp = -1; 1198 } 1199 if (tpgrp == -1) { 1200 notty: 1201 xprintf(CGETS(11, 1, "Warning: no access to tty (%s).\n"), 1202 strerror(errno)); 1203 xprintf(CGETS(11, 2, "Thus no job control in this shell.\n")); 1204 /* 1205 * Fix from:Sakari Jalovaara <sja@sirius.hut.fi> if we don't 1206 * have access to tty, disable editing too 1207 */ 1208 if (adrof(STRedit)) 1209 unsetv(STRedit); 1210 editing = 0; 1211 } 1212 #else /* BSDJOBS */ /* don't have job control, so frotz it */ 1213 tpgrp = -1; 1214 #endif /* BSDJOBS */ 1215 } 1216 } 1217 if ((setintr == 0) && (parintr == SIG_DFL)) 1218 setintr = 1; 1219 1220 /* 1221 * SVR4 doesn't send a SIGCHLD when a child is stopped or continued if the 1222 * handler is installed with signal(2) or sigset(2). sigaction(2) must 1223 * be used instead. 1224 * 1225 * David Dawes (dawes@physics.su.oz.au) Sept 1991 1226 */ 1227 1228 #if SYSVREL > 3 1229 { 1230 struct sigaction act; 1231 act.sa_handler=pchild; 1232 (void) sigemptyset(&(act.sa_mask)); /* Don't block any extra sigs 1233 * when the handler is called 1234 */ 1235 act.sa_flags=0; /* want behaviour of sigset() without 1236 * SA_NOCLDSTOP 1237 */ 1238 1239 if ((sigaction(SIGCHLD,&act,(struct sigaction *)NULL)) == -1) 1240 stderror(ERR_SYSTEM, "sigaction", strerror(errno)); 1241 } 1242 #else /* SYSVREL <= 3 */ 1243 (void) sigset(SIGCHLD, pchild); /* while signals not ready */ 1244 #endif /* SYSVREL <= 3 */ 1245 1246 1247 if (intty && !arginp) 1248 (void) ed_Setup(editing);/* Get the tty state, and set defaults */ 1249 /* Only alter the tty state if editing */ 1250 1251 /* 1252 * Set an exit here in case of an interrupt or error reading the shell 1253 * start-up scripts. 1254 */ 1255 reenter = setexit(); /* PWP */ 1256 exitset++; 1257 haderr = 0; /* In case second time through */ 1258 if (!fast && reenter == 0) { 1259 /* Will have varval(STRhome) here because set fast if don't */ 1260 { 1261 int osetintr = setintr; 1262 signalfun_t oparintr = parintr; 1263 1264 #ifdef BSDSIGS 1265 sigmask_t omask = sigblock(sigmask(SIGINT)); 1266 #else 1267 (void) sighold(SIGINT); 1268 #endif 1269 setintr = 0; 1270 parintr = SIG_IGN; /* onintr in /etc/ files has no effect */ 1271 #ifdef LOGINFIRST 1272 #ifdef _PATH_DOTLOGIN 1273 if (loginsh) 1274 (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 1275 #endif 1276 #endif 1277 1278 #ifdef _PATH_DOTCSHRC 1279 (void) srcfile(_PATH_DOTCSHRC, 0, 0, NULL); 1280 #endif 1281 if (!arginp && !onelflg && !havhash) 1282 dohash(NULL,NULL); 1283 #ifndef LOGINFIRST 1284 #ifdef _PATH_DOTLOGIN 1285 if (loginsh) 1286 (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 1287 #endif 1288 #endif 1289 #ifdef BSDSIGS 1290 (void) sigsetmask(omask); 1291 #else 1292 (void) sigrelse(SIGINT); 1293 #endif 1294 setintr = osetintr; 1295 parintr = oparintr; 1296 } 1297 #ifdef LOGINFIRST 1298 if (loginsh) 1299 (void) srccat(varval(STRhome), STRsldotlogin); 1300 #endif 1301 /* upward compat. */ 1302 if (!srccat(varval(STRhome), STRsldottcshrc)) 1303 (void) srccat(varval(STRhome), STRsldotcshrc); 1304 1305 if (!fast && !arginp && !onelflg && !havhash) 1306 dohash(NULL,NULL); 1307 1308 /* 1309 * Source history before .login so that it is available in .login 1310 */ 1311 loadhist(NULL, 0); 1312 #ifndef LOGINFIRST 1313 if (loginsh) 1314 (void) srccat(varval(STRhome), STRsldotlogin); 1315 #endif 1316 if (!fast && (loginsh || rdirs)) 1317 loaddirs(NULL); 1318 } 1319 /* Initing AFTER .cshrc is the Right Way */ 1320 if (intty && !arginp) { /* PWP setup stuff */ 1321 ed_Init(); /* init the new line editor */ 1322 #ifdef SIG_WINDOW 1323 check_window_size(1); /* mung environment */ 1324 #endif /* SIG_WINDOW */ 1325 } 1326 1327 /* 1328 * Now are ready for the -v and -x flags 1329 */ 1330 if (nverbose) 1331 setNS(STRverbose); 1332 if (nexececho) 1333 setNS(STRecho); 1334 1335 /* 1336 * All the rest of the world is inside this call. The argument to process 1337 * indicates whether it should catch "error unwinds". Thus if we are a 1338 * interactive shell our call here will never return by being blown past on 1339 * an error. 1340 */ 1341 process(setintr); 1342 1343 /* 1344 * Mop-up. 1345 */ 1346 if (intty) { 1347 if (loginsh) { 1348 xprintf("logout\n"); 1349 (void) close(SHIN); 1350 child = 1; 1351 #ifdef TESLA 1352 do_logout = 1; 1353 #endif /* TESLA */ 1354 goodbye(NULL, NULL); 1355 } 1356 else { 1357 xprintf("exit\n"); 1358 } 1359 } 1360 record(); 1361 exitstat(); 1362 return (0); 1363 } 1364 1365 void 1366 untty() 1367 { 1368 #ifdef BSDJOBS 1369 if (tpgrp > 0 && opgrp != shpgrp) { 1370 (void) setpgid(0, opgrp); 1371 (void) tcsetpgrp(FSHTTY, opgrp); 1372 (void) resetdisc(FSHTTY); 1373 } 1374 #endif /* BSDJOBS */ 1375 } 1376 1377 void 1378 importpath(cp) 1379 Char *cp; 1380 { 1381 register int i = 0; 1382 register Char *dp; 1383 register Char **pv; 1384 int c; 1385 1386 for (dp = cp; *dp; dp++) 1387 if (*dp == PATHSEP) 1388 i++; 1389 /* 1390 * i+2 where i is the number of colons in the path. There are i+1 1391 * directories in the path plus we need room for a zero terminator. 1392 */ 1393 pv = (Char **) xcalloc((size_t) (i + 2), sizeof(Char *)); 1394 dp = cp; 1395 i = 0; 1396 if (*dp) 1397 for (;;) { 1398 if ((c = *dp) == PATHSEP || c == 0) { 1399 *dp = 0; 1400 pv[i++] = Strsave(*cp ? cp : STRdot); 1401 if (c) { 1402 cp = dp + 1; 1403 *dp = PATHSEP; 1404 } 1405 else 1406 break; 1407 } 1408 #ifdef WINNT_NATIVE 1409 else if (*dp == '\\') 1410 *dp = '/'; 1411 #endif /* WINNT_NATIVE */ 1412 dp++; 1413 } 1414 pv[i] = 0; 1415 setq(STRpath, pv, &shvhed, VAR_READWRITE); 1416 } 1417 1418 /* 1419 * Source to the file which is the catenation of the argument names. 1420 */ 1421 static int 1422 srccat(cp, dp) 1423 Char *cp, *dp; 1424 { 1425 if (cp[0] == '/' && cp[1] == '\0') 1426 return srcfile(short2str(dp), (mflag ? 0 : 1), 0, NULL); 1427 else { 1428 register Char *ep; 1429 char *ptr; 1430 int rv; 1431 1432 #ifdef WINNT_NATIVE 1433 ep = cp; 1434 while(*ep) 1435 ep++; 1436 if (ep[-1] == '/' && dp[0] == '/') /* silly win95 */ 1437 dp++; 1438 #endif /* WINNT_NATIVE */ 1439 1440 ep = Strspl(cp, dp); 1441 ptr = short2str(ep); 1442 1443 rv = srcfile(ptr, (mflag ? 0 : 1), 0, NULL); 1444 xfree((ptr_t) ep); 1445 return rv; 1446 } 1447 } 1448 1449 /* 1450 * Source to a file putting the file descriptor in a safe place (> 2). 1451 */ 1452 #ifndef WINNT_NATIVE 1453 static int 1454 #else 1455 int 1456 #endif /*WINNT_NATIVE*/ 1457 srcfile(f, onlyown, flag, av) 1458 char *f; 1459 bool onlyown; 1460 int flag; 1461 Char **av; 1462 { 1463 register int unit; 1464 1465 if ((unit = open(f, O_RDONLY)) == -1) 1466 return 0; 1467 unit = dmove(unit, -1); 1468 1469 (void) close_on_exec(unit, 1); 1470 srcunit(unit, onlyown, flag, av); 1471 return 1; 1472 } 1473 1474 1475 /* 1476 * Save the shell state, and establish new argument vector, and new input 1477 * fd. 1478 */ 1479 static void 1480 st_save(st, unit, hflg, al, av) 1481 struct saved_state *st; 1482 int unit, hflg; 1483 Char **al, **av; 1484 { 1485 st->insource = insource; 1486 st->SHIN = SHIN; 1487 /* Want to preserve the meaning of "source file >output". 1488 * Save old descriptors, move new 0,1,2 to safe places and assign 1489 * them to SH* and let process() redo 0,1,2 from them. 1490 * 1491 * The macro returns true if d1 and d2 are good and they point to 1492 * different things. If you don't avoid saving duplicate 1493 * descriptors, you really limit the depth of "source" recursion 1494 * you can do because of all the open file descriptors. -IAN! 1495 */ 1496 #define NEED_SAVE_FD(d1,d2) \ 1497 (fstat(d1, &s1) != -1 && fstat(d2, &s2) != -1 \ 1498 && (s1.st_ino != s2.st_ino || s1.st_dev != s2.st_dev) ) 1499 1500 st->OLDSTD = st->SHOUT = st->SHDIAG = -1;/* test later to restore these */ 1501 if (didfds) { 1502 struct stat s1, s2; 1503 if (NEED_SAVE_FD(0,OLDSTD)) 1504 st->OLDSTD = OLDSTD, OLDSTD = dmove(0, -1); 1505 if (NEED_SAVE_FD(1,SHOUT)) 1506 st->SHOUT = SHOUT, SHOUT = dmove(1, -1); 1507 if (NEED_SAVE_FD(2,SHDIAG)) 1508 st->SHDIAG = SHDIAG, SHDIAG = dmove(2, -1); 1509 donefds(); 1510 } 1511 1512 st->intty = intty; 1513 st->whyles = whyles; 1514 st->gointr = gointr; 1515 st->arginp = arginp; 1516 st->evalp = evalp; 1517 st->evalvec = evalvec; 1518 st->alvecp = alvecp; 1519 st->alvec = alvec; 1520 st->onelflg = onelflg; 1521 st->enterhist = enterhist; 1522 if (hflg) 1523 st->HIST = HIST; 1524 else 1525 st->HIST = '\0'; 1526 st->cantell = cantell; 1527 cpybin(st->B, B); 1528 1529 /* 1530 * we can now pass arguments to source. 1531 * For compatibility we do that only if arguments were really 1532 * passed, otherwise we keep the old, global $argv like before. 1533 */ 1534 if (av != NULL && *av != NULL) { 1535 struct varent *vp; 1536 if ((vp = adrof(STRargv)) != NULL && vp->vec != NULL) 1537 st->argv = saveblk(vp->vec); 1538 else 1539 st->argv = NULL; 1540 setq(STRargv, saveblk(av), &shvhed, VAR_READWRITE); 1541 } 1542 else 1543 st->argv = NULL; 1544 1545 SHIN = unit; /* Do this first */ 1546 1547 /* Establish new input arena */ 1548 { 1549 fbuf = NULL; 1550 fseekp = feobp = fblocks = 0; 1551 settell(); 1552 } 1553 1554 arginp = 0; 1555 onelflg = 0; 1556 intty = isatty(SHIN); 1557 whyles = 0; 1558 gointr = 0; 1559 evalvec = 0; 1560 evalp = 0; 1561 alvec = al; 1562 alvecp = 0; 1563 enterhist = hflg; 1564 if (enterhist) 1565 HIST = '\0'; 1566 insource = 1; 1567 } 1568 1569 1570 /* 1571 * Restore the shell to a saved state 1572 */ 1573 static void 1574 st_restore(st, av) 1575 struct saved_state *st; 1576 Char **av; 1577 { 1578 if (st->SHIN == -1) 1579 return; 1580 1581 /* Reset input arena */ 1582 { 1583 register int i; 1584 register Char** nfbuf = fbuf; 1585 register int nfblocks = fblocks; 1586 1587 fblocks = 0; 1588 fbuf = NULL; 1589 for (i = 0; i < nfblocks; i++) 1590 xfree((ptr_t) nfbuf[i]); 1591 xfree((ptr_t) nfbuf); 1592 } 1593 cpybin(B, st->B); 1594 1595 (void) close(SHIN); 1596 1597 insource = st->insource; 1598 SHIN = st->SHIN; 1599 if (st->OLDSTD != -1) 1600 (void)close(OLDSTD), OLDSTD = st->OLDSTD; 1601 if (st->SHOUT != -1) 1602 (void)close(SHOUT), SHOUT = st->SHOUT; 1603 if (st->SHDIAG != -1) 1604 (void)close(SHDIAG), SHDIAG = st->SHDIAG; 1605 arginp = st->arginp; 1606 onelflg = st->onelflg; 1607 evalp = st->evalp; 1608 evalvec = st->evalvec; 1609 alvecp = st->alvecp; 1610 alvec = st->alvec; 1611 intty = st->intty; 1612 whyles = st->whyles; 1613 gointr = st->gointr; 1614 if (st->HIST != '\0') 1615 HIST = st->HIST; 1616 enterhist = st->enterhist; 1617 cantell = st->cantell; 1618 1619 if (st->argv != NULL) 1620 setq(STRargv, st->argv, &shvhed, VAR_READWRITE); 1621 else if (av != NULL && *av != NULL && adrof(STRargv) != NULL) 1622 unsetv(STRargv); 1623 } 1624 1625 /* 1626 * Source to a unit. If onlyown it must be our file or our group or 1627 * we don't chance it. This occurs on ".cshrc"s and the like. 1628 */ 1629 static void 1630 srcunit(unit, onlyown, hflg, av) 1631 register int unit; 1632 bool onlyown; 1633 int hflg; 1634 Char **av; 1635 { 1636 struct saved_state st; 1637 st.SHIN = -1; /* st_restore checks this */ 1638 1639 if (unit < 0) 1640 return; 1641 1642 if (onlyown) { 1643 struct stat stb; 1644 1645 if (fstat(unit, &stb) < 0) { 1646 (void) close(unit); 1647 return; 1648 } 1649 } 1650 1651 getexit(st.oldexit); 1652 1653 if (setintr) 1654 #ifdef BSDSIGS 1655 st.mask = sigblock(sigmask(SIGINT)); 1656 #else 1657 (void) sighold(SIGINT); 1658 #endif 1659 1660 /* Save the current state and move us to a new state */ 1661 st_save(&st, unit, hflg, NULL, av); 1662 1663 /* 1664 * Now if we are allowing commands to be interrupted, we let ourselves be 1665 * interrupted. 1666 */ 1667 if (setintr) 1668 #ifdef BSDSIGS 1669 (void) sigsetmask(st.mask); 1670 #else 1671 (void) sigrelse(SIGINT); 1672 #endif 1673 1674 /* 1675 * Bugfix for running out of memory by: Jak Kirman 1676 * <jak%cs.brown.edu@RELAY.CS.NET>. Solution: pay attention to what 1677 * setexit() is returning because reenter _may_ be in a register, and 1678 * thus restored to 0 on a longjump(). (PWP: insert flames about 1679 * compiler-dependant code here) PWP: THANKS LOTS !!! 1680 * 1681 * PWP: think of this as like a LISP (unwind-protect ...) 1682 * thanks to Diana Smetters for pointing out how this _should_ be written 1683 */ 1684 #ifdef cray 1685 st.reenter = 1; /* assume non-zero return val */ 1686 if (setexit() == 0) { 1687 st.reenter = 0; /* Oh well, we were wrong */ 1688 #else 1689 if ((st.reenter = setexit()) == 0) { 1690 #endif 1691 process(0); /* 0 -> blow away on errors */ 1692 } 1693 1694 if (setintr) 1695 #ifdef BSDSIGS 1696 (void) sigsetmask(st.mask); 1697 #else 1698 (void) sigrelse(SIGINT); 1699 #endif 1700 1701 /* Restore the old state */ 1702 st_restore(&st, av); 1703 resexit(st.oldexit); 1704 /* 1705 * If process reset() (effectively an unwind) then we must also unwind. 1706 */ 1707 if (st.reenter) 1708 stderror(ERR_SILENT); 1709 } 1710 1711 1712 /*ARGSUSED*/ 1713 void 1714 goodbye(v, c) 1715 Char **v; 1716 struct command *c; 1717 { 1718 USE(c); 1719 record(); 1720 1721 if (loginsh) { 1722 (void) sigset(SIGQUIT, SIG_IGN); 1723 (void) sigset(SIGINT, SIG_IGN); 1724 (void) sigset(SIGTERM, SIG_IGN); 1725 (void) sigset(SIGHUP, SIG_IGN); 1726 setintr = 0; /* No interrupts after "logout" */ 1727 /* Trap errors inside .logout */ 1728 reenter = setexit(); 1729 if (reenter != 0) 1730 exitstat(); 1731 if (!(adrof(STRlogout))) 1732 set(STRlogout, Strsave(STRnormal), VAR_READWRITE); 1733 #ifdef _PATH_DOTLOGOUT 1734 (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 1735 #endif 1736 if (adrof(STRhome)) 1737 (void) srccat(varval(STRhome), STRsldtlogout); 1738 #ifdef TESLA 1739 do_logout = 1; 1740 #endif /* TESLA */ 1741 } 1742 exitstat(); 1743 } 1744 1745 void 1746 exitstat() 1747 { 1748 #ifdef PROF 1749 monitor(0); 1750 #endif 1751 /* 1752 * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit 1753 * directly because we poke child here. Otherwise we might continue 1754 * unwarrantedly (sic). 1755 */ 1756 child = 1; 1757 1758 xexit(getn(varval(STRstatus))); 1759 } 1760 1761 /* 1762 * in the event of a HUP we want to save the history 1763 */ 1764 static sigret_t 1765 phup(snum) 1766 int snum; 1767 { 1768 /* 1769 * There is no return from here, 1770 * so we are not going to release SIGHUP 1771 * anymore 1772 */ 1773 #ifdef UNRELSIGS 1774 if (snum) 1775 (void) sigset(snum, SIG_IGN); 1776 #else 1777 # ifdef BSDSIGS 1778 (void) sigblock(sigmask(SIGHUP)); 1779 # else 1780 (void) sighold(SIGHUP); 1781 # endif /* BSDSIGS */ 1782 #endif /* UNRELSIGS */ 1783 1784 if (loginsh) { 1785 set(STRlogout, Strsave(STRhangup), VAR_READWRITE); 1786 #ifdef _PATH_DOTLOGOUT 1787 (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 1788 #endif 1789 if (adrof(STRhome)) 1790 (void) srccat(varval(STRhome), STRsldtlogout); 1791 } 1792 1793 record(); 1794 1795 #ifdef POSIXJOBS 1796 /* 1797 * We kill the last foreground process group. It then becomes 1798 * responsible to propagate the SIGHUP to its progeny. 1799 */ 1800 { 1801 struct process *pp, *np; 1802 1803 for (pp = proclist.p_next; pp; pp = pp->p_next) { 1804 np = pp; 1805 /* 1806 * Find if this job is in the foreground. It could be that 1807 * the process leader has exited and the foreground flag 1808 * is cleared for it. 1809 */ 1810 do 1811 /* 1812 * If a process is in the foreground we try to kill 1813 * it's process group. If we succeed, then the 1814 * whole job is gone. Otherwise we keep going... 1815 * But avoid sending HUP to the shell again. 1816 */ 1817 if (((np->p_flags & PFOREGND) != 0) && np->p_jobid != shpgrp) { 1818 np->p_flags &= ~PHUP; 1819 if (killpg(np->p_jobid, SIGHUP) != -1) { 1820 /* In case the job was suspended... */ 1821 #ifdef SIGCONT 1822 (void) killpg(np->p_jobid, SIGCONT); 1823 #endif 1824 break; 1825 } 1826 } 1827 while ((np = np->p_friends) != pp); 1828 } 1829 } 1830 #endif /* POSIXJOBS */ 1831 1832 xexit(snum); 1833 #ifndef SIGVOID 1834 return (snum); 1835 #endif 1836 } 1837 1838 static Char *jobargv[2] = {STRjobs, 0}; 1839 1840 /* 1841 * Catch an interrupt, e.g. during lexical input. 1842 * If we are an interactive shell, we reset the interrupt catch 1843 * immediately. In any case we drain the shell output, 1844 * and finally go through the normal error mechanism, which 1845 * gets a chance to make the shell go away. 1846 */ 1847 int just_signaled; /* bugfix by Michael Bloom (mg@ttidca.TTI.COM) */ 1848 1849 #ifdef SIGVOID 1850 /*ARGSUSED*/ 1851 #endif 1852 sigret_t 1853 pintr(snum) 1854 int snum; 1855 { 1856 #ifdef UNRELSIGS 1857 if (snum) 1858 (void) sigset(snum, pintr); 1859 #endif /* UNRELSIGS */ 1860 just_signaled = 1; 1861 pintr1(1); 1862 #ifndef SIGVOID 1863 return (snum); 1864 #endif 1865 } 1866 1867 void 1868 pintr1(wantnl) 1869 bool wantnl; 1870 { 1871 register Char **v; 1872 #ifdef BSDSIGS 1873 sigmask_t omask; 1874 #endif 1875 1876 #ifdef BSDSIGS 1877 omask = sigblock((sigmask_t) 0); 1878 #endif 1879 if (setintr) { 1880 #ifdef BSDSIGS 1881 (void) sigsetmask(omask & ~sigmask(SIGINT)); 1882 #else 1883 (void) sigrelse(SIGINT); 1884 #endif 1885 if (pjobs) { 1886 pjobs = 0; 1887 xputchar('\n'); 1888 dojobs(jobargv, NULL); 1889 stderror(ERR_NAME | ERR_INTR); 1890 } 1891 } 1892 /* MH - handle interrupted completions specially */ 1893 { 1894 extern int InsideCompletion; 1895 1896 if (InsideCompletion) 1897 stderror(ERR_SILENT); 1898 } 1899 /* JV - Make sure we shut off inputl */ 1900 { 1901 extern Char GettingInput; 1902 1903 (void) Cookedmode(); 1904 GettingInput = 0; 1905 } 1906 #ifdef BSDSIGS 1907 (void) sigsetmask(omask & ~sigmask(SIGCHLD)); 1908 #else 1909 if (setintr) 1910 (void) sighold(SIGINT); 1911 (void) sigrelse(SIGCHLD); 1912 #endif 1913 drainoline(); 1914 #if !defined(_VMS_POSIX) && !defined(WINNT_NATIVE) 1915 (void) endpwent(); 1916 #endif /* !_VMS_POSIX && !WINNT_NATIVE */ 1917 1918 /* 1919 * If we have an active "onintr" then we search for the label. Note that if 1920 * one does "onintr -" then we shan't be interruptible so we needn't worry 1921 * about that here. 1922 */ 1923 if (gointr) { 1924 gotolab(gointr); 1925 timflg = 0; 1926 if ((v = pargv) != 0) 1927 pargv = 0, blkfree(v); 1928 if ((v = gargv) != 0) 1929 gargv = 0, blkfree(v); 1930 reset(); 1931 } 1932 else if (intty && wantnl) { 1933 if (editing) { 1934 /* 1935 * If we are editing a multi-line input command, and move to 1936 * the beginning of the line, we don't want to trash it when 1937 * we hit ^C 1938 */ 1939 PastBottom(); 1940 ClearLines(); 1941 ClearDisp(); 1942 } 1943 else { 1944 /* xputchar('\n'); *//* Some like this, others don't */ 1945 (void) putraw('\r'); 1946 (void) putraw('\n'); 1947 } 1948 } 1949 stderror(ERR_SILENT); 1950 } 1951 1952 /* 1953 * Process is the main driving routine for the shell. 1954 * It runs all command processing, except for those within { ... } 1955 * in expressions (which is run by a routine evalav in sh.exp.c which 1956 * is a stripped down process), and `...` evaluation which is run 1957 * also by a subset of this code in sh.glob.c in the routine backeval. 1958 * 1959 * The code here is a little strange because part of it is interruptible 1960 * and hence freeing of structures appears to occur when none is necessary 1961 * if this is ignored. 1962 * 1963 * Note that if catch is not set then we will unwind on any error. 1964 * If an end-of-file occurs, we return. 1965 */ 1966 static struct command *savet = NULL; 1967 void 1968 process(catch) 1969 bool catch; 1970 { 1971 extern char Expand; 1972 jmp_buf_t osetexit; 1973 /* PWP: This might get nuked my longjmp so don't make it a register var */ 1974 struct command *t = savet; 1975 1976 savet = NULL; 1977 getexit(osetexit); 1978 for (;;) { 1979 1980 pendjob(); 1981 1982 /* This was leaking memory badly, particularly when sourcing 1983 * files, etc.. For whatever reason we were arriving here with 1984 * allocated pointers still active, and the code was simply 1985 * overwriting them. I can't say I fully understand the 1986 * control flow here, but according to Purify this particular 1987 * leak has been plugged, and I haven't noticed any ill 1988 * effects.. (sg) 1989 */ 1990 if (paraml.next && paraml.next != ¶ml) 1991 freelex(¶ml); 1992 1993 paraml.next = paraml.prev = ¶ml; 1994 paraml.word = STRNULL; 1995 (void) setexit(); 1996 justpr = enterhist; /* execute if not entering history */ 1997 1998 /* 1999 * Interruptible during interactive reads 2000 */ 2001 if (setintr) 2002 #ifdef BSDSIGS 2003 (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 2004 #else 2005 (void) sigrelse(SIGINT); 2006 #endif 2007 2008 2009 /* 2010 * For the sake of reset() 2011 */ 2012 freelex(¶ml); 2013 if (savet) 2014 freesyn(savet), savet = NULL; 2015 2016 if (haderr) { 2017 if (!catch) { 2018 /* unwind */ 2019 doneinp = 0; 2020 savet = t; 2021 resexit(osetexit); 2022 reset(); 2023 } 2024 haderr = 0; 2025 /* 2026 * Every error is eventually caught here or the shell dies. It is 2027 * at this point that we clean up any left-over open files, by 2028 * closing all but a fixed number of pre-defined files. Thus 2029 * routines don't have to worry about leaving files open due to 2030 * deeper errors... they will get closed here. 2031 */ 2032 closem(); 2033 continue; 2034 } 2035 if (doneinp) { 2036 doneinp = 0; 2037 break; 2038 } 2039 if (chkstop) 2040 chkstop--; 2041 if (neednote) 2042 pnote(); 2043 if (intty && prompt && evalvec == 0) { 2044 just_signaled = 0; 2045 mailchk(); 2046 /* 2047 * Watch for logins/logouts. Next is scheduled commands stored 2048 * previously using "sched." Then execute periodic commands. 2049 * Following that, the prompt precmd is run. 2050 */ 2051 #ifndef HAVENOUTMP 2052 watch_login(0); 2053 #endif /* !HAVENOUTMP */ 2054 sched_run(0); 2055 period_cmd(); 2056 precmd(); 2057 /* 2058 * If we are at the end of the input buffer then we are going to 2059 * read fresh stuff. Otherwise, we are rereading input and don't 2060 * need or want to prompt. 2061 */ 2062 if (fseekp == feobp && aret == TCSH_F_SEEK) 2063 printprompt(0, NULL); 2064 flush(); 2065 setalarm(1); 2066 } 2067 if (seterr) { 2068 xfree((ptr_t) seterr); 2069 seterr = NULL; 2070 } 2071 2072 /* 2073 * Echo not only on VERBOSE, but also with history expansion. If there 2074 * is a lexical error then we forego history echo. 2075 */ 2076 if ((lex(¶ml) && !seterr && intty && !tellwhat && !Expand && 2077 !whyles) || adrof(STRverbose)) { 2078 int odidfds = didfds; 2079 haderr = 1; 2080 didfds = 0; 2081 prlex(¶ml); 2082 flush(); 2083 haderr = 0; 2084 didfds = odidfds; 2085 } 2086 (void) alarm(0); /* Autologout OFF */ 2087 2088 /* 2089 * The parser may lose space if interrupted. 2090 */ 2091 if (setintr) 2092 #ifdef BSDSIGS 2093 (void) sigblock(sigmask(SIGINT)); 2094 #else 2095 (void) sighold(SIGINT); 2096 #endif 2097 2098 /* 2099 * Save input text on the history list if reading in old history, or it 2100 * is from the terminal at the top level and not in a loop. 2101 * 2102 * PWP: entry of items in the history list while in a while loop is done 2103 * elsewhere... 2104 */ 2105 if (enterhist || (catch && intty && !whyles && !tellwhat && !arun)) 2106 savehist(¶ml, enterhist > 1); 2107 2108 if (Expand && seterr) 2109 Expand = 0; 2110 2111 /* 2112 * Print lexical error messages, except when sourcing history lists. 2113 */ 2114 if (!enterhist && seterr) 2115 stderror(ERR_OLD); 2116 2117 /* 2118 * If had a history command :p modifier then this is as far as we 2119 * should go 2120 */ 2121 if (justpr) 2122 reset(); 2123 2124 /* 2125 * If had a tellwhat from twenex() then do 2126 */ 2127 if (tellwhat) { 2128 (void) tellmewhat(¶ml, NULL); 2129 reset(); 2130 } 2131 2132 alias(¶ml); 2133 2134 #ifdef BSDJOBS 2135 /* 2136 * If we are interactive, try to continue jobs that we have stopped 2137 */ 2138 if (prompt) 2139 continue_jobs(¶ml); 2140 #endif /* BSDJOBS */ 2141 2142 /* 2143 * Check to see if the user typed "rm * .o" or something 2144 */ 2145 if (prompt) 2146 rmstar(¶ml); 2147 /* 2148 * Parse the words of the input into a parse tree. 2149 */ 2150 savet = syntax(paraml.next, ¶ml, 0); 2151 if (seterr) 2152 stderror(ERR_OLD); 2153 2154 postcmd(); 2155 /* 2156 * Execute the parse tree From: Michael Schroeder 2157 * <mlschroe@immd4.informatik.uni-erlangen.de> was execute(t, tpgrp); 2158 */ 2159 execute(savet, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 2160 2161 /* 2162 * Made it! 2163 */ 2164 freelex(¶ml); 2165 freesyn(savet), savet = NULL; 2166 #ifdef SIG_WINDOW 2167 if (windowchg || (catch && intty && !whyles && !tellwhat)) { 2168 windowchg = 0; 2169 (void) check_window_size(0); /* for window systems */ 2170 } 2171 #endif /* SIG_WINDOW */ 2172 set(STR_, Strsave(InputBuf), VAR_READWRITE | VAR_NOGLOB); 2173 } 2174 savet = t; 2175 resexit(osetexit); 2176 } 2177 2178 /*ARGSUSED*/ 2179 void 2180 dosource(t, c) 2181 register Char **t; 2182 struct command *c; 2183 { 2184 register Char *f; 2185 bool hflg = 0; 2186 extern int bequiet; 2187 char buf[BUFSIZE]; 2188 2189 USE(c); 2190 t++; 2191 if (*t && eq(*t, STRmh)) { 2192 if (*++t == NULL) 2193 stderror(ERR_NAME | ERR_HFLAG); 2194 hflg++; 2195 } 2196 else if (*t && eq(*t, STRmm)) { 2197 if (*++t == NULL) 2198 stderror(ERR_NAME | ERR_MFLAG); 2199 hflg = 2; 2200 } 2201 2202 f = globone(*t++, G_ERROR); 2203 (void) strcpy(buf, short2str(f)); 2204 xfree((ptr_t) f); 2205 if ((!srcfile(buf, 0, hflg, t)) && (!hflg) && (!bequiet)) 2206 stderror(ERR_SYSTEM, buf, strerror(errno)); 2207 } 2208 2209 /* 2210 * Check for mail. 2211 * If we are a login shell, then we don't want to tell 2212 * about any mail file unless its been modified 2213 * after the time we started. 2214 * This prevents us from telling the user things he already 2215 * knows, since the login program insists on saying 2216 * "You have mail." 2217 */ 2218 2219 /* 2220 * The AMS version. 2221 * This version checks if the file is a directory, and if so, 2222 * tells you the number of files in it, otherwise do the old thang. 2223 * The magic "+1" in the time calculation is to compensate for 2224 * an AFS bug where directory mtimes are set to 1 second in 2225 * the future. 2226 */ 2227 2228 static void 2229 mailchk() 2230 { 2231 register struct varent *v; 2232 register Char **vp; 2233 time_t t; 2234 int intvl, cnt; 2235 struct stat stb; 2236 bool new; 2237 2238 v = adrof(STRmail); 2239 if (v == NULL || v->vec == NULL) 2240 return; 2241 (void) time(&t); 2242 vp = v->vec; 2243 cnt = blklen(vp); 2244 intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 2245 if (intvl < 1) 2246 intvl = 1; 2247 if (chktim + intvl > t) 2248 return; 2249 for (; *vp; vp++) { 2250 char *filename = short2str(*vp); 2251 char *mboxdir = filename; 2252 2253 if (stat(filename, &stb) < 0) 2254 continue; 2255 #if defined(BSDTIMES) || defined(_SEQUENT_) 2256 new = stb.st_mtime > time0.tv_sec; 2257 #else 2258 new = stb.st_mtime > seconds0; 2259 #endif 2260 if (S_ISDIR(stb.st_mode)) { 2261 DIR *mailbox; 2262 int mailcount = 0; 2263 char tempfilename[MAXPATHLEN]; 2264 struct stat stc; 2265 2266 xsnprintf(tempfilename, MAXPATHLEN, "%s/new", filename); 2267 2268 if (stat(tempfilename, &stc) != -1 && S_ISDIR(stc.st_mode)) { 2269 /* 2270 * "filename/new" exists and is a directory; you are 2271 * using Qmail. 2272 */ 2273 stb = stc; 2274 #if defined(BSDTIMES) || defined(_SEQUENT_) 2275 new = stb.st_mtime > time0.tv_sec; 2276 #else 2277 new = stb.st_mtime > seconds0; 2278 #endif 2279 mboxdir = tempfilename; 2280 } 2281 2282 if (stb.st_mtime <= chktim + 1 || (loginsh && !new)) 2283 continue; 2284 2285 if ((mailbox = opendir(mboxdir)) == NULL) 2286 continue; 2287 2288 /* skip . and .. */ 2289 if (!readdir(mailbox) || !readdir(mailbox)) 2290 continue; 2291 2292 while (readdir(mailbox)) 2293 mailcount++; 2294 2295 if (mailcount == 0) 2296 continue; 2297 2298 if (cnt == 1) 2299 xprintf(CGETS(11, 3, "You have %d mail messages.\n"), 2300 mailcount); 2301 else 2302 xprintf(CGETS(11, 4, "You have %d mail messages in %s.\n"), 2303 mailcount, filename); 2304 } 2305 else { 2306 if (stb.st_size == 0 || stb.st_atime > stb.st_mtime || 2307 (stb.st_atime <= chktim && stb.st_mtime <= chktim) || 2308 (loginsh && !new)) 2309 continue; 2310 if (cnt == 1) 2311 xprintf(CGETS(11, 5, "You have %smail.\n"), 2312 new ? CGETS(11, 6, "new ") : ""); 2313 else 2314 xprintf(CGETS(11, 7, "You have %smail in %s.\n"), 2315 new ? CGETS(11, 6, "new ") : "", filename); 2316 } 2317 } 2318 chktim = t; 2319 } 2320 2321 /* 2322 * Extract a home directory from the password file 2323 * The argument points to a buffer where the name of the 2324 * user whose home directory is sought is currently. 2325 * We write the home directory of the user back there. 2326 */ 2327 int 2328 gethdir(home) 2329 Char *home; 2330 { 2331 Char *h; 2332 2333 /* 2334 * Is it us? 2335 */ 2336 if (*home == '\0') { 2337 if ((h = varval(STRhome)) != STRNULL) { 2338 (void) Strcpy(home, h); 2339 return 0; 2340 } 2341 else 2342 return 1; 2343 } 2344 2345 /* 2346 * Look in the cache 2347 */ 2348 if ((h = gettilde(home)) == NULL) 2349 return 1; 2350 else { 2351 (void) Strcpy(home, h); 2352 return 0; 2353 } 2354 } 2355 2356 /* 2357 * Move the initial descriptors to their eventual 2358 * resting places, closing all other units. 2359 */ 2360 void 2361 initdesc() 2362 { 2363 #ifdef NLS_BUGS 2364 #ifdef NLS_CATALOGS 2365 (void)catclose(catd); 2366 #endif /* NLS_CATALOGS */ 2367 #endif /* NLS_BUGS */ 2368 2369 2370 didfds = 0; /* 0, 1, 2 aren't set up */ 2371 (void) close_on_exec(SHIN = dcopy(0, FSHIN), 1); 2372 (void) close_on_exec(SHOUT = dcopy(1, FSHOUT), 1); 2373 (void) close_on_exec(SHDIAG = dcopy(2, FSHDIAG), 1); 2374 (void) close_on_exec(OLDSTD = dcopy(SHIN, FOLDSTD), 1); 2375 #ifndef CLOSE_ON_EXEC 2376 didcch = 0; /* Havent closed for child */ 2377 #endif /* CLOSE_ON_EXEC */ 2378 isdiagatty = isatty(SHDIAG); 2379 isoutatty = isatty(SHOUT); 2380 #ifdef NLS_BUGS 2381 #ifdef NLS_CATALOGS 2382 nlsinit(); 2383 #endif /* NLS_CATALOGS */ 2384 #endif /* NLS_BUGS */ 2385 } 2386 2387 2388 void 2389 #ifdef PROF 2390 done(i) 2391 #else 2392 xexit(i) 2393 #endif 2394 int i; 2395 { 2396 #ifdef TESLA 2397 if (loginsh && do_logout) { 2398 /* this is to send hangup signal to the develcon */ 2399 /* we toggle DTR. clear dtr - sleep 1 - set dtr */ 2400 /* ioctl will return ENOTTY for pty's but we ignore it */ 2401 /* exitstat will run after disconnect */ 2402 /* we sleep for 2 seconds to let things happen in */ 2403 /* .logout and rechist() */ 2404 #ifdef TIOCCDTR 2405 (void) sleep(2); 2406 (void) ioctl(FSHTTY, TIOCCDTR, NULL); 2407 (void) sleep(1); 2408 (void) ioctl(FSHTTY, TIOCSDTR, NULL); 2409 #endif /* TIOCCDTR */ 2410 } 2411 #endif /* TESLA */ 2412 2413 { 2414 struct process *pp, *np; 2415 2416 /* Kill all processes marked for hup'ing */ 2417 for (pp = proclist.p_next; pp; pp = pp->p_next) { 2418 np = pp; 2419 do 2420 if ((np->p_flags & PHUP) && np->p_jobid != shpgrp) { 2421 if (killpg(np->p_jobid, SIGHUP) != -1) { 2422 /* In case the job was suspended... */ 2423 #ifdef SIGCONT 2424 (void) killpg(np->p_jobid, SIGCONT); 2425 #endif 2426 break; 2427 } 2428 } 2429 while ((np = np->p_friends) != pp); 2430 } 2431 } 2432 untty(); 2433 #ifdef NLS_CATALOGS 2434 /* 2435 * We need to call catclose, because SVR4 leaves symlinks behind otherwise 2436 * in the catalog directories. We cannot close on a vforked() child, 2437 * because messages will stop working on the parent too. 2438 */ 2439 if (child == 0) 2440 (void) catclose(catd); 2441 #endif /* NLS_CATALOGS */ 2442 #ifdef WINNT_NATIVE 2443 nt_cleanup(); 2444 #endif /* WINNT_NATIVE */ 2445 _exit(i); 2446 } 2447 2448 #ifndef _PATH_DEFPATH 2449 static Char ** 2450 defaultpath() 2451 { 2452 char *ptr; 2453 Char **blk, **blkp; 2454 struct stat stb; 2455 2456 blkp = blk = (Char **) xmalloc((size_t) sizeof(Char *) * 10); 2457 2458 #ifndef NODOT 2459 # ifndef DOTLAST 2460 *blkp++ = Strsave(STRdot); 2461 # endif 2462 #endif 2463 2464 #define DIRAPPEND(a) \ 2465 if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \ 2466 *blkp++ = SAVE(ptr) 2467 2468 #ifdef _PATH_LOCAL 2469 DIRAPPEND(_PATH_LOCAL); 2470 #endif 2471 2472 #ifdef _PATH_USRUCB 2473 DIRAPPEND(_PATH_USRUCB); 2474 #endif 2475 2476 #ifdef _PATH_USRBSD 2477 DIRAPPEND(_PATH_USRBSD); 2478 #endif 2479 2480 #ifdef _PATH_BIN 2481 DIRAPPEND(_PATH_BIN); 2482 #endif 2483 2484 #ifdef _PATH_USRBIN 2485 DIRAPPEND(_PATH_USRBIN); 2486 #endif 2487 2488 #undef DIRAPPEND 2489 2490 #ifndef NODOT 2491 # ifdef DOTLAST 2492 *blkp++ = Strsave(STRdot); 2493 # endif 2494 #endif 2495 *blkp = NULL; 2496 return (blk); 2497 } 2498 #endif 2499 2500 static void 2501 record() 2502 { 2503 if (!fast) { 2504 recdirs(NULL, adrof(STRsavedirs) != NULL); 2505 rechist(NULL, adrof(STRsavehist) != NULL); 2506 } 2507 } 2508