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