sh.c revision 131962
1131962Smp/* $Header: /src/pub/tcsh/sh.c,v 3.109 2004/02/21 20:34:24 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.c: Main shell routines 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#define EXTERN /* Intern */ 3459243Sobrien#include "sh.h" 3559243Sobrien 3659243Sobrien#ifndef lint 3759243Sobrienchar copyright[] = 3859243Sobrien"@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 3959243Sobrien All rights reserved.\n"; 4059243Sobrien#endif /* not lint */ 4159243Sobrien 42131962SmpRCSID("$Id: sh.c,v 3.109 2004/02/21 20:34:24 christos Exp $") 4359243Sobrien 4459243Sobrien#include "tc.h" 4559243Sobrien#include "ed.h" 4659243Sobrien#include "tw.h" 4759243Sobrien 4859243Sobrienextern bool MapsAreInited; 4959243Sobrienextern bool NLSMapsAreInited; 5059243Sobrienextern bool NoNLSRebind; 5159243Sobrien 5259243Sobrien/* 5359243Sobrien * C Shell 5459243Sobrien * 5559243Sobrien * Bill Joy, UC Berkeley, California, USA 5659243Sobrien * October 1978, May 1980 5759243Sobrien * 5859243Sobrien * Jim Kulp, IIASA, Laxenburg, Austria 5959243Sobrien * April 1980 6059243Sobrien * 6159243Sobrien * Filename recognition added: 6259243Sobrien * Ken Greer, Ind. Consultant, Palo Alto CA 6359243Sobrien * October 1983. 6459243Sobrien * 6559243Sobrien * Karl Kleinpaste, Computer Consoles, Inc. 6659243Sobrien * Added precmd, periodic/tperiod, prompt changes, 6759243Sobrien * directory stack hack, and login watch. 6859243Sobrien * Sometime March 1983 - Feb 1984. 6959243Sobrien * 7059243Sobrien * Added scheduled commands, including the "sched" command, 7159243Sobrien * plus the call to sched_run near the precmd et al 7259243Sobrien * routines. 7359243Sobrien * Upgraded scheduled events for running events while 7459243Sobrien * sitting idle at command input. 7559243Sobrien * 7659243Sobrien * Paul Placeway, Ohio State 7759243Sobrien * added stuff for running with twenex/inputl 9 Oct 1984. 7859243Sobrien * 7959243Sobrien * ported to Apple Unix (TM) (OREO) 26 -- 29 Jun 1987 8059243Sobrien */ 8159243Sobrien 8259243Sobrienjmp_buf_t reslab INIT_ZERO_STRUCT; 8359243Sobrien 8459243Sobrienstatic const char tcshstr[] = "tcsh"; 8569408Sache#ifdef WINNT_NATIVE 8659243Sobrienstatic const char tcshstr_nt[] = "tcsh.exe"; 8769408Sache#endif /* WINNT_NATIVE */ 8859243Sobrien 8959243Sobriensignalfun_t parintr = 0; /* Parents interrupt catch */ 9059243Sobriensignalfun_t parterm = 0; /* Parents terminate catch */ 9159243Sobrien 9259243Sobrien#ifdef TESLA 9359243Sobrienint do_logout = 0; 9459243Sobrien#endif /* TESLA */ 9559243Sobrien 9659243Sobrien 9759243Sobrienbool use_fork = 0; /* use fork() instead of vfork()? */ 9859243Sobrien 9959243Sobrien/* 10059243Sobrien * Magic pointer values. Used to specify other invalid conditions aside 10159243Sobrien * from null. 10259243Sobrien */ 10359243Sobrienstatic Char INVCHAR; 10459243SobrienChar *INVPTR = &INVCHAR; 10559243SobrienChar **INVPPTR = &INVPTR; 10659243Sobrien 10759243Sobrienstatic int nofile = 0; 10859243Sobrienstatic bool reenter = 0; 10959243Sobrienstatic bool nverbose = 0; 11059243Sobrienstatic bool nexececho = 0; 11159243Sobrienstatic bool quitit = 0; 11259243Sobrienstatic bool rdirs = 0; 11359243Sobrienbool fast = 0; 11459243Sobrienstatic bool batch = 0; 11559243Sobrienstatic bool mflag = 0; 11659243Sobrienstatic bool prompt = 1; 11759243Sobrienstatic int enterhist = 0; 11859243Sobrienbool tellwhat = 0; 11959243Sobrientime_t t_period; 12059243SobrienChar *ffile = NULL; 12159243Sobrienbool dolzero = 0; 12259243Sobrienint insource = 0; 12369408Sacheint exitset = 0; 12459243Sobrienstatic time_t chktim; /* Time mail last checked */ 12559243Sobrienchar *progname; 12659243Sobrienint tcsh; 12759243Sobrienextern char **environ; 12859243Sobrien 12959243Sobrien/* 13059243Sobrien * This preserves the input state of the shell. It is used by 13159243Sobrien * st_save and st_restore to manupulate shell state. 13259243Sobrien */ 13359243Sobrienstruct saved_state { 13459243Sobrien int insource; 135100616Smp int OLDSTD; 13659243Sobrien int SHIN; 137100616Smp int SHOUT; 138100616Smp int SHDIAG; 13959243Sobrien int intty; 14059243Sobrien struct whyle *whyles; 14159243Sobrien Char *gointr; 14259243Sobrien Char *arginp; 14359243Sobrien Char *evalp; 14459243Sobrien Char **evalvec; 14559243Sobrien Char *alvecp; 14659243Sobrien Char **alvec; 14759243Sobrien int onelflg; 14859243Sobrien bool enterhist; 14959243Sobrien Char **argv; 15059243Sobrien Char HIST; 15159243Sobrien bool cantell; 15259243Sobrien struct Bin B; 15359243Sobrien /* These keep signal state and setjump state */ 15459243Sobrien#ifdef BSDSIGS 15559243Sobrien sigmask_t mask; 15659243Sobrien#endif 15759243Sobrien jmp_buf_t oldexit; 15859243Sobrien int reenter; 15959243Sobrien}; 16059243Sobrien 16159243Sobrienstatic int srccat __P((Char *, Char *)); 16283098Smp#ifndef WINNT_NATIVE 16359243Sobrienstatic int srcfile __P((char *, bool, int, Char **)); 16483098Smp#else 16583098Smpint srcfile __P((char *, bool, int, Char **)); 16683098Smp#endif /*WINNT_NATIVE*/ 16759243Sobrienstatic sigret_t phup __P((int)); 16859243Sobrienstatic void srcunit __P((int, bool, int, Char **)); 16959243Sobrienstatic void mailchk __P((void)); 17059243Sobrien#ifndef _PATH_DEFPATH 17159243Sobrienstatic Char **defaultpath __P((void)); 17259243Sobrien#endif 17359243Sobrienstatic void record __P((void)); 17459243Sobrienstatic void st_save __P((struct saved_state *, int, int, 17559243Sobrien Char **, Char **)); 17659243Sobrienstatic void st_restore __P((struct saved_state *, Char **)); 17759243Sobrien 17859243Sobrien int main __P((int, char **)); 17959243Sobrien 18059243Sobrienint 18159243Sobrienmain(argc, argv) 18259243Sobrien int argc; 18359243Sobrien char **argv; 18459243Sobrien{ 18559243Sobrien register Char *cp; 18659243Sobrien#ifdef AUTOLOGOUT 18759243Sobrien register Char *cp2; 18859243Sobrien#endif 18959243Sobrien register char *tcp, *ttyn; 19059243Sobrien register int f; 19159243Sobrien register char **tempv; 192131962Smp int osetintr; 193131962Smp signalfun_t oparintr; 19459243Sobrien 19559243Sobrien#ifdef BSDSIGS 19659243Sobrien sigvec_t osv; 19759243Sobrien#endif /* BSDSIGS */ 19859243Sobrien 19969408Sache#ifdef WINNT_NATIVE 20059243Sobrien nt_init(); 20169408Sache#endif /* WINNT_NATIVE */ 20259243Sobrien#if defined(NLS_CATALOGS) && defined(LC_MESSAGES) 20359243Sobrien (void) setlocale(LC_MESSAGES, ""); 20459243Sobrien#endif /* NLS_CATALOGS && LC_MESSAGES */ 20559243Sobrien 20659243Sobrien#ifdef NLS 20759243Sobrien# ifdef LC_CTYPE 20859243Sobrien (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 20959243Sobrien# endif /* LC_CTYPE */ 21059243Sobrien#endif /* NLS */ 21159243Sobrien 21259243Sobrien nlsinit(); 21359243Sobrien 21459243Sobrien#ifdef MALLOC_TRACE 21559243Sobrien mal_setstatsfile(fdopen(dup2(open("/tmp/tcsh.trace", 216131962Smp O_WRONLY|O_CREAT|O_LARGEFILE, 0666), 25), 217131962Smp "w")); 21859243Sobrien mal_trace(1); 21959243Sobrien#endif /* MALLOC_TRACE */ 22059243Sobrien 22159243Sobrien#if !(defined(BSDTIMES) || defined(_SEQUENT_)) && defined(POSIX) 22259243Sobrien# ifdef _SC_CLK_TCK 22359243Sobrien clk_tck = (clock_t) sysconf(_SC_CLK_TCK); 22459243Sobrien# else /* ! _SC_CLK_TCK */ 22559243Sobrien# ifdef CLK_TCK 22659243Sobrien clk_tck = CLK_TCK; 22759243Sobrien# else /* !CLK_TCK */ 22859243Sobrien clk_tck = HZ; 22959243Sobrien# endif /* CLK_TCK */ 23059243Sobrien# endif /* _SC_CLK_TCK */ 23159243Sobrien#endif /* !BSDTIMES && POSIX */ 23259243Sobrien 23359243Sobrien settimes(); /* Immed. estab. timing base */ 23459243Sobrien#ifdef TESLA 23559243Sobrien do_logout = 0; 23659243Sobrien#endif /* TESLA */ 23759243Sobrien 23859243Sobrien /* 23959243Sobrien * Make sure we have 0, 1, 2 open 24059243Sobrien * Otherwise `` jobs will not work... (From knaff@poly.polytechnique.fr) 24159243Sobrien */ 24259243Sobrien { 24359243Sobrien do 244131962Smp if ((f = open(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE)) == -1 && 245131962Smp (f = open("/", O_RDONLY|O_LARGEFILE)) == -1) 24659243Sobrien exit(1); 24759243Sobrien while (f < 3); 24859243Sobrien (void) close(f); 24959243Sobrien } 25059243Sobrien 251131962Smp#ifdef O_TEXT 252131962Smp setmode(0, O_TEXT); 253131962Smp#endif 254131962Smp 25559243Sobrien osinit(); /* Os dependent initialization */ 25659243Sobrien 25759243Sobrien 25859243Sobrien { 25959243Sobrien char *t; 26059243Sobrien 26159243Sobrien t = strrchr(argv[0], '/'); 26269408Sache#ifdef WINNT_NATIVE 26359243Sobrien { 26459243Sobrien char *s = strrchr(argv[0], '\\'); 26559243Sobrien if (s) 26659243Sobrien t = s; 26759243Sobrien } 26869408Sache#endif /* WINNT_NATIVE */ 26959243Sobrien t = t ? t + 1 : argv[0]; 27059243Sobrien if (*t == '-') t++; 27159243Sobrien progname = strsave((t && *t) ? t : tcshstr); /* never want a null */ 27259243Sobrien tcsh = strcmp(progname, tcshstr) == 0; 27359243Sobrien } 27459243Sobrien 27559243Sobrien /* 27659243Sobrien * Initialize non constant strings 27759243Sobrien */ 27859243Sobrien#ifdef _PATH_BSHELL 27959243Sobrien STR_BSHELL = SAVE(_PATH_BSHELL); 28059243Sobrien#endif 28159243Sobrien#ifdef _PATH_TCSHELL 28259243Sobrien STR_SHELLPATH = SAVE(_PATH_TCSHELL); 28359243Sobrien#else 28459243Sobrien# ifdef _PATH_CSHELL 28559243Sobrien STR_SHELLPATH = SAVE(_PATH_CSHELL); 28659243Sobrien# endif 28759243Sobrien#endif 28859243Sobrien STR_environ = blk2short(environ); 28959243Sobrien environ = short2blk(STR_environ); /* So that we can free it */ 29059243Sobrien STR_WORD_CHARS = SAVE(WORD_CHARS); 29159243Sobrien 29259243Sobrien HIST = '!'; 29359243Sobrien HISTSUB = '^'; 29459243Sobrien PRCH = '>'; 29559243Sobrien PRCHROOT = '#'; 29659243Sobrien word_chars = STR_WORD_CHARS; 29759243Sobrien bslash_quote = 0; /* PWP: do tcsh-style backslash quoting? */ 29859243Sobrien 29959243Sobrien /* Default history size to 100 */ 30059243Sobrien set(STRhistory, SAVE("100"), VAR_READWRITE); 30159243Sobrien 30259243Sobrien tempv = argv; 30359243Sobrien ffile = SAVE(tempv[0]); 30459243Sobrien dolzero = 0; 30559243Sobrien if (eq(ffile, STRaout)) /* A.out's are quittable */ 30659243Sobrien quitit = 1; 30759243Sobrien uid = getuid(); 30859243Sobrien gid = getgid(); 30959243Sobrien euid = geteuid(); 31059243Sobrien egid = getegid(); 31159243Sobrien /* 31259243Sobrien * We are a login shell if: 1. we were invoked as -<something> with 31359243Sobrien * optional arguments 2. or we were invoked only with the -l flag 31459243Sobrien */ 31559243Sobrien loginsh = (**tempv == '-') || (argc == 2 && 31659243Sobrien tempv[1][0] == '-' && tempv[1][1] == 'l' && 31759243Sobrien tempv[1][2] == '\0'); 31859243Sobrien#ifdef _VMS_POSIX 31959243Sobrien /* No better way to find if we are a login shell */ 32059243Sobrien if (!loginsh) { 32159243Sobrien loginsh = (argc == 1 && getppid() == 1); 32259243Sobrien **tempv = '-'; /* Avoid giving VMS an acidic stomach */ 32359243Sobrien } 32459243Sobrien#endif /* _VMS_POSIX */ 32559243Sobrien 32659243Sobrien if (loginsh && **tempv != '-') { 32759243Sobrien /* 32859243Sobrien * Mangle the argv space 32959243Sobrien */ 33059243Sobrien tempv[1][0] = '\0'; 33159243Sobrien tempv[1][1] = '\0'; 33259243Sobrien tempv[1] = NULL; 33359243Sobrien for (tcp = *tempv; *tcp++;) 33459243Sobrien continue; 33559243Sobrien for (tcp--; tcp >= *tempv; tcp--) 33659243Sobrien tcp[1] = tcp[0]; 33759243Sobrien *++tcp = '-'; 33859243Sobrien argc--; 33959243Sobrien } 34059243Sobrien if (loginsh) { 34159243Sobrien (void) time(&chktim); 34259243Sobrien set(STRloginsh, Strsave(STRNULL), VAR_READWRITE); 34359243Sobrien } 34459243Sobrien 34559243Sobrien AsciiOnly = 1; 34659243Sobrien NoNLSRebind = getenv("NOREBIND") != NULL; 34759243Sobrien#ifdef NLS 34859243Sobrien# ifdef SETLOCALEBUG 34959243Sobrien dont_free = 1; 35059243Sobrien# endif /* SETLOCALEBUG */ 35159243Sobrien (void) setlocale(LC_ALL, ""); 35259243Sobrien# ifdef LC_COLLATE 35359243Sobrien (void) setlocale(LC_COLLATE, ""); 35459243Sobrien# endif 35559243Sobrien# ifdef SETLOCALEBUG 35659243Sobrien dont_free = 0; 35759243Sobrien# endif /* SETLOCALEBUG */ 35859243Sobrien# ifdef STRCOLLBUG 35959243Sobrien fix_strcoll_bug(); 36059243Sobrien# endif /* STRCOLLBUG */ 36159243Sobrien 36259243Sobrien { 36359243Sobrien int k; 36459243Sobrien 36559243Sobrien for (k = 0200; k <= 0377 && !Isprint(k); k++) 36659243Sobrien continue; 36759243Sobrien AsciiOnly = k > 0377; 36859243Sobrien } 36959243Sobrien#else 37059243Sobrien AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL; 37159243Sobrien#endif /* NLS */ 37259243Sobrien if (MapsAreInited && !NLSMapsAreInited) 37359243Sobrien ed_InitNLSMaps(); 37459243Sobrien ResetArrowKeys(); 37559243Sobrien 37659243Sobrien /* 37759243Sobrien * Initialize for periodic command intervals. Also, initialize the dummy 37859243Sobrien * tty list for login-watch. 37959243Sobrien */ 38059243Sobrien (void) time(&t_period); 38159243Sobrien#ifndef HAVENOUTMP 38259243Sobrien initwatch(); 38359243Sobrien#endif /* !HAVENOUTMP */ 38459243Sobrien 38559243Sobrien#if defined(alliant) 38659243Sobrien /* 38759243Sobrien * From: Jim Pace <jdp@research.att.com> 38859243Sobrien * tcsh does not work properly on the alliants through an rlogin session. 38959243Sobrien * The shell generally hangs. Also, reference to the controlling terminal 39059243Sobrien * does not work ( ie: echo foo > /dev/tty ). 39159243Sobrien * 39259243Sobrien * A security feature was added to rlogind affecting FX/80's Concentrix 39359243Sobrien * from revision 5.5.xx upwards (through 5.7 where this fix was implemented) 39459243Sobrien * This security change also affects the FX/2800 series. 39559243Sobrien * The security change to rlogind requires the process group of an rlogin 39659243Sobrien * session become disassociated with the tty in rlogind. 39759243Sobrien * 39859243Sobrien * The changes needed are: 39959243Sobrien * 1. set the process group 40059243Sobrien * 2. reenable the control terminal 40159243Sobrien */ 40259243Sobrien if (loginsh && isatty(SHIN)) { 40359243Sobrien ttyn = (char *) ttyname(SHIN); 40459243Sobrien (void) close(SHIN); 405131962Smp SHIN = open(ttyn, O_RDWR|O_LARGEFILE); 40659243Sobrien shpgrp = getpid(); 40759243Sobrien (void) ioctl (SHIN, TIOCSPGRP, (ioctl_t) &shpgrp); 40859243Sobrien (void) setpgid(0, shpgrp); 40959243Sobrien } 41059243Sobrien#endif /* alliant */ 41159243Sobrien 41259243Sobrien /* 41359243Sobrien * Move the descriptors to safe places. The variable didfds is 0 while we 41459243Sobrien * have only FSH* to work with. When didfds is true, we have 0,1,2 and 41559243Sobrien * prefer to use these. 41659243Sobrien */ 41759243Sobrien initdesc(); 41859243Sobrien 41959243Sobrien /* 42059243Sobrien * Get and set the tty now 42159243Sobrien */ 42259243Sobrien if ((ttyn = ttyname(SHIN)) != NULL) { 42359243Sobrien /* 42459243Sobrien * Could use rindex to get rid of other possible path components, but 42559243Sobrien * hpux preserves the subdirectory /pty/ when storing the tty name in 42659243Sobrien * utmp, so we keep it too. 42759243Sobrien */ 42859243Sobrien if (strncmp(ttyn, "/dev/", 5) == 0) 42959243Sobrien set(STRtty, cp = SAVE(ttyn + 5), VAR_READWRITE); 43059243Sobrien else 43159243Sobrien set(STRtty, cp = SAVE(ttyn), VAR_READWRITE); 43259243Sobrien } 43359243Sobrien else 43459243Sobrien set(STRtty, cp = SAVE(""), VAR_READWRITE); 43559243Sobrien /* 43659243Sobrien * Initialize the shell variables. ARGV and PROMPT are initialized later. 43759243Sobrien * STATUS is also munged in several places. CHILD is munged when 43859243Sobrien * forking/waiting 43959243Sobrien */ 44059243Sobrien 44159243Sobrien /* 44259243Sobrien * 7-10-87 Paul Placeway autologout should be set ONLY on login shells and 44359243Sobrien * on shells running as root. Out of these, autologout should NOT be set 44459243Sobrien * for any psudo-terminals (this catches most window systems) and not for 44559243Sobrien * any terminal running X windows. 44659243Sobrien * 44759243Sobrien * At Ohio State, we have had problems with a user having his X session 44859243Sobrien * drop out from under him (on a Sun) because the shell in his master 44959243Sobrien * xterm timed out and exited. 45059243Sobrien * 45159243Sobrien * Really, this should be done with a program external to the shell, that 45259243Sobrien * watches for no activity (and NO running programs, such as dump) on a 45359243Sobrien * terminal for a long peroid of time, and then SIGHUPS the shell on that 45459243Sobrien * terminal. 45559243Sobrien * 45659243Sobrien * bugfix by Rich Salz <rsalz@PINEAPPLE.BBN.COM>: For root rsh things 45759243Sobrien * allways first check to see if loginsh or really root, then do things 45859243Sobrien * with ttyname() 45959243Sobrien * 46059243Sobrien * Also by Jean-Francois Lamy <lamy%ai.toronto.edu@RELAY.CS.NET>: check the 46159243Sobrien * value of cp before using it! ("root can rsh too") 46259243Sobrien * 46359243Sobrien * PWP: keep the nested ifs; the order of the tests matters and a good 46459243Sobrien * (smart) C compiler might re-arange things wrong. 46559243Sobrien */ 46659243Sobrien#ifdef AUTOLOGOUT 46759243Sobrien# ifdef convex 46859243Sobrien if (uid == 0) { 46959243Sobrien /* root always has a 15 minute autologout */ 47059243Sobrien set(STRautologout, Strsave(STRrootdefautologout), VAR_READWRITE); 47159243Sobrien } 47259243Sobrien else 47359243Sobrien if (loginsh) 47459243Sobrien /* users get autologout set to 0 */ 47559243Sobrien set(STRautologout, Strsave(STR0), VAR_READWRITE); 47659243Sobrien# else /* convex */ 47759243Sobrien if (loginsh || (uid == 0)) { 47859243Sobrien if (*cp) { 47959243Sobrien /* only for login shells or root and we must have a tty */ 48059243Sobrien if ((cp2 = Strrchr(cp, (Char) '/')) != NULL) { 48159243Sobrien cp = cp2 + 1; 48259243Sobrien } 48359243Sobrien else 48459243Sobrien cp2 = cp; 48559243Sobrien if (!(((Strncmp(cp2, STRtty, 3) == 0) && Isalpha(cp2[3])) || 48659243Sobrien ((Strncmp(cp, STRpts, 3) == 0) && cp[3] == '/'))) { 48759243Sobrien if (getenv("DISPLAY") == NULL) { 48859243Sobrien /* NOT on X window shells */ 48959243Sobrien set(STRautologout, Strsave(STRdefautologout), 49059243Sobrien VAR_READWRITE); 49159243Sobrien } 49259243Sobrien } 49359243Sobrien } 49459243Sobrien } 49559243Sobrien# endif /* convex */ 49659243Sobrien#endif /* AUTOLOGOUT */ 49759243Sobrien 49859243Sobrien (void) sigset(SIGALRM, alrmcatch); 49959243Sobrien 50059243Sobrien set(STRstatus, Strsave(STR0), VAR_READWRITE); 50159243Sobrien 50259243Sobrien /* 503100616Smp * get and set machine specific environment variables 50459243Sobrien */ 50559243Sobrien getmachine(); 50659243Sobrien 50759243Sobrien 50859243Sobrien /* 50959243Sobrien * Publish the selected echo style 51059243Sobrien */ 511100616Smp#if ECHO_STYLE != BSD_ECHO 512100616Smp if (tcsh) { 513100616Smp# if ECHO_STYLE == NONE_ECHO 514100616Smp set(STRecho_style, Strsave(STRnone), VAR_READWRITE); 515100616Smp# endif /* ECHO_STYLE == NONE_ECHO */ 516100616Smp# if ECHO_STYLE == SYSV_ECHO 517100616Smp set(STRecho_style, Strsave(STRsysv), VAR_READWRITE); 518100616Smp# endif /* ECHO_STYLE == SYSV_ECHO */ 519100616Smp# if ECHO_STYLE == BOTH_ECHO 520100616Smp set(STRecho_style, Strsave(STRboth), VAR_READWRITE); 521100616Smp# endif /* ECHO_STYLE == BOTH_ECHO */ 522100616Smp } else 523100616Smp#endif /* ECHO_STYLE != BSD_ECHO */ 524100616Smp set(STRecho_style, Strsave(STRbsd), VAR_READWRITE); 52559243Sobrien 52659243Sobrien /* 52759243Sobrien * increment the shell level. 52859243Sobrien */ 52959243Sobrien shlvl(1); 53059243Sobrien 53173393Skris if ((tcp = getenv("HOME")) != NULL) { 53273393Skris if (strlen(tcp) >= MAXPATHLEN) { 53373393Skris struct passwd *pw; 53473393Skris if ((pw = getpwuid(getuid())) != NULL) 53573393Skris cp = quote(SAVE(pw->pw_dir)); 53673393Skris else { 53773393Skris tcp[MAXPATHLEN-1] = '\0'; 53873393Skris cp = quote(SAVE(tcp)); 53973393Skris } 54073393Skris } else { 54173393Skris cp = quote(SAVE(tcp)); 54273393Skris } 54373393Skris } else 54459243Sobrien cp = NULL; 54573393Skris 54659243Sobrien if (cp == NULL) 54759243Sobrien fast = 1; /* No home -> can't read scripts */ 54859243Sobrien else 54959243Sobrien set(STRhome, cp, VAR_READWRITE); 55073393Skris 55159243Sobrien dinit(cp); /* dinit thinks that HOME == cwd in a login 55259243Sobrien * shell */ 55359243Sobrien /* 55459243Sobrien * Grab other useful things from the environment. Should we grab 55559243Sobrien * everything?? 55659243Sobrien */ 55759243Sobrien { 55859243Sobrien char *cln, *cus, *cgr; 55959243Sobrien Char buff[BUFSIZE]; 56059243Sobrien struct passwd *pw; 56159243Sobrien struct group *gr; 56259243Sobrien 56359243Sobrien 56459243Sobrien#ifdef apollo 56559243Sobrien int oid = getoid(); 56659243Sobrien 56759243Sobrien (void) Itoa(oid, buff, 0, 0); 56859243Sobrien set(STRoid, Strsave(buff), VAR_READWRITE); 56959243Sobrien#endif /* apollo */ 57059243Sobrien 57159243Sobrien (void) Itoa(uid, buff, 0, 0); 57259243Sobrien set(STRuid, Strsave(buff), VAR_READWRITE); 57359243Sobrien 57459243Sobrien (void) Itoa(gid, buff, 0, 0); 57559243Sobrien set(STRgid, Strsave(buff), VAR_READWRITE); 57659243Sobrien 57759243Sobrien cln = getenv("LOGNAME"); 57859243Sobrien cus = getenv("USER"); 57959243Sobrien if (cus != NULL) 58059243Sobrien set(STRuser, quote(SAVE(cus)), VAR_READWRITE); 58159243Sobrien else if (cln != NULL) 58259243Sobrien set(STRuser, quote(SAVE(cln)), VAR_READWRITE); 58359243Sobrien else if ((pw = getpwuid(uid)) == NULL) 58459243Sobrien set(STRuser, SAVE("unknown"), VAR_READWRITE); 58559243Sobrien else 58659243Sobrien set(STRuser, SAVE(pw->pw_name), VAR_READWRITE); 58759243Sobrien if (cln == NULL) 58859243Sobrien tsetenv(STRLOGNAME, varval(STRuser)); 58959243Sobrien if (cus == NULL) 59059243Sobrien tsetenv(STRKUSER, varval(STRuser)); 59159243Sobrien 59259243Sobrien cgr = getenv("GROUP"); 59359243Sobrien if (cgr != NULL) 59459243Sobrien set(STRgroup, quote(SAVE(cgr)), VAR_READWRITE); 59559243Sobrien else if ((gr = getgrgid(gid)) == NULL) 59659243Sobrien set(STRgroup, SAVE("unknown"), VAR_READWRITE); 59759243Sobrien else 59859243Sobrien set(STRgroup, SAVE(gr->gr_name), VAR_READWRITE); 59959243Sobrien if (cgr == NULL) 60059243Sobrien tsetenv(STRKGROUP, varval(STRgroup)); 60159243Sobrien } 60259243Sobrien 60359243Sobrien /* 60459243Sobrien * HOST may be wrong, since rexd transports the entire environment on sun 60559243Sobrien * 3.x Just set it again 60659243Sobrien */ 60759243Sobrien { 60859243Sobrien char cbuff[MAXHOSTNAMELEN]; 60959243Sobrien 61059243Sobrien if (gethostname(cbuff, sizeof(cbuff)) >= 0) { 61159243Sobrien cbuff[sizeof(cbuff) - 1] = '\0'; /* just in case */ 61259243Sobrien tsetenv(STRHOST, str2short(cbuff)); 61359243Sobrien } 61459243Sobrien else 61559243Sobrien tsetenv(STRHOST, str2short("unknown")); 61659243Sobrien } 61759243Sobrien 61859243Sobrien 61959243Sobrien#ifdef REMOTEHOST 62059243Sobrien /* 62159243Sobrien * Try to determine the remote host we were logged in from. 62259243Sobrien */ 62359243Sobrien remotehost(); 62459243Sobrien#endif /* REMOTEHOST */ 62559243Sobrien 62659243Sobrien#ifdef apollo 62759243Sobrien if ((tcp = getenv("SYSTYPE")) == NULL) 62859243Sobrien tcp = "bsd4.3"; 62959243Sobrien tsetenv(STRSYSTYPE, quote(str2short(tcp))); 63059243Sobrien#endif /* apollo */ 63159243Sobrien 63259243Sobrien /* 63359243Sobrien * set editing on by default, unless running under Emacs as an inferior 63459243Sobrien * shell. 63559243Sobrien * We try to do this intelligently. If $TERM is available, then it 63659243Sobrien * should determine if we should edit or not. $TERM is preserved 63759243Sobrien * across rlogin sessions, so we will not get confused if we rlogin 63859243Sobrien * under an emacs shell. Another advantage is that if we run an 63959243Sobrien * xterm under an emacs shell, then the $TERM will be set to 64059243Sobrien * xterm, so we are going to want to edit. Unfortunately emacs 64159243Sobrien * does not restore all the tty modes, so xterm is not very well 64259243Sobrien * set up. But this is not the shell's fault. 64359243Sobrien * Also don't edit if $TERM == wm, for when we're running under an ATK app. 64459243Sobrien * Finally, emacs compiled under terminfo, sets the terminal to dumb, 64559243Sobrien * so disable editing for that too. 64659243Sobrien * 64759243Sobrien * Unfortunately, in some cases the initial $TERM setting is "unknown", 64859243Sobrien * "dumb", or "network" which is then changed in the user's startup files. 64959243Sobrien * We fix this by setting noediting here if $TERM is unknown/dumb and 65059243Sobrien * if noediting is set, we switch on editing if $TERM is changed. 65159243Sobrien */ 65259243Sobrien if ((tcp = getenv("TERM")) != NULL) { 65359243Sobrien set(STRterm, quote(SAVE(tcp)), VAR_READWRITE); 65459243Sobrien noediting = strcmp(tcp, "unknown") == 0 || strcmp(tcp, "dumb") == 0 || 65559243Sobrien strcmp(tcp, "network") == 0; 65659243Sobrien editing = strcmp(tcp, "emacs") != 0 && strcmp(tcp, "wm") != 0 && 65759243Sobrien !noediting; 65859243Sobrien } 65959243Sobrien else { 66059243Sobrien noediting = 0; 66159243Sobrien editing = ((tcp = getenv("EMACS")) == NULL || strcmp(tcp, "t") != 0); 66259243Sobrien } 66359243Sobrien 66459243Sobrien /* 66559243Sobrien * The 'edit' variable is either set or unset. It doesn't 66659243Sobrien * need a value. Making it 'emacs' might be confusing. 66759243Sobrien */ 66859243Sobrien if (editing) 66959243Sobrien set(STRedit, Strsave(STRNULL), VAR_READWRITE); 67059243Sobrien 67159243Sobrien 67259243Sobrien /* 67359243Sobrien * still more mutability: make the complete routine automatically add the 67459243Sobrien * suffix of file names... 67559243Sobrien */ 67659243Sobrien set(STRaddsuffix, Strsave(STRNULL), VAR_READWRITE); 67759243Sobrien 67859243Sobrien /* 67983098Smp * Random default kill ring size 68083098Smp */ 68183098Smp set(STRkillring, SAVE("30"), VAR_READWRITE); 68283098Smp 68383098Smp /* 68459243Sobrien * Re-initialize path if set in environment 68559243Sobrien */ 68659243Sobrien if ((tcp = getenv("PATH")) == NULL) 68759243Sobrien#ifdef _PATH_DEFPATH 68859243Sobrien importpath(str2short(_PATH_DEFPATH)); 68959243Sobrien#else /* !_PATH_DEFPATH */ 69059243Sobrien setq(STRpath, defaultpath(), &shvhed, VAR_READWRITE); 69159243Sobrien#endif /* _PATH_DEFPATH */ 69259243Sobrien else 69359243Sobrien /* Importpath() allocates memory for the path, and the 69459243Sobrien * returned pointer from SAVE() was discarded, so 69559243Sobrien * this was a memory leak.. (sg) 69659243Sobrien * 69759243Sobrien * importpath(SAVE(tcp)); 69859243Sobrien */ 69959243Sobrien importpath(str2short(tcp)); 70059243Sobrien 70159243Sobrien 70259243Sobrien { 70359243Sobrien /* If the SHELL environment variable ends with "tcsh", set 70459243Sobrien * STRshell to the same path. This is to facilitate using 70559243Sobrien * the executable in environments where the compiled-in 70659243Sobrien * default isn't appropriate (sg). 70759243Sobrien */ 70859243Sobrien 70959243Sobrien int sh_len = 0; 71059243Sobrien 71159243Sobrien if ((tcp = getenv("SHELL")) != NULL) { 71259243Sobrien sh_len = strlen(tcp); 71359243Sobrien if ((sh_len >= 5 && strcmp(tcp + (sh_len - 5), "/tcsh") == 0) || 71459243Sobrien (!tcsh && sh_len >= 4 && strcmp(tcp + (sh_len - 4), "/csh") == 0)) 71559243Sobrien set(STRshell, quote(SAVE(tcp)), VAR_READWRITE); 71659243Sobrien else 71759243Sobrien sh_len = 0; 71859243Sobrien } 71959243Sobrien if (sh_len == 0) 72059243Sobrien set(STRshell, Strsave(STR_SHELLPATH), VAR_READWRITE); 72159243Sobrien } 72259243Sobrien 72359243Sobrien#ifdef COLOR_LS_F 72459243Sobrien if ((tcp = getenv("LS_COLORS")) != NULL) 72559243Sobrien parseLS_COLORS(str2short(tcp)); 72659243Sobrien#endif /* COLOR_LS_F */ 72759243Sobrien 72859243Sobrien doldol = putn((int) getpid()); /* For $$ */ 72969408Sache#ifdef WINNT_NATIVE 73059243Sobrien { 73159243Sobrien char *strtmp1, strtmp2[MAXPATHLEN]; 73259243Sobrien if ((strtmp1 = getenv("TMP")) != NULL) 73359243Sobrien wsprintf(strtmp2, "%s/%s", strtmp1, "sh"); 73459243Sobrien shtemp = Strspl(SAVE(strtmp2), doldol); /* For << */ 73559243Sobrien } 73669408Sache#else /* !WINNT_NATIVE */ 73759243Sobrien shtemp = Strspl(STRtmpsh, doldol); /* For << */ 73869408Sache#endif /* WINNT_NATIVE */ 73959243Sobrien 74059243Sobrien /* 74159243Sobrien * Record the interrupt states from the parent process. If the parent is 74259243Sobrien * non-interruptible our hand must be forced or we (and our children) won't 74359243Sobrien * be either. Our children inherit termination from our parent. We catch it 74459243Sobrien * only if we are the login shell. 74559243Sobrien */ 74659243Sobrien#ifdef BSDSIGS 74759243Sobrien /* 74859243Sobrien * PURIFY-2 claims that osv does not get 74959243Sobrien * initialized after the sigvec call 75059243Sobrien */ 75159243Sobrien setzero((char*) &osv, sizeof(osv)); 75259243Sobrien /* parents interruptibility */ 75359243Sobrien (void) mysigvec(SIGINT, NULL, &osv); 75459243Sobrien parintr = (signalfun_t) osv.sv_handler; 75559243Sobrien (void) mysigvec(SIGTERM, NULL, &osv); 75659243Sobrien parterm = (signalfun_t) osv.sv_handler; 75759243Sobrien#else /* BSDSIGS */ 75859243Sobrien parintr = signal(SIGINT, SIG_IGN); /* parents interruptibility */ 75959243Sobrien (void) sigset(SIGINT, parintr); /* ... restore */ 76059243Sobrien 76159243Sobrien# ifdef COHERENT 76259243Sobrien if (loginsh) /* it seems that SIGTERM is always set to SIG_IGN by */ 76359243Sobrien /* init/getty so it should be set to SIG_DFL - there may be */ 76459243Sobrien /* a better fix for this. */ 76559243Sobrien parterm = SIG_DFL; 76659243Sobrien else 76759243Sobrien# else /* !COHERENT */ 76859243Sobrien parterm = signal(SIGTERM, SIG_IGN); /* parents terminability */ 76959243Sobrien# endif /* COHERENT */ 77059243Sobrien (void) sigset(SIGTERM, parterm); /* ... restore */ 77159243Sobrien 77259243Sobrien#endif /* BSDSIGS */ 77359243Sobrien 77459243Sobrien 77559243Sobrien#ifdef TCF 77659243Sobrien /* Enable process migration on ourselves and our progeny */ 77759243Sobrien (void) signal(SIGMIGRATE, SIG_DFL); 77859243Sobrien#endif /* TCF */ 77959243Sobrien 78059243Sobrien /* 78169408Sache * dspkanji/dspmbyte autosetting 78269408Sache */ 78369408Sache /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 78469408Sache#if defined(DSPMBYTE) 78569408Sache#if defined(NLS) && defined(LC_CTYPE) 78669408Sache if (((tcp = setlocale(LC_CTYPE, NULL)) != NULL || (tcp = getenv("LANG")) != NULL) && !adrof(CHECK_MBYTEVAR)) { 78769408Sache#else 78869408Sache if ((tcp = getenv("LANG")) != NULL && !adrof(CHECK_MBYTEVAR)) { 78969408Sache#endif 79069408Sache autoset_dspmbyte(str2short(tcp)); 79169408Sache } 79269408Sache#if defined(WINNT_NATIVE) 79369408Sache else if (!adrof(CHECK_MBYTEVAR)) 79469408Sache nt_autoset_dspmbyte(); 79569408Sache#endif /* WINNT_NATIVE */ 79669408Sache#endif 79769408Sache 798100616Smp fix_version(); /* publish the shell version */ 799100616Smp 800100616Smp if (argc > 1 && strcmp(argv[1], "--version") == 0) { 801100616Smp xprintf("%S\n", varval(STRversion)); 802100616Smp xexit(0); 803100616Smp } 80469408Sache /* 80559243Sobrien * Process the arguments. 80659243Sobrien * 80759243Sobrien * Note that processing of -v/-x is actually delayed till after script 80859243Sobrien * processing. 80959243Sobrien * 81059243Sobrien * We set the first character of our name to be '-' if we are a shell 81159243Sobrien * running interruptible commands. Many programs which examine ps'es 81259243Sobrien * use this to filter such shells out. 81359243Sobrien */ 81459243Sobrien argc--, tempv++; 81559243Sobrien while (argc > 0 && (tcp = tempv[0])[0] == '-' && 81659243Sobrien *++tcp != '\0' && !batch) { 81759243Sobrien do 81859243Sobrien switch (*tcp++) { 81959243Sobrien 82059243Sobrien case 0: /* - Interruptible, no prompt */ 82159243Sobrien prompt = 0; 82259243Sobrien setintr = 1; 82359243Sobrien nofile = 1; 82459243Sobrien break; 82559243Sobrien 82659243Sobrien case 'b': /* -b Next arg is input file */ 82759243Sobrien batch = 1; 82859243Sobrien break; 82959243Sobrien 83059243Sobrien case 'c': /* -c Command input from arg */ 83159243Sobrien if (argc == 1) 83259243Sobrien xexit(0); 83359243Sobrien argc--, tempv++; 83459243Sobrien#ifdef M_XENIX 83559243Sobrien /* Xenix Vi bug: 83659243Sobrien it relies on a 7 bit environment (/bin/sh), so it 83759243Sobrien pass ascii arguments with the 8th bit set */ 83859243Sobrien if (!strcmp(argv[0], "sh")) 83959243Sobrien { 84059243Sobrien char *p; 84159243Sobrien 84259243Sobrien for (p = tempv[0]; *p; ++p) 84359243Sobrien *p &= ASCII; 84459243Sobrien } 84559243Sobrien#endif 84659243Sobrien arginp = SAVE(tempv[0]); 84759243Sobrien 84859243Sobrien /* 84959243Sobrien * we put the command into a variable 85059243Sobrien */ 85159243Sobrien if (arginp != NULL) 85259243Sobrien set(STRcommand, quote(Strsave(arginp)), VAR_READWRITE); 85359243Sobrien 85459243Sobrien /* 85559243Sobrien * * Give an error on -c arguments that end in * backslash to 85659243Sobrien * ensure that you don't make * nonportable csh scripts. 85759243Sobrien */ 85859243Sobrien { 85959243Sobrien register int count; 86059243Sobrien 86159243Sobrien cp = arginp + Strlen(arginp); 86259243Sobrien count = 0; 86359243Sobrien while (cp > arginp && *--cp == '\\') 86459243Sobrien ++count; 86559243Sobrien if ((count & 1) != 0) { 86659243Sobrien exiterr = 1; 86759243Sobrien stderror(ERR_ARGC); 86859243Sobrien } 86959243Sobrien } 87059243Sobrien prompt = 0; 87159243Sobrien nofile = 1; 87259243Sobrien break; 87359243Sobrien case 'd': /* -d Load directory stack from file */ 87459243Sobrien rdirs = 1; 87559243Sobrien break; 87659243Sobrien 87759243Sobrien#ifdef apollo 87859243Sobrien case 'D': /* -D Define environment variable */ 87959243Sobrien { 88059243Sobrien register Char *dp; 88159243Sobrien 88259243Sobrien cp = str2short(tcp); 88359243Sobrien if (dp = Strchr(cp, '=')) { 88459243Sobrien *dp++ = '\0'; 88559243Sobrien tsetenv(cp, dp); 88659243Sobrien } 88759243Sobrien else 88859243Sobrien tsetenv(cp, STRNULL); 88959243Sobrien } 89059243Sobrien *tcp = '\0'; /* done with this argument */ 89159243Sobrien break; 89259243Sobrien#endif /* apollo */ 89359243Sobrien 89459243Sobrien case 'e': /* -e Exit on any error */ 89559243Sobrien exiterr = 1; 89659243Sobrien break; 89759243Sobrien 89859243Sobrien case 'f': /* -f Fast start */ 89959243Sobrien fast = 1; 90059243Sobrien break; 90159243Sobrien 90259243Sobrien case 'i': /* -i Interactive, even if !intty */ 90359243Sobrien intact = 1; 90459243Sobrien nofile = 1; 90559243Sobrien break; 90659243Sobrien 90759243Sobrien case 'm': /* -m read .cshrc (from su) */ 90859243Sobrien mflag = 1; 90959243Sobrien break; 91059243Sobrien 91159243Sobrien case 'n': /* -n Don't execute */ 91259243Sobrien noexec = 1; 91359243Sobrien break; 91459243Sobrien 91559243Sobrien case 'q': /* -q (Undoc'd) ... die on quit */ 91659243Sobrien quitit = 1; 91759243Sobrien break; 91859243Sobrien 91959243Sobrien case 's': /* -s Read from std input */ 92059243Sobrien nofile = 1; 92159243Sobrien break; 92259243Sobrien 92359243Sobrien case 't': /* -t Read one line from input */ 92459243Sobrien onelflg = 2; 92559243Sobrien prompt = 0; 92659243Sobrien nofile = 1; 92759243Sobrien break; 92859243Sobrien 92959243Sobrien case 'v': /* -v Echo hist expanded input */ 93059243Sobrien nverbose = 1; /* ... later */ 93159243Sobrien break; 93259243Sobrien 93359243Sobrien case 'x': /* -x Echo just before execution */ 93459243Sobrien nexececho = 1; /* ... later */ 93559243Sobrien break; 93659243Sobrien 93759243Sobrien case 'V': /* -V Echo hist expanded input */ 93859243Sobrien setNS(STRverbose); /* NOW! */ 93959243Sobrien break; 94059243Sobrien 94159243Sobrien case 'X': /* -X Echo just before execution */ 94259243Sobrien setNS(STRecho); /* NOW! */ 94359243Sobrien break; 94459243Sobrien 94559243Sobrien case 'F': /* Undocumented flag */ 94659243Sobrien /* 94759243Sobrien * This will cause children to be created using fork instead of 94859243Sobrien * vfork. 94959243Sobrien */ 95059243Sobrien use_fork = 1; 95159243Sobrien break; 95259243Sobrien 95359243Sobrien case ' ': 95459243Sobrien case '\t': 95559243Sobrien /* 95659243Sobrien * for O/S's that don't do the argument parsing right in 95759243Sobrien * "#!/foo -f " scripts 95859243Sobrien */ 95959243Sobrien break; 96059243Sobrien 96159243Sobrien default: /* Unknown command option */ 96259243Sobrien exiterr = 1; 96359243Sobrien stderror(ERR_TCSHUSAGE, tcp-1, progname); 96459243Sobrien break; 96559243Sobrien 96659243Sobrien } while (*tcp); 96759243Sobrien tempv++, argc--; 96859243Sobrien } 96959243Sobrien 97059243Sobrien if (quitit) /* With all due haste, for debugging */ 97159243Sobrien (void) signal(SIGQUIT, SIG_DFL); 97259243Sobrien 97359243Sobrien /* 97459243Sobrien * Unless prevented by -, -c, -i, -s, or -t, if there are remaining 97559243Sobrien * arguments the first of them is the name of a shell file from which to 97659243Sobrien * read commands. 97759243Sobrien */ 97859243Sobrien if (nofile == 0 && argc > 0) { 979131962Smp nofile = open(tempv[0], O_RDONLY|O_LARGEFILE); 98059243Sobrien if (nofile < 0) { 98159243Sobrien child = 1; /* So this ... */ 98259243Sobrien /* ... doesn't return */ 98359243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 98459243Sobrien } 985131962Smp#ifdef O_TEXT 986131962Smp setmode(nofile, O_TEXT); 987131962Smp#endif 98859243Sobrien if (ffile != NULL) 98959243Sobrien xfree((ptr_t) ffile); 99059243Sobrien dolzero = 1; 99159243Sobrien ffile = SAVE(tempv[0]); 99259243Sobrien /* 99359243Sobrien * Replace FSHIN. Handle /dev/std{in,out,err} specially 99459243Sobrien * since once they are closed we cannot open them again. 99559243Sobrien * In that case we use our own saved descriptors 99659243Sobrien */ 99759243Sobrien if ((SHIN = dmove(nofile, FSHIN)) < 0) 99859243Sobrien switch(nofile) { 99959243Sobrien case 0: 100059243Sobrien SHIN = FSHIN; 100159243Sobrien break; 100259243Sobrien case 1: 100359243Sobrien SHIN = FSHOUT; 100459243Sobrien break; 100559243Sobrien case 2: 100659243Sobrien SHIN = FSHDIAG; 100759243Sobrien break; 100859243Sobrien default: 100959243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 101059243Sobrien break; 101159243Sobrien } 101259243Sobrien (void) close_on_exec(SHIN, 1); 101359243Sobrien prompt = 0; 101459243Sobrien /* argc not used any more */ tempv++; 101559243Sobrien } 101659243Sobrien 1017100616Smp /* 1018100616Smp * Call to closem() used to be part of initdesc(). Now called below where 1019100616Smp * the script name argument has become stdin. Kernel may have used a file 1020100616Smp * descriptor to hold the name of the script (setuid case) and this name 1021100616Smp * mustn't be lost by closing the fd too soon. 1022100616Smp */ 1023100616Smp closem(); 102459243Sobrien 102559243Sobrien /* 102659243Sobrien * Consider input a tty if it really is or we are interactive. but not for 102759243Sobrien * editing (christos) 102859243Sobrien */ 102959243Sobrien if (!(intty = isatty(SHIN))) { 103059243Sobrien if (adrof(STRedit)) 103159243Sobrien unsetv(STRedit); 103259243Sobrien editing = 0; 103359243Sobrien } 103459243Sobrien intty |= intact; 103559243Sobrien#ifndef convex 103659243Sobrien if (intty || (intact && isatty(SHOUT))) { 103759243Sobrien if (!batch && (uid != euid || gid != egid)) { 103859243Sobrien errno = EACCES; 103959243Sobrien child = 1; /* So this ... */ 104059243Sobrien /* ... doesn't return */ 104159243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 104259243Sobrien } 104359243Sobrien } 104459243Sobrien#endif /* convex */ 104559243Sobrien isoutatty = isatty(SHOUT); 104659243Sobrien isdiagatty = isatty(SHDIAG); 104759243Sobrien /* 104859243Sobrien * Decide whether we should play with signals or not. If we are explicitly 104959243Sobrien * told (via -i, or -) or we are a login shell (arg0 starts with -) or the 105059243Sobrien * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 105159243Sobrien * Note that in only the login shell is it likely that parent may have set 105259243Sobrien * signals to be ignored 105359243Sobrien */ 105459243Sobrien if (loginsh || intact || (intty && isatty(SHOUT))) 105559243Sobrien setintr = 1; 105659243Sobrien settell(); 105759243Sobrien /* 105859243Sobrien * Save the remaining arguments in argv. 105959243Sobrien */ 106059243Sobrien setq(STRargv, blk2short(tempv), &shvhed, VAR_READWRITE); 106159243Sobrien 106259243Sobrien /* 106359243Sobrien * Set up the prompt. 106459243Sobrien */ 106559243Sobrien if (prompt) { 106659243Sobrien if (tcsh) 106759243Sobrien set(STRprompt, Strsave(STRdeftcshprompt), VAR_READWRITE); 106859243Sobrien else 106959243Sobrien set(STRprompt, Strsave(STRdefcshprompt), VAR_READWRITE); 107059243Sobrien /* that's a meta-questionmark */ 107159243Sobrien set(STRprompt2, Strsave(STRmquestion), VAR_READWRITE); 107259243Sobrien set(STRprompt3, Strsave(STRKCORRECT), VAR_READWRITE); 107359243Sobrien } 107459243Sobrien 107559243Sobrien /* 107659243Sobrien * If we are an interactive shell, then start fiddling with the signals; 107759243Sobrien * this is a tricky game. 107859243Sobrien */ 107959243Sobrien shpgrp = mygetpgrp(); 108059243Sobrien opgrp = tpgrp = -1; 108159243Sobrien if (setintr) { 108259243Sobrien signalfun_t osig; 108359243Sobrien **argv = '-'; 108459243Sobrien if (!quitit) /* Wary! */ 108559243Sobrien (void) signal(SIGQUIT, SIG_IGN); 108659243Sobrien (void) sigset(SIGINT, pintr); 108759243Sobrien (void) sighold(SIGINT); 108859243Sobrien (void) signal(SIGTERM, SIG_IGN); 108959243Sobrien 109059243Sobrien /* 109159243Sobrien * No reason I can see not to save history on all these events.. 109259243Sobrien * Most usual occurrence is in a window system, where we're not a login 109359243Sobrien * shell, but might as well be... (sg) 109459243Sobrien * But there might be races when lots of shells exit together... 109559243Sobrien * [this is also incompatible]. 109659243Sobrien * We have to be mre careful here. If the parent wants to 109759243Sobrien * ignore the signals then we leave them untouched... 109859243Sobrien * We also only setup the handlers for shells that are trully 109959243Sobrien * interactive. 110059243Sobrien */ 110159243Sobrien osig = signal(SIGHUP, phup); /* exit processing on HUP */ 110259243Sobrien if (!loginsh && osig == SIG_IGN) 110359243Sobrien (void) signal(SIGHUP, osig); 110459243Sobrien#ifdef SIGXCPU 110559243Sobrien osig = signal(SIGXCPU, phup); /* exit processing on XCPU */ 110659243Sobrien if (!loginsh && osig == SIG_IGN) 110759243Sobrien (void) signal(SIGXCPU, osig); 110859243Sobrien#endif 110959243Sobrien#ifdef SIGXFSZ 111059243Sobrien osig = signal(SIGXFSZ, phup); /* exit processing on XFSZ */ 111159243Sobrien if (!loginsh && osig == SIG_IGN) 111259243Sobrien (void) signal(SIGXFSZ, osig); 111359243Sobrien#endif 111459243Sobrien 111559243Sobrien if (quitit == 0 && arginp == 0) { 111659243Sobrien#ifdef SIGTSTP 111759243Sobrien (void) signal(SIGTSTP, SIG_IGN); 111859243Sobrien#endif 111959243Sobrien#ifdef SIGTTIN 112059243Sobrien (void) signal(SIGTTIN, SIG_IGN); 112159243Sobrien#endif 112259243Sobrien#ifdef SIGTTOU 112359243Sobrien (void) signal(SIGTTOU, SIG_IGN); 112459243Sobrien#endif 112559243Sobrien /* 112659243Sobrien * Wait till in foreground, in case someone stupidly runs csh & 112759243Sobrien * dont want to try to grab away the tty. 112859243Sobrien */ 112959243Sobrien if (isatty(FSHDIAG)) 113059243Sobrien f = FSHDIAG; 113159243Sobrien else if (isatty(FSHOUT)) 113259243Sobrien f = FSHOUT; 113359243Sobrien else if (isatty(OLDSTD)) 113459243Sobrien f = OLDSTD; 113559243Sobrien else 113659243Sobrien f = -1; 113759243Sobrien 113859243Sobrien#ifdef NeXT 113959243Sobrien /* NeXT 2.0 /usr/etc/rlogind, does not set our process group! */ 114059243Sobrien if (shpgrp == 0) { 114159243Sobrien shpgrp = getpid(); 114259243Sobrien (void) setpgid(0, shpgrp); 114359243Sobrien (void) tcsetpgrp(f, shpgrp); 114459243Sobrien } 114559243Sobrien#endif /* NeXT */ 114659243Sobrien#ifdef BSDJOBS /* if we have tty job control */ 114759243Sobrien retry: 114859243Sobrien if ((tpgrp = tcgetpgrp(f)) != -1) { 114959243Sobrien if (tpgrp != shpgrp) { 115059243Sobrien signalfun_t old = signal(SIGTTIN, SIG_DFL); 115159243Sobrien (void) kill(0, SIGTTIN); 115259243Sobrien (void) signal(SIGTTIN, old); 115359243Sobrien goto retry; 115459243Sobrien } 115559243Sobrien /* 115659243Sobrien * Thanks to Matt Day for the POSIX references, and to 115759243Sobrien * Paul Close for the SGI clarification. 115859243Sobrien */ 115959243Sobrien if (setdisc(f) != -1) { 116059243Sobrien opgrp = shpgrp; 116159243Sobrien shpgrp = getpid(); 116259243Sobrien tpgrp = shpgrp; 116359243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 116459243Sobrien /* 116559243Sobrien * On hpux 7.03 this fails with EPERM. This happens on 116659243Sobrien * the 800 when opgrp != shpgrp at this point. (we were 116759243Sobrien * forked from a non job control shell) 116859243Sobrien * POSIX 7.2.4, says we failed because the process 116959243Sobrien * group specified did not belong to a process 117059243Sobrien * in the same session with the tty. So we set our 117159243Sobrien * process group and try again. 117259243Sobrien */ 117359243Sobrien if (setpgid(0, shpgrp) == -1) { 117459243Sobrien xprintf("setpgid:"); 117559243Sobrien goto notty; 117659243Sobrien } 117759243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 117859243Sobrien xprintf("tcsetpgrp:"); 117959243Sobrien goto notty; 118059243Sobrien } 118159243Sobrien } 118259243Sobrien /* 118359243Sobrien * We check the process group now. If it is the same, then 118459243Sobrien * we don't need to set it again. On hpux 7.0 on the 300's 118559243Sobrien * if we set it again it fails with EPERM. This is the 118659243Sobrien * correct behavior according to POSIX 4.3.3 if the process 118759243Sobrien * was a session leader . 118859243Sobrien */ 118959243Sobrien else if (shpgrp != mygetpgrp()) { 119059243Sobrien if(setpgid(0, shpgrp) == -1) { 119159243Sobrien xprintf("setpgid:"); 119259243Sobrien goto notty; 119359243Sobrien } 119459243Sobrien } 119559243Sobrien#ifdef IRIS4D 119659243Sobrien /* 119759243Sobrien * But on irix 3.3 we need to set it again, even if it is 119859243Sobrien * the same. We do that to tell the system that we 119959243Sobrien * need BSD process group compatibility. 120059243Sobrien */ 120159243Sobrien else 120259243Sobrien (void) setpgid(0, shpgrp); 120359243Sobrien#endif 120459243Sobrien (void) close_on_exec(dcopy(f, FSHTTY), 1); 120559243Sobrien } 120659243Sobrien else 120759243Sobrien tpgrp = -1; 120859243Sobrien } 120959243Sobrien if (tpgrp == -1) { 121059243Sobrien notty: 121159243Sobrien xprintf(CGETS(11, 1, "Warning: no access to tty (%s).\n"), 121259243Sobrien strerror(errno)); 121359243Sobrien xprintf(CGETS(11, 2, "Thus no job control in this shell.\n")); 121459243Sobrien /* 121559243Sobrien * Fix from:Sakari Jalovaara <sja@sirius.hut.fi> if we don't 121659243Sobrien * have access to tty, disable editing too 121759243Sobrien */ 121859243Sobrien if (adrof(STRedit)) 121959243Sobrien unsetv(STRedit); 122059243Sobrien editing = 0; 122159243Sobrien } 122259243Sobrien#else /* BSDJOBS */ /* don't have job control, so frotz it */ 122359243Sobrien tpgrp = -1; 122459243Sobrien#endif /* BSDJOBS */ 122559243Sobrien } 122659243Sobrien } 122759243Sobrien if ((setintr == 0) && (parintr == SIG_DFL)) 122859243Sobrien setintr = 1; 122959243Sobrien 123059243Sobrien/* 123159243Sobrien * SVR4 doesn't send a SIGCHLD when a child is stopped or continued if the 123259243Sobrien * handler is installed with signal(2) or sigset(2). sigaction(2) must 123359243Sobrien * be used instead. 123459243Sobrien * 123559243Sobrien * David Dawes (dawes@physics.su.oz.au) Sept 1991 123659243Sobrien */ 123759243Sobrien 123859243Sobrien#if SYSVREL > 3 123959243Sobrien { 124059243Sobrien struct sigaction act; 124159243Sobrien act.sa_handler=pchild; 124259243Sobrien (void) sigemptyset(&(act.sa_mask)); /* Don't block any extra sigs 124359243Sobrien * when the handler is called 124459243Sobrien */ 124559243Sobrien act.sa_flags=0; /* want behaviour of sigset() without 124659243Sobrien * SA_NOCLDSTOP 124759243Sobrien */ 124859243Sobrien 124959243Sobrien if ((sigaction(SIGCHLD,&act,(struct sigaction *)NULL)) == -1) 125059243Sobrien stderror(ERR_SYSTEM, "sigaction", strerror(errno)); 125159243Sobrien } 125259243Sobrien#else /* SYSVREL <= 3 */ 125359243Sobrien (void) sigset(SIGCHLD, pchild); /* while signals not ready */ 125459243Sobrien#endif /* SYSVREL <= 3 */ 125559243Sobrien 125659243Sobrien 125759243Sobrien if (intty && !arginp) 125859243Sobrien (void) ed_Setup(editing);/* Get the tty state, and set defaults */ 125959243Sobrien /* Only alter the tty state if editing */ 126059243Sobrien 126159243Sobrien /* 126259243Sobrien * Set an exit here in case of an interrupt or error reading the shell 126359243Sobrien * start-up scripts. 126459243Sobrien */ 1265131962Smp osetintr = setintr; 1266131962Smp oparintr = parintr; 126759243Sobrien reenter = setexit(); /* PWP */ 126869408Sache exitset++; 126959243Sobrien haderr = 0; /* In case second time through */ 127059243Sobrien if (!fast && reenter == 0) { 127159243Sobrien /* Will have varval(STRhome) here because set fast if don't */ 127259243Sobrien { 127359243Sobrien#ifdef BSDSIGS 127459243Sobrien sigmask_t omask = sigblock(sigmask(SIGINT)); 127559243Sobrien#else 127659243Sobrien (void) sighold(SIGINT); 127759243Sobrien#endif 127859243Sobrien setintr = 0; 127959243Sobrien parintr = SIG_IGN; /* onintr in /etc/ files has no effect */ 128059243Sobrien#ifdef LOGINFIRST 128159243Sobrien#ifdef _PATH_DOTLOGIN 128259243Sobrien if (loginsh) 128359243Sobrien (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 128459243Sobrien#endif 128559243Sobrien#endif 128659243Sobrien 128759243Sobrien#ifdef _PATH_DOTCSHRC 128859243Sobrien (void) srcfile(_PATH_DOTCSHRC, 0, 0, NULL); 128959243Sobrien#endif 129059243Sobrien if (!arginp && !onelflg && !havhash) 129159243Sobrien dohash(NULL,NULL); 129259243Sobrien#ifndef LOGINFIRST 129359243Sobrien#ifdef _PATH_DOTLOGIN 129459243Sobrien if (loginsh) 129559243Sobrien (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 129659243Sobrien#endif 129759243Sobrien#endif 129859243Sobrien#ifdef BSDSIGS 129959243Sobrien (void) sigsetmask(omask); 130059243Sobrien#else 130159243Sobrien (void) sigrelse(SIGINT); 130259243Sobrien#endif 130359243Sobrien setintr = osetintr; 130459243Sobrien parintr = oparintr; 130559243Sobrien } 130659243Sobrien#ifdef LOGINFIRST 130759243Sobrien if (loginsh) 130859243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 130959243Sobrien#endif 131059243Sobrien /* upward compat. */ 131159243Sobrien if (!srccat(varval(STRhome), STRsldottcshrc)) 131259243Sobrien (void) srccat(varval(STRhome), STRsldotcshrc); 131359243Sobrien 131459243Sobrien if (!fast && !arginp && !onelflg && !havhash) 131559243Sobrien dohash(NULL,NULL); 131659243Sobrien 131759243Sobrien /* 131859243Sobrien * Source history before .login so that it is available in .login 131959243Sobrien */ 132059243Sobrien loadhist(NULL, 0); 132159243Sobrien#ifndef LOGINFIRST 132259243Sobrien if (loginsh) 132359243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 132459243Sobrien#endif 132559243Sobrien if (!fast && (loginsh || rdirs)) 132659243Sobrien loaddirs(NULL); 132759243Sobrien } 1328131962Smp /* Reset interrupt flag */ 1329131962Smp setintr = osetintr; 1330131962Smp parintr = oparintr; 1331131962Smp 133259243Sobrien /* Initing AFTER .cshrc is the Right Way */ 133359243Sobrien if (intty && !arginp) { /* PWP setup stuff */ 133459243Sobrien ed_Init(); /* init the new line editor */ 133559243Sobrien#ifdef SIG_WINDOW 133659243Sobrien check_window_size(1); /* mung environment */ 133759243Sobrien#endif /* SIG_WINDOW */ 133859243Sobrien } 133959243Sobrien 134059243Sobrien /* 134159243Sobrien * Now are ready for the -v and -x flags 134259243Sobrien */ 134359243Sobrien if (nverbose) 134459243Sobrien setNS(STRverbose); 134559243Sobrien if (nexececho) 134659243Sobrien setNS(STRecho); 134759243Sobrien 134859243Sobrien /* 134959243Sobrien * All the rest of the world is inside this call. The argument to process 135059243Sobrien * indicates whether it should catch "error unwinds". Thus if we are a 135159243Sobrien * interactive shell our call here will never return by being blown past on 135259243Sobrien * an error. 135359243Sobrien */ 135459243Sobrien process(setintr); 135559243Sobrien 135659243Sobrien /* 135759243Sobrien * Mop-up. 135859243Sobrien */ 135959243Sobrien if (intty) { 136059243Sobrien if (loginsh) { 136159243Sobrien xprintf("logout\n"); 136259243Sobrien (void) close(SHIN); 136359243Sobrien child = 1; 136459243Sobrien#ifdef TESLA 136559243Sobrien do_logout = 1; 136659243Sobrien#endif /* TESLA */ 136759243Sobrien goodbye(NULL, NULL); 136859243Sobrien } 136959243Sobrien else { 137059243Sobrien xprintf("exit\n"); 137159243Sobrien } 137259243Sobrien } 137359243Sobrien record(); 137459243Sobrien exitstat(); 137559243Sobrien return (0); 137659243Sobrien} 137759243Sobrien 137859243Sobrienvoid 137959243Sobrienuntty() 138059243Sobrien{ 138159243Sobrien#ifdef BSDJOBS 138259243Sobrien if (tpgrp > 0 && opgrp != shpgrp) { 138359243Sobrien (void) setpgid(0, opgrp); 138459243Sobrien (void) tcsetpgrp(FSHTTY, opgrp); 138559243Sobrien (void) resetdisc(FSHTTY); 138659243Sobrien } 138759243Sobrien#endif /* BSDJOBS */ 138859243Sobrien} 138959243Sobrien 139059243Sobrienvoid 139159243Sobrienimportpath(cp) 139259243Sobrien Char *cp; 139359243Sobrien{ 139459243Sobrien register int i = 0; 139559243Sobrien register Char *dp; 139659243Sobrien register Char **pv; 139759243Sobrien int c; 139859243Sobrien 139959243Sobrien for (dp = cp; *dp; dp++) 140059243Sobrien if (*dp == PATHSEP) 140159243Sobrien i++; 140259243Sobrien /* 140359243Sobrien * i+2 where i is the number of colons in the path. There are i+1 140459243Sobrien * directories in the path plus we need room for a zero terminator. 140559243Sobrien */ 140659243Sobrien pv = (Char **) xcalloc((size_t) (i + 2), sizeof(Char *)); 140759243Sobrien dp = cp; 140859243Sobrien i = 0; 140959243Sobrien if (*dp) 141059243Sobrien for (;;) { 141159243Sobrien if ((c = *dp) == PATHSEP || c == 0) { 141259243Sobrien *dp = 0; 141359243Sobrien pv[i++] = Strsave(*cp ? cp : STRdot); 141459243Sobrien if (c) { 141559243Sobrien cp = dp + 1; 141659243Sobrien *dp = PATHSEP; 141759243Sobrien } 141859243Sobrien else 141959243Sobrien break; 142059243Sobrien } 142169408Sache#ifdef WINNT_NATIVE 142259243Sobrien else if (*dp == '\\') 142359243Sobrien *dp = '/'; 142469408Sache#endif /* WINNT_NATIVE */ 142559243Sobrien dp++; 142659243Sobrien } 142759243Sobrien pv[i] = 0; 142859243Sobrien setq(STRpath, pv, &shvhed, VAR_READWRITE); 142959243Sobrien} 143059243Sobrien 143159243Sobrien/* 143259243Sobrien * Source to the file which is the catenation of the argument names. 143359243Sobrien */ 143459243Sobrienstatic int 143559243Sobriensrccat(cp, dp) 143659243Sobrien Char *cp, *dp; 143759243Sobrien{ 143859243Sobrien if (cp[0] == '/' && cp[1] == '\0') 143959243Sobrien return srcfile(short2str(dp), (mflag ? 0 : 1), 0, NULL); 144059243Sobrien else { 144159243Sobrien register Char *ep; 144259243Sobrien char *ptr; 144359243Sobrien int rv; 144459243Sobrien 144569408Sache#ifdef WINNT_NATIVE 144659243Sobrien ep = cp; 144759243Sobrien while(*ep) 144859243Sobrien ep++; 144959243Sobrien if (ep[-1] == '/' && dp[0] == '/') /* silly win95 */ 145059243Sobrien dp++; 145169408Sache#endif /* WINNT_NATIVE */ 145259243Sobrien 145359243Sobrien ep = Strspl(cp, dp); 145459243Sobrien ptr = short2str(ep); 145559243Sobrien 145659243Sobrien rv = srcfile(ptr, (mflag ? 0 : 1), 0, NULL); 145759243Sobrien xfree((ptr_t) ep); 145859243Sobrien return rv; 145959243Sobrien } 146059243Sobrien} 146159243Sobrien 146259243Sobrien/* 146359243Sobrien * Source to a file putting the file descriptor in a safe place (> 2). 146459243Sobrien */ 146583098Smp#ifndef WINNT_NATIVE 146659243Sobrienstatic int 146783098Smp#else 146883098Smpint 146983098Smp#endif /*WINNT_NATIVE*/ 147059243Sobriensrcfile(f, onlyown, flag, av) 147159243Sobrien char *f; 147259243Sobrien bool onlyown; 147359243Sobrien int flag; 147459243Sobrien Char **av; 147559243Sobrien{ 147659243Sobrien register int unit; 147759243Sobrien 1478131962Smp if ((unit = open(f, O_RDONLY|O_LARGEFILE)) == -1) 147959243Sobrien return 0; 1480131962Smp#ifdef O_TEXT 1481131962Smp setmode(unit, O_TEXT); 1482131962Smp#endif 148359243Sobrien unit = dmove(unit, -1); 148459243Sobrien 148559243Sobrien (void) close_on_exec(unit, 1); 148659243Sobrien srcunit(unit, onlyown, flag, av); 148759243Sobrien return 1; 148859243Sobrien} 148959243Sobrien 149059243Sobrien 149159243Sobrien/* 149259243Sobrien * Save the shell state, and establish new argument vector, and new input 149359243Sobrien * fd. 149459243Sobrien */ 149559243Sobrienstatic void 149659243Sobrienst_save(st, unit, hflg, al, av) 149759243Sobrien struct saved_state *st; 149859243Sobrien int unit, hflg; 149959243Sobrien Char **al, **av; 150059243Sobrien{ 150159243Sobrien st->insource = insource; 150259243Sobrien st->SHIN = SHIN; 1503100616Smp /* Want to preserve the meaning of "source file >output". 1504100616Smp * Save old descriptors, move new 0,1,2 to safe places and assign 1505100616Smp * them to SH* and let process() redo 0,1,2 from them. 1506100616Smp * 1507100616Smp * The macro returns true if d1 and d2 are good and they point to 1508100616Smp * different things. If you don't avoid saving duplicate 1509100616Smp * descriptors, you really limit the depth of "source" recursion 1510100616Smp * you can do because of all the open file descriptors. -IAN! 1511100616Smp */ 1512100616Smp#define NEED_SAVE_FD(d1,d2) \ 1513100616Smp (fstat(d1, &s1) != -1 && fstat(d2, &s2) != -1 \ 1514100616Smp && (s1.st_ino != s2.st_ino || s1.st_dev != s2.st_dev) ) 1515100616Smp 1516100616Smp st->OLDSTD = st->SHOUT = st->SHDIAG = -1;/* test later to restore these */ 1517100616Smp if (didfds) { 1518100616Smp struct stat s1, s2; 1519100616Smp if (NEED_SAVE_FD(0,OLDSTD)) 1520100616Smp st->OLDSTD = OLDSTD, OLDSTD = dmove(0, -1); 1521100616Smp if (NEED_SAVE_FD(1,SHOUT)) 1522100616Smp st->SHOUT = SHOUT, SHOUT = dmove(1, -1); 1523100616Smp if (NEED_SAVE_FD(2,SHDIAG)) 1524100616Smp st->SHDIAG = SHDIAG, SHDIAG = dmove(2, -1); 1525100616Smp donefds(); 1526100616Smp } 1527100616Smp 152859243Sobrien st->intty = intty; 152959243Sobrien st->whyles = whyles; 153059243Sobrien st->gointr = gointr; 153159243Sobrien st->arginp = arginp; 153259243Sobrien st->evalp = evalp; 153359243Sobrien st->evalvec = evalvec; 153459243Sobrien st->alvecp = alvecp; 153559243Sobrien st->alvec = alvec; 153659243Sobrien st->onelflg = onelflg; 153759243Sobrien st->enterhist = enterhist; 153859243Sobrien if (hflg) 153959243Sobrien st->HIST = HIST; 154059243Sobrien else 154159243Sobrien st->HIST = '\0'; 154259243Sobrien st->cantell = cantell; 154359243Sobrien cpybin(st->B, B); 154459243Sobrien 154559243Sobrien /* 154659243Sobrien * we can now pass arguments to source. 154759243Sobrien * For compatibility we do that only if arguments were really 154859243Sobrien * passed, otherwise we keep the old, global $argv like before. 154959243Sobrien */ 155059243Sobrien if (av != NULL && *av != NULL) { 155159243Sobrien struct varent *vp; 1552100616Smp if ((vp = adrof(STRargv)) != NULL && vp->vec != NULL) 155359243Sobrien st->argv = saveblk(vp->vec); 155459243Sobrien else 155559243Sobrien st->argv = NULL; 155659243Sobrien setq(STRargv, saveblk(av), &shvhed, VAR_READWRITE); 155759243Sobrien } 155859243Sobrien else 155959243Sobrien st->argv = NULL; 156059243Sobrien 156159243Sobrien SHIN = unit; /* Do this first */ 156259243Sobrien 156359243Sobrien /* Establish new input arena */ 156459243Sobrien { 156559243Sobrien fbuf = NULL; 156659243Sobrien fseekp = feobp = fblocks = 0; 156759243Sobrien settell(); 156859243Sobrien } 156959243Sobrien 157059243Sobrien arginp = 0; 157159243Sobrien onelflg = 0; 157259243Sobrien intty = isatty(SHIN); 157359243Sobrien whyles = 0; 157459243Sobrien gointr = 0; 157559243Sobrien evalvec = 0; 157659243Sobrien evalp = 0; 157759243Sobrien alvec = al; 157859243Sobrien alvecp = 0; 157959243Sobrien enterhist = hflg; 158059243Sobrien if (enterhist) 158159243Sobrien HIST = '\0'; 158259243Sobrien insource = 1; 158359243Sobrien} 158459243Sobrien 158559243Sobrien 158659243Sobrien/* 158759243Sobrien * Restore the shell to a saved state 158859243Sobrien */ 158959243Sobrienstatic void 159059243Sobrienst_restore(st, av) 159159243Sobrien struct saved_state *st; 159259243Sobrien Char **av; 159359243Sobrien{ 159459243Sobrien if (st->SHIN == -1) 159559243Sobrien return; 159659243Sobrien 159759243Sobrien /* Reset input arena */ 159859243Sobrien { 159959243Sobrien register int i; 160059243Sobrien register Char** nfbuf = fbuf; 160159243Sobrien register int nfblocks = fblocks; 160259243Sobrien 160359243Sobrien fblocks = 0; 160459243Sobrien fbuf = NULL; 160559243Sobrien for (i = 0; i < nfblocks; i++) 160659243Sobrien xfree((ptr_t) nfbuf[i]); 160759243Sobrien xfree((ptr_t) nfbuf); 160859243Sobrien } 160959243Sobrien cpybin(B, st->B); 161059243Sobrien 161159243Sobrien (void) close(SHIN); 161259243Sobrien 161359243Sobrien insource = st->insource; 161459243Sobrien SHIN = st->SHIN; 1615100616Smp if (st->OLDSTD != -1) 1616100616Smp (void)close(OLDSTD), OLDSTD = st->OLDSTD; 1617100616Smp if (st->SHOUT != -1) 1618100616Smp (void)close(SHOUT), SHOUT = st->SHOUT; 1619100616Smp if (st->SHDIAG != -1) 1620100616Smp (void)close(SHDIAG), SHDIAG = st->SHDIAG; 162159243Sobrien arginp = st->arginp; 162259243Sobrien onelflg = st->onelflg; 162359243Sobrien evalp = st->evalp; 162459243Sobrien evalvec = st->evalvec; 162559243Sobrien alvecp = st->alvecp; 162659243Sobrien alvec = st->alvec; 162759243Sobrien intty = st->intty; 162859243Sobrien whyles = st->whyles; 162959243Sobrien gointr = st->gointr; 163059243Sobrien if (st->HIST != '\0') 163159243Sobrien HIST = st->HIST; 163259243Sobrien enterhist = st->enterhist; 163359243Sobrien cantell = st->cantell; 163459243Sobrien 163559243Sobrien if (st->argv != NULL) 163659243Sobrien setq(STRargv, st->argv, &shvhed, VAR_READWRITE); 163759243Sobrien else if (av != NULL && *av != NULL && adrof(STRargv) != NULL) 163859243Sobrien unsetv(STRargv); 163959243Sobrien} 164059243Sobrien 164159243Sobrien/* 164259243Sobrien * Source to a unit. If onlyown it must be our file or our group or 164359243Sobrien * we don't chance it. This occurs on ".cshrc"s and the like. 164459243Sobrien */ 164559243Sobrienstatic void 164659243Sobriensrcunit(unit, onlyown, hflg, av) 164759243Sobrien register int unit; 164859243Sobrien bool onlyown; 164959243Sobrien int hflg; 165059243Sobrien Char **av; 165159243Sobrien{ 165259243Sobrien struct saved_state st; 165359243Sobrien st.SHIN = -1; /* st_restore checks this */ 165459243Sobrien 165559243Sobrien if (unit < 0) 165659243Sobrien return; 165759243Sobrien 165859243Sobrien if (onlyown) { 165959243Sobrien struct stat stb; 166059243Sobrien 166159243Sobrien if (fstat(unit, &stb) < 0) { 166259243Sobrien (void) close(unit); 166359243Sobrien return; 166459243Sobrien } 166559243Sobrien } 166659243Sobrien 166759243Sobrien getexit(st.oldexit); 166859243Sobrien 166959243Sobrien if (setintr) 167059243Sobrien#ifdef BSDSIGS 167159243Sobrien st.mask = sigblock(sigmask(SIGINT)); 167259243Sobrien#else 167359243Sobrien (void) sighold(SIGINT); 167459243Sobrien#endif 167559243Sobrien 167659243Sobrien /* Save the current state and move us to a new state */ 167759243Sobrien st_save(&st, unit, hflg, NULL, av); 167859243Sobrien 167959243Sobrien /* 168059243Sobrien * Now if we are allowing commands to be interrupted, we let ourselves be 168159243Sobrien * interrupted. 168259243Sobrien */ 168359243Sobrien if (setintr) 168459243Sobrien#ifdef BSDSIGS 168559243Sobrien (void) sigsetmask(st.mask); 168659243Sobrien#else 168759243Sobrien (void) sigrelse(SIGINT); 168859243Sobrien#endif 168959243Sobrien 169059243Sobrien /* 169159243Sobrien * Bugfix for running out of memory by: Jak Kirman 169259243Sobrien * <jak%cs.brown.edu@RELAY.CS.NET>. Solution: pay attention to what 169359243Sobrien * setexit() is returning because reenter _may_ be in a register, and 169459243Sobrien * thus restored to 0 on a longjump(). (PWP: insert flames about 169559243Sobrien * compiler-dependant code here) PWP: THANKS LOTS !!! 169659243Sobrien * 169759243Sobrien * PWP: think of this as like a LISP (unwind-protect ...) 169859243Sobrien * thanks to Diana Smetters for pointing out how this _should_ be written 169959243Sobrien */ 170059243Sobrien#ifdef cray 170159243Sobrien st.reenter = 1; /* assume non-zero return val */ 170259243Sobrien if (setexit() == 0) { 170359243Sobrien st.reenter = 0; /* Oh well, we were wrong */ 170459243Sobrien#else 170559243Sobrien if ((st.reenter = setexit()) == 0) { 170659243Sobrien#endif 170759243Sobrien process(0); /* 0 -> blow away on errors */ 170859243Sobrien } 170959243Sobrien 171059243Sobrien if (setintr) 171159243Sobrien#ifdef BSDSIGS 171259243Sobrien (void) sigsetmask(st.mask); 171359243Sobrien#else 171459243Sobrien (void) sigrelse(SIGINT); 171559243Sobrien#endif 171659243Sobrien 171759243Sobrien /* Restore the old state */ 171859243Sobrien st_restore(&st, av); 171959243Sobrien resexit(st.oldexit); 172059243Sobrien /* 172159243Sobrien * If process reset() (effectively an unwind) then we must also unwind. 172259243Sobrien */ 172359243Sobrien if (st.reenter) 172459243Sobrien stderror(ERR_SILENT); 172559243Sobrien} 172659243Sobrien 172759243Sobrien 172859243Sobrien/*ARGSUSED*/ 172959243Sobrienvoid 173059243Sobriengoodbye(v, c) 173159243Sobrien Char **v; 173259243Sobrien struct command *c; 173359243Sobrien{ 173459243Sobrien USE(c); 173559243Sobrien record(); 173659243Sobrien 173759243Sobrien if (loginsh) { 173859243Sobrien (void) sigset(SIGQUIT, SIG_IGN); 173959243Sobrien (void) sigset(SIGINT, SIG_IGN); 174059243Sobrien (void) sigset(SIGTERM, SIG_IGN); 174159243Sobrien (void) sigset(SIGHUP, SIG_IGN); 174259243Sobrien setintr = 0; /* No interrupts after "logout" */ 174359243Sobrien /* Trap errors inside .logout */ 174459243Sobrien reenter = setexit(); 174559243Sobrien if (reenter != 0) 174659243Sobrien exitstat(); 174759243Sobrien if (!(adrof(STRlogout))) 174859243Sobrien set(STRlogout, Strsave(STRnormal), VAR_READWRITE); 174959243Sobrien#ifdef _PATH_DOTLOGOUT 175059243Sobrien (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 175159243Sobrien#endif 175259243Sobrien if (adrof(STRhome)) 175359243Sobrien (void) srccat(varval(STRhome), STRsldtlogout); 175459243Sobrien#ifdef TESLA 175559243Sobrien do_logout = 1; 175659243Sobrien#endif /* TESLA */ 175759243Sobrien } 175859243Sobrien exitstat(); 175959243Sobrien} 176059243Sobrien 176159243Sobrienvoid 176259243Sobrienexitstat() 176359243Sobrien{ 176459243Sobrien#ifdef PROF 176559243Sobrien monitor(0); 176659243Sobrien#endif 176759243Sobrien /* 176859243Sobrien * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit 176959243Sobrien * directly because we poke child here. Otherwise we might continue 177059243Sobrien * unwarrantedly (sic). 177159243Sobrien */ 177259243Sobrien child = 1; 177359243Sobrien 177459243Sobrien xexit(getn(varval(STRstatus))); 177559243Sobrien} 177659243Sobrien 177759243Sobrien/* 177859243Sobrien * in the event of a HUP we want to save the history 177959243Sobrien */ 178059243Sobrienstatic sigret_t 178159243Sobrienphup(snum) 178259243Sobrienint snum; 178359243Sobrien{ 178459243Sobrien /* 178559243Sobrien * There is no return from here, 178659243Sobrien * so we are not going to release SIGHUP 178759243Sobrien * anymore 178859243Sobrien */ 178959243Sobrien#ifdef UNRELSIGS 179059243Sobrien if (snum) 179159243Sobrien (void) sigset(snum, SIG_IGN); 179259243Sobrien#else 179359243Sobrien# ifdef BSDSIGS 179459243Sobrien (void) sigblock(sigmask(SIGHUP)); 179559243Sobrien# else 179659243Sobrien (void) sighold(SIGHUP); 179759243Sobrien# endif /* BSDSIGS */ 179859243Sobrien#endif /* UNRELSIGS */ 179959243Sobrien 180059243Sobrien if (loginsh) { 180159243Sobrien set(STRlogout, Strsave(STRhangup), VAR_READWRITE); 180259243Sobrien#ifdef _PATH_DOTLOGOUT 180359243Sobrien (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 180459243Sobrien#endif 180559243Sobrien if (adrof(STRhome)) 180659243Sobrien (void) srccat(varval(STRhome), STRsldtlogout); 180759243Sobrien } 180859243Sobrien 180959243Sobrien record(); 181059243Sobrien 181159243Sobrien#ifdef POSIXJOBS 181259243Sobrien /* 181359243Sobrien * We kill the last foreground process group. It then becomes 181459243Sobrien * responsible to propagate the SIGHUP to its progeny. 181559243Sobrien */ 181659243Sobrien { 181759243Sobrien struct process *pp, *np; 181859243Sobrien 181959243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 182059243Sobrien np = pp; 182159243Sobrien /* 182259243Sobrien * Find if this job is in the foreground. It could be that 182359243Sobrien * the process leader has exited and the foreground flag 182459243Sobrien * is cleared for it. 182559243Sobrien */ 182659243Sobrien do 182759243Sobrien /* 182859243Sobrien * If a process is in the foreground we try to kill 182959243Sobrien * it's process group. If we succeed, then the 183059243Sobrien * whole job is gone. Otherwise we keep going... 183159243Sobrien * But avoid sending HUP to the shell again. 183259243Sobrien */ 183359243Sobrien if (((np->p_flags & PFOREGND) != 0) && np->p_jobid != shpgrp) { 183459243Sobrien np->p_flags &= ~PHUP; 183559243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 183659243Sobrien /* In case the job was suspended... */ 183759243Sobrien#ifdef SIGCONT 183859243Sobrien (void) killpg(np->p_jobid, SIGCONT); 183959243Sobrien#endif 184059243Sobrien break; 184159243Sobrien } 184259243Sobrien } 184359243Sobrien while ((np = np->p_friends) != pp); 184459243Sobrien } 184559243Sobrien } 184659243Sobrien#endif /* POSIXJOBS */ 184759243Sobrien 184859243Sobrien xexit(snum); 184959243Sobrien#ifndef SIGVOID 185059243Sobrien return (snum); 185159243Sobrien#endif 185259243Sobrien} 185359243Sobrien 185459243Sobrienstatic Char *jobargv[2] = {STRjobs, 0}; 185559243Sobrien 185659243Sobrien/* 185759243Sobrien * Catch an interrupt, e.g. during lexical input. 185859243Sobrien * If we are an interactive shell, we reset the interrupt catch 185959243Sobrien * immediately. In any case we drain the shell output, 186059243Sobrien * and finally go through the normal error mechanism, which 186159243Sobrien * gets a chance to make the shell go away. 186259243Sobrien */ 186359243Sobrienint just_signaled; /* bugfix by Michael Bloom (mg@ttidca.TTI.COM) */ 186459243Sobrien 186559243Sobrien#ifdef SIGVOID 186659243Sobrien/*ARGSUSED*/ 186759243Sobrien#endif 186859243Sobriensigret_t 186959243Sobrienpintr(snum) 187059243Sobrienint snum; 187159243Sobrien{ 187259243Sobrien#ifdef UNRELSIGS 187359243Sobrien if (snum) 187459243Sobrien (void) sigset(snum, pintr); 187559243Sobrien#endif /* UNRELSIGS */ 187659243Sobrien just_signaled = 1; 187759243Sobrien pintr1(1); 187859243Sobrien#ifndef SIGVOID 187959243Sobrien return (snum); 188059243Sobrien#endif 188159243Sobrien} 188259243Sobrien 188359243Sobrienvoid 188459243Sobrienpintr1(wantnl) 188559243Sobrien bool wantnl; 188659243Sobrien{ 188759243Sobrien register Char **v; 188859243Sobrien#ifdef BSDSIGS 188959243Sobrien sigmask_t omask; 189059243Sobrien#endif 189159243Sobrien 189259243Sobrien#ifdef BSDSIGS 189359243Sobrien omask = sigblock((sigmask_t) 0); 189459243Sobrien#endif 189559243Sobrien if (setintr) { 189659243Sobrien#ifdef BSDSIGS 189759243Sobrien (void) sigsetmask(omask & ~sigmask(SIGINT)); 189859243Sobrien#else 189959243Sobrien (void) sigrelse(SIGINT); 190059243Sobrien#endif 190159243Sobrien if (pjobs) { 190259243Sobrien pjobs = 0; 190359243Sobrien xputchar('\n'); 190459243Sobrien dojobs(jobargv, NULL); 190559243Sobrien stderror(ERR_NAME | ERR_INTR); 190659243Sobrien } 190759243Sobrien } 190859243Sobrien /* MH - handle interrupted completions specially */ 190959243Sobrien { 191059243Sobrien extern int InsideCompletion; 191159243Sobrien 191259243Sobrien if (InsideCompletion) 191359243Sobrien stderror(ERR_SILENT); 191459243Sobrien } 191559243Sobrien /* JV - Make sure we shut off inputl */ 191659243Sobrien { 191759243Sobrien extern Char GettingInput; 191859243Sobrien 191959243Sobrien (void) Cookedmode(); 192059243Sobrien GettingInput = 0; 192159243Sobrien } 192259243Sobrien#ifdef BSDSIGS 192359243Sobrien (void) sigsetmask(omask & ~sigmask(SIGCHLD)); 192459243Sobrien#else 192559243Sobrien if (setintr) 192659243Sobrien (void) sighold(SIGINT); 192759243Sobrien (void) sigrelse(SIGCHLD); 192859243Sobrien#endif 192959243Sobrien drainoline(); 193069408Sache#if !defined(_VMS_POSIX) && !defined(WINNT_NATIVE) 193159243Sobrien (void) endpwent(); 193269408Sache#endif /* !_VMS_POSIX && !WINNT_NATIVE */ 193359243Sobrien 193459243Sobrien /* 193559243Sobrien * If we have an active "onintr" then we search for the label. Note that if 193659243Sobrien * one does "onintr -" then we shan't be interruptible so we needn't worry 193759243Sobrien * about that here. 193859243Sobrien */ 193959243Sobrien if (gointr) { 194059243Sobrien gotolab(gointr); 194159243Sobrien timflg = 0; 194259243Sobrien if ((v = pargv) != 0) 194359243Sobrien pargv = 0, blkfree(v); 194459243Sobrien if ((v = gargv) != 0) 194559243Sobrien gargv = 0, blkfree(v); 194659243Sobrien reset(); 194759243Sobrien } 194859243Sobrien else if (intty && wantnl) { 194959243Sobrien if (editing) { 195059243Sobrien /* 195159243Sobrien * If we are editing a multi-line input command, and move to 195259243Sobrien * the beginning of the line, we don't want to trash it when 195359243Sobrien * we hit ^C 195459243Sobrien */ 195559243Sobrien PastBottom(); 195659243Sobrien ClearLines(); 195759243Sobrien ClearDisp(); 195859243Sobrien } 195959243Sobrien else { 196059243Sobrien /* xputchar('\n'); *//* Some like this, others don't */ 196159243Sobrien (void) putraw('\r'); 196259243Sobrien (void) putraw('\n'); 196359243Sobrien } 196459243Sobrien } 196559243Sobrien stderror(ERR_SILENT); 196659243Sobrien} 196759243Sobrien 196859243Sobrien/* 196959243Sobrien * Process is the main driving routine for the shell. 197059243Sobrien * It runs all command processing, except for those within { ... } 197159243Sobrien * in expressions (which is run by a routine evalav in sh.exp.c which 197259243Sobrien * is a stripped down process), and `...` evaluation which is run 197359243Sobrien * also by a subset of this code in sh.glob.c in the routine backeval. 197459243Sobrien * 197559243Sobrien * The code here is a little strange because part of it is interruptible 197659243Sobrien * and hence freeing of structures appears to occur when none is necessary 197759243Sobrien * if this is ignored. 197859243Sobrien * 197959243Sobrien * Note that if catch is not set then we will unwind on any error. 198059243Sobrien * If an end-of-file occurs, we return. 198159243Sobrien */ 198259243Sobrienstatic struct command *savet = NULL; 198359243Sobrienvoid 198459243Sobrienprocess(catch) 198559243Sobrien bool catch; 198659243Sobrien{ 198759243Sobrien extern char Expand; 198859243Sobrien jmp_buf_t osetexit; 198959243Sobrien /* PWP: This might get nuked my longjmp so don't make it a register var */ 199059243Sobrien struct command *t = savet; 199159243Sobrien 199259243Sobrien savet = NULL; 199359243Sobrien getexit(osetexit); 199459243Sobrien for (;;) { 199559243Sobrien 199659243Sobrien pendjob(); 199759243Sobrien 199859243Sobrien /* This was leaking memory badly, particularly when sourcing 199959243Sobrien * files, etc.. For whatever reason we were arriving here with 200059243Sobrien * allocated pointers still active, and the code was simply 200159243Sobrien * overwriting them. I can't say I fully understand the 200259243Sobrien * control flow here, but according to Purify this particular 200359243Sobrien * leak has been plugged, and I haven't noticed any ill 200459243Sobrien * effects.. (sg) 200559243Sobrien */ 200659243Sobrien if (paraml.next && paraml.next != ¶ml) 200759243Sobrien freelex(¶ml); 200859243Sobrien 200959243Sobrien paraml.next = paraml.prev = ¶ml; 201059243Sobrien paraml.word = STRNULL; 201159243Sobrien (void) setexit(); 201259243Sobrien justpr = enterhist; /* execute if not entering history */ 201359243Sobrien 201459243Sobrien /* 201559243Sobrien * Interruptible during interactive reads 201659243Sobrien */ 201759243Sobrien if (setintr) 201859243Sobrien#ifdef BSDSIGS 201959243Sobrien (void) sigsetmask(sigblock((sigmask_t) 0) & ~sigmask(SIGINT)); 202059243Sobrien#else 202159243Sobrien (void) sigrelse(SIGINT); 202259243Sobrien#endif 202359243Sobrien 202459243Sobrien 202559243Sobrien /* 202659243Sobrien * For the sake of reset() 202759243Sobrien */ 202859243Sobrien freelex(¶ml); 202959243Sobrien if (savet) 203059243Sobrien freesyn(savet), savet = NULL; 203159243Sobrien 203259243Sobrien if (haderr) { 203359243Sobrien if (!catch) { 203459243Sobrien /* unwind */ 203559243Sobrien doneinp = 0; 203659243Sobrien savet = t; 203759243Sobrien resexit(osetexit); 203859243Sobrien reset(); 203959243Sobrien } 204059243Sobrien haderr = 0; 204159243Sobrien /* 204259243Sobrien * Every error is eventually caught here or the shell dies. It is 204359243Sobrien * at this point that we clean up any left-over open files, by 204459243Sobrien * closing all but a fixed number of pre-defined files. Thus 204559243Sobrien * routines don't have to worry about leaving files open due to 204659243Sobrien * deeper errors... they will get closed here. 204759243Sobrien */ 204859243Sobrien closem(); 204959243Sobrien continue; 205059243Sobrien } 205159243Sobrien if (doneinp) { 205259243Sobrien doneinp = 0; 205359243Sobrien break; 205459243Sobrien } 205559243Sobrien if (chkstop) 205659243Sobrien chkstop--; 205759243Sobrien if (neednote) 205859243Sobrien pnote(); 205959243Sobrien if (intty && prompt && evalvec == 0) { 206059243Sobrien just_signaled = 0; 206159243Sobrien mailchk(); 206259243Sobrien /* 206359243Sobrien * Watch for logins/logouts. Next is scheduled commands stored 206459243Sobrien * previously using "sched." Then execute periodic commands. 206559243Sobrien * Following that, the prompt precmd is run. 206659243Sobrien */ 206759243Sobrien#ifndef HAVENOUTMP 206859243Sobrien watch_login(0); 206959243Sobrien#endif /* !HAVENOUTMP */ 207059243Sobrien sched_run(0); 207159243Sobrien period_cmd(); 207259243Sobrien precmd(); 207359243Sobrien /* 207459243Sobrien * If we are at the end of the input buffer then we are going to 207559243Sobrien * read fresh stuff. Otherwise, we are rereading input and don't 207659243Sobrien * need or want to prompt. 207759243Sobrien */ 207869408Sache if (fseekp == feobp && aret == TCSH_F_SEEK) 207959243Sobrien printprompt(0, NULL); 208059243Sobrien flush(); 208159243Sobrien setalarm(1); 208259243Sobrien } 208359243Sobrien if (seterr) { 208459243Sobrien xfree((ptr_t) seterr); 208559243Sobrien seterr = NULL; 208659243Sobrien } 208759243Sobrien 208859243Sobrien /* 208959243Sobrien * Echo not only on VERBOSE, but also with history expansion. If there 209059243Sobrien * is a lexical error then we forego history echo. 209159243Sobrien */ 209259243Sobrien if ((lex(¶ml) && !seterr && intty && !tellwhat && !Expand && 209359243Sobrien !whyles) || adrof(STRverbose)) { 2094100616Smp int odidfds = didfds; 209559243Sobrien haderr = 1; 2096100616Smp didfds = 0; 209759243Sobrien prlex(¶ml); 2098100616Smp flush(); 209959243Sobrien haderr = 0; 2100100616Smp didfds = odidfds; 210159243Sobrien } 210259243Sobrien (void) alarm(0); /* Autologout OFF */ 210359243Sobrien 210459243Sobrien /* 210559243Sobrien * The parser may lose space if interrupted. 210659243Sobrien */ 210759243Sobrien if (setintr) 210859243Sobrien#ifdef BSDSIGS 210959243Sobrien (void) sigblock(sigmask(SIGINT)); 211059243Sobrien#else 211159243Sobrien (void) sighold(SIGINT); 211259243Sobrien#endif 211359243Sobrien 211459243Sobrien /* 211559243Sobrien * Save input text on the history list if reading in old history, or it 211659243Sobrien * is from the terminal at the top level and not in a loop. 211759243Sobrien * 211859243Sobrien * PWP: entry of items in the history list while in a while loop is done 211959243Sobrien * elsewhere... 212059243Sobrien */ 212159243Sobrien if (enterhist || (catch && intty && !whyles && !tellwhat && !arun)) 212259243Sobrien savehist(¶ml, enterhist > 1); 212359243Sobrien 212459243Sobrien if (Expand && seterr) 212559243Sobrien Expand = 0; 212659243Sobrien 212759243Sobrien /* 212859243Sobrien * Print lexical error messages, except when sourcing history lists. 212959243Sobrien */ 213059243Sobrien if (!enterhist && seterr) 213159243Sobrien stderror(ERR_OLD); 213259243Sobrien 213359243Sobrien /* 213459243Sobrien * If had a history command :p modifier then this is as far as we 213559243Sobrien * should go 213659243Sobrien */ 213759243Sobrien if (justpr) 213859243Sobrien reset(); 213959243Sobrien 214059243Sobrien /* 214159243Sobrien * If had a tellwhat from twenex() then do 214259243Sobrien */ 214359243Sobrien if (tellwhat) { 214459243Sobrien (void) tellmewhat(¶ml, NULL); 214559243Sobrien reset(); 214659243Sobrien } 214759243Sobrien 214859243Sobrien alias(¶ml); 214959243Sobrien 215059243Sobrien#ifdef BSDJOBS 215159243Sobrien /* 215259243Sobrien * If we are interactive, try to continue jobs that we have stopped 215359243Sobrien */ 215459243Sobrien if (prompt) 215559243Sobrien continue_jobs(¶ml); 215659243Sobrien#endif /* BSDJOBS */ 215759243Sobrien 215859243Sobrien /* 215959243Sobrien * Check to see if the user typed "rm * .o" or something 216059243Sobrien */ 216159243Sobrien if (prompt) 216259243Sobrien rmstar(¶ml); 216359243Sobrien /* 216459243Sobrien * Parse the words of the input into a parse tree. 216559243Sobrien */ 216659243Sobrien savet = syntax(paraml.next, ¶ml, 0); 216759243Sobrien if (seterr) 216859243Sobrien stderror(ERR_OLD); 216959243Sobrien 217059243Sobrien postcmd(); 217159243Sobrien /* 217259243Sobrien * Execute the parse tree From: Michael Schroeder 217359243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> was execute(t, tpgrp); 217459243Sobrien */ 2175100616Smp execute(savet, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 217659243Sobrien 217759243Sobrien /* 217859243Sobrien * Made it! 217959243Sobrien */ 218059243Sobrien freelex(¶ml); 218159243Sobrien freesyn(savet), savet = NULL; 218259243Sobrien#ifdef SIG_WINDOW 2183100616Smp if (windowchg || (catch && intty && !whyles && !tellwhat)) { 2184100616Smp windowchg = 0; 2185100616Smp (void) check_window_size(0); /* for window systems */ 2186100616Smp } 218759243Sobrien#endif /* SIG_WINDOW */ 218859243Sobrien set(STR_, Strsave(InputBuf), VAR_READWRITE | VAR_NOGLOB); 218959243Sobrien } 219059243Sobrien savet = t; 219159243Sobrien resexit(osetexit); 219259243Sobrien} 219359243Sobrien 219459243Sobrien/*ARGSUSED*/ 219559243Sobrienvoid 219659243Sobriendosource(t, c) 219759243Sobrien register Char **t; 219859243Sobrien struct command *c; 219959243Sobrien{ 220059243Sobrien register Char *f; 220159243Sobrien bool hflg = 0; 220259243Sobrien extern int bequiet; 220359243Sobrien char buf[BUFSIZE]; 220459243Sobrien 220559243Sobrien USE(c); 220659243Sobrien t++; 220759243Sobrien if (*t && eq(*t, STRmh)) { 220859243Sobrien if (*++t == NULL) 220959243Sobrien stderror(ERR_NAME | ERR_HFLAG); 221059243Sobrien hflg++; 221159243Sobrien } 221259243Sobrien else if (*t && eq(*t, STRmm)) { 221359243Sobrien if (*++t == NULL) 221459243Sobrien stderror(ERR_NAME | ERR_MFLAG); 221559243Sobrien hflg = 2; 221659243Sobrien } 221759243Sobrien 221859243Sobrien f = globone(*t++, G_ERROR); 221959243Sobrien (void) strcpy(buf, short2str(f)); 222059243Sobrien xfree((ptr_t) f); 2221131962Smp gflag = 0, tglob(t); 2222131962Smp if (gflag) { 2223131962Smp t = globall(t); 2224131962Smp if (t == 0) 2225131962Smp stderror(ERR_NAME | ERR_NOMATCH); 2226131962Smp } else { 2227131962Smp t = saveblk(t); 2228131962Smp trim(t); 2229131962Smp } 223059243Sobrien if ((!srcfile(buf, 0, hflg, t)) && (!hflg) && (!bequiet)) 223159243Sobrien stderror(ERR_SYSTEM, buf, strerror(errno)); 223259243Sobrien} 223359243Sobrien 223459243Sobrien/* 223559243Sobrien * Check for mail. 223659243Sobrien * If we are a login shell, then we don't want to tell 223759243Sobrien * about any mail file unless its been modified 223859243Sobrien * after the time we started. 223959243Sobrien * This prevents us from telling the user things he already 224059243Sobrien * knows, since the login program insists on saying 224159243Sobrien * "You have mail." 224259243Sobrien */ 224359243Sobrien 224459243Sobrien/* 224559243Sobrien * The AMS version. 224659243Sobrien * This version checks if the file is a directory, and if so, 224759243Sobrien * tells you the number of files in it, otherwise do the old thang. 224859243Sobrien * The magic "+1" in the time calculation is to compensate for 224959243Sobrien * an AFS bug where directory mtimes are set to 1 second in 225059243Sobrien * the future. 225159243Sobrien */ 225259243Sobrien 225359243Sobrienstatic void 225459243Sobrienmailchk() 225559243Sobrien{ 225659243Sobrien register struct varent *v; 225759243Sobrien register Char **vp; 225859243Sobrien time_t t; 225959243Sobrien int intvl, cnt; 226059243Sobrien struct stat stb; 226159243Sobrien bool new; 226259243Sobrien 226359243Sobrien v = adrof(STRmail); 2264100616Smp if (v == NULL || v->vec == NULL) 226559243Sobrien return; 226659243Sobrien (void) time(&t); 226759243Sobrien vp = v->vec; 226859243Sobrien cnt = blklen(vp); 226959243Sobrien intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 227059243Sobrien if (intvl < 1) 227159243Sobrien intvl = 1; 227259243Sobrien if (chktim + intvl > t) 227359243Sobrien return; 227459243Sobrien for (; *vp; vp++) { 227559243Sobrien char *filename = short2str(*vp); 227659243Sobrien char *mboxdir = filename; 227759243Sobrien 227859243Sobrien if (stat(filename, &stb) < 0) 227959243Sobrien continue; 228059243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 228159243Sobrien new = stb.st_mtime > time0.tv_sec; 228259243Sobrien#else 228359415Sobrien new = stb.st_mtime > seconds0; 228459243Sobrien#endif 228559243Sobrien if (S_ISDIR(stb.st_mode)) { 228659243Sobrien DIR *mailbox; 228759243Sobrien int mailcount = 0; 228859243Sobrien char tempfilename[MAXPATHLEN]; 228959243Sobrien struct stat stc; 229059243Sobrien 229159243Sobrien xsnprintf(tempfilename, MAXPATHLEN, "%s/new", filename); 229259243Sobrien 229359243Sobrien if (stat(tempfilename, &stc) != -1 && S_ISDIR(stc.st_mode)) { 229459243Sobrien /* 229559243Sobrien * "filename/new" exists and is a directory; you are 229659243Sobrien * using Qmail. 229759243Sobrien */ 229859243Sobrien stb = stc; 229959243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 230059243Sobrien new = stb.st_mtime > time0.tv_sec; 230159243Sobrien#else 230259415Sobrien new = stb.st_mtime > seconds0; 230359243Sobrien#endif 230459243Sobrien mboxdir = tempfilename; 230559243Sobrien } 230659243Sobrien 230759243Sobrien if (stb.st_mtime <= chktim + 1 || (loginsh && !new)) 230859243Sobrien continue; 230959243Sobrien 231059243Sobrien if ((mailbox = opendir(mboxdir)) == NULL) 231159243Sobrien continue; 231259243Sobrien 231359243Sobrien /* skip . and .. */ 231459243Sobrien if (!readdir(mailbox) || !readdir(mailbox)) 231559243Sobrien continue; 231659243Sobrien 231759243Sobrien while (readdir(mailbox)) 231859243Sobrien mailcount++; 231959243Sobrien 232059243Sobrien if (mailcount == 0) 232159243Sobrien continue; 232259243Sobrien 232359243Sobrien if (cnt == 1) 232459243Sobrien xprintf(CGETS(11, 3, "You have %d mail messages.\n"), 232559243Sobrien mailcount); 232659243Sobrien else 232759243Sobrien xprintf(CGETS(11, 4, "You have %d mail messages in %s.\n"), 232859243Sobrien mailcount, filename); 232959243Sobrien } 233059243Sobrien else { 233159243Sobrien if (stb.st_size == 0 || stb.st_atime > stb.st_mtime || 233259243Sobrien (stb.st_atime <= chktim && stb.st_mtime <= chktim) || 233359243Sobrien (loginsh && !new)) 233459243Sobrien continue; 233559243Sobrien if (cnt == 1) 233659243Sobrien xprintf(CGETS(11, 5, "You have %smail.\n"), 233759243Sobrien new ? CGETS(11, 6, "new ") : ""); 233859243Sobrien else 233959243Sobrien xprintf(CGETS(11, 7, "You have %smail in %s.\n"), 234059243Sobrien new ? CGETS(11, 6, "new ") : "", filename); 234159243Sobrien } 234259243Sobrien } 234359243Sobrien chktim = t; 234459243Sobrien} 234559243Sobrien 234659243Sobrien/* 234759243Sobrien * Extract a home directory from the password file 234859243Sobrien * The argument points to a buffer where the name of the 234959243Sobrien * user whose home directory is sought is currently. 235059243Sobrien * We write the home directory of the user back there. 235159243Sobrien */ 235259243Sobrienint 235359243Sobriengethdir(home) 235459243Sobrien Char *home; 235559243Sobrien{ 235659243Sobrien Char *h; 235759243Sobrien 235859243Sobrien /* 235959243Sobrien * Is it us? 236059243Sobrien */ 236159243Sobrien if (*home == '\0') { 236259243Sobrien if ((h = varval(STRhome)) != STRNULL) { 236359243Sobrien (void) Strcpy(home, h); 236459243Sobrien return 0; 236559243Sobrien } 236659243Sobrien else 236759243Sobrien return 1; 236859243Sobrien } 236959243Sobrien 237059243Sobrien /* 237159243Sobrien * Look in the cache 237259243Sobrien */ 237359243Sobrien if ((h = gettilde(home)) == NULL) 237459243Sobrien return 1; 237559243Sobrien else { 237659243Sobrien (void) Strcpy(home, h); 237759243Sobrien return 0; 237859243Sobrien } 237959243Sobrien} 238059243Sobrien 238159243Sobrien/* 238259243Sobrien * Move the initial descriptors to their eventual 238359243Sobrien * resting places, closing all other units. 238459243Sobrien */ 238559243Sobrienvoid 238659243Sobrieninitdesc() 238759243Sobrien{ 238859243Sobrien#ifdef NLS_BUGS 238959243Sobrien#ifdef NLS_CATALOGS 239059243Sobrien (void)catclose(catd); 239159243Sobrien#endif /* NLS_CATALOGS */ 239259243Sobrien#endif /* NLS_BUGS */ 239359243Sobrien 239459243Sobrien 239559243Sobrien didfds = 0; /* 0, 1, 2 aren't set up */ 239659243Sobrien (void) close_on_exec(SHIN = dcopy(0, FSHIN), 1); 239759243Sobrien (void) close_on_exec(SHOUT = dcopy(1, FSHOUT), 1); 239859243Sobrien (void) close_on_exec(SHDIAG = dcopy(2, FSHDIAG), 1); 239959243Sobrien (void) close_on_exec(OLDSTD = dcopy(SHIN, FOLDSTD), 1); 240059243Sobrien#ifndef CLOSE_ON_EXEC 240159243Sobrien didcch = 0; /* Havent closed for child */ 240259243Sobrien#endif /* CLOSE_ON_EXEC */ 240359243Sobrien isdiagatty = isatty(SHDIAG); 240459243Sobrien isoutatty = isatty(SHOUT); 240559243Sobrien#ifdef NLS_BUGS 240659243Sobrien#ifdef NLS_CATALOGS 240759243Sobrien nlsinit(); 240859243Sobrien#endif /* NLS_CATALOGS */ 240959243Sobrien#endif /* NLS_BUGS */ 241059243Sobrien} 241159243Sobrien 241259243Sobrien 241359243Sobrienvoid 241459243Sobrien#ifdef PROF 241559243Sobriendone(i) 241659243Sobrien#else 241759243Sobrienxexit(i) 241859243Sobrien#endif 241959243Sobrien int i; 242059243Sobrien{ 242159243Sobrien#ifdef TESLA 242259243Sobrien if (loginsh && do_logout) { 242359243Sobrien /* this is to send hangup signal to the develcon */ 242459243Sobrien /* we toggle DTR. clear dtr - sleep 1 - set dtr */ 242559243Sobrien /* ioctl will return ENOTTY for pty's but we ignore it */ 242659243Sobrien /* exitstat will run after disconnect */ 242759243Sobrien /* we sleep for 2 seconds to let things happen in */ 242859243Sobrien /* .logout and rechist() */ 242959243Sobrien#ifdef TIOCCDTR 243059243Sobrien (void) sleep(2); 243159243Sobrien (void) ioctl(FSHTTY, TIOCCDTR, NULL); 243259243Sobrien (void) sleep(1); 243359243Sobrien (void) ioctl(FSHTTY, TIOCSDTR, NULL); 243459243Sobrien#endif /* TIOCCDTR */ 243559243Sobrien } 243659243Sobrien#endif /* TESLA */ 243759243Sobrien 243859243Sobrien { 243959243Sobrien struct process *pp, *np; 244059243Sobrien 244159243Sobrien /* Kill all processes marked for hup'ing */ 244259243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 244359243Sobrien np = pp; 244459243Sobrien do 244559243Sobrien if ((np->p_flags & PHUP) && np->p_jobid != shpgrp) { 244659243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 244759243Sobrien /* In case the job was suspended... */ 244859243Sobrien#ifdef SIGCONT 244959243Sobrien (void) killpg(np->p_jobid, SIGCONT); 245059243Sobrien#endif 245159243Sobrien break; 245259243Sobrien } 245359243Sobrien } 245459243Sobrien while ((np = np->p_friends) != pp); 245559243Sobrien } 245659243Sobrien } 245759243Sobrien untty(); 245859243Sobrien#ifdef NLS_CATALOGS 245959243Sobrien /* 246059243Sobrien * We need to call catclose, because SVR4 leaves symlinks behind otherwise 246159243Sobrien * in the catalog directories. We cannot close on a vforked() child, 246259243Sobrien * because messages will stop working on the parent too. 246359243Sobrien */ 246459243Sobrien if (child == 0) 246559243Sobrien (void) catclose(catd); 246659243Sobrien#endif /* NLS_CATALOGS */ 246769408Sache#ifdef WINNT_NATIVE 246859243Sobrien nt_cleanup(); 246969408Sache#endif /* WINNT_NATIVE */ 247059243Sobrien _exit(i); 247159243Sobrien} 247259243Sobrien 247359243Sobrien#ifndef _PATH_DEFPATH 247459243Sobrienstatic Char ** 247559243Sobriendefaultpath() 247659243Sobrien{ 247759243Sobrien char *ptr; 247859243Sobrien Char **blk, **blkp; 247959243Sobrien struct stat stb; 248059243Sobrien 248159243Sobrien blkp = blk = (Char **) xmalloc((size_t) sizeof(Char *) * 10); 248259243Sobrien 248359243Sobrien#ifndef NODOT 248459243Sobrien# ifndef DOTLAST 248559243Sobrien *blkp++ = Strsave(STRdot); 248659243Sobrien# endif 248759243Sobrien#endif 248859243Sobrien 248959243Sobrien#define DIRAPPEND(a) \ 249059243Sobrien if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \ 249159243Sobrien *blkp++ = SAVE(ptr) 249259243Sobrien 249359243Sobrien#ifdef _PATH_LOCAL 249459243Sobrien DIRAPPEND(_PATH_LOCAL); 249559243Sobrien#endif 249659243Sobrien 249759243Sobrien#ifdef _PATH_USRUCB 249859243Sobrien DIRAPPEND(_PATH_USRUCB); 249959243Sobrien#endif 250059243Sobrien 250159243Sobrien#ifdef _PATH_USRBSD 250259243Sobrien DIRAPPEND(_PATH_USRBSD); 250359243Sobrien#endif 250459243Sobrien 250559243Sobrien#ifdef _PATH_BIN 250659243Sobrien DIRAPPEND(_PATH_BIN); 250759243Sobrien#endif 250859243Sobrien 250959243Sobrien#ifdef _PATH_USRBIN 251059243Sobrien DIRAPPEND(_PATH_USRBIN); 251159243Sobrien#endif 251259243Sobrien 251359243Sobrien#undef DIRAPPEND 251459243Sobrien 251559243Sobrien#ifndef NODOT 251659243Sobrien# ifdef DOTLAST 251759243Sobrien *blkp++ = Strsave(STRdot); 251859243Sobrien# endif 251959243Sobrien#endif 252059243Sobrien *blkp = NULL; 252159243Sobrien return (blk); 252259243Sobrien} 252359243Sobrien#endif 252459243Sobrien 252559243Sobrienstatic void 252659243Sobrienrecord() 252759243Sobrien{ 252859243Sobrien if (!fast) { 252959243Sobrien recdirs(NULL, adrof(STRsavedirs) != NULL); 253059243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 253159243Sobrien } 253259243Sobrien} 2533