sh.c revision 231990
1231990Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.c,v 3.174 2011/11/29 18:38:54 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.c: Main shell routines 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#define EXTERN /* Intern */ 3459243Sobrien#include "sh.h" 3559243Sobrien 3659243Sobrien#ifndef lint 3759243Sobrienchar copyright[] = 3859243Sobrien"@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 3959243Sobrien All rights reserved.\n"; 4059243Sobrien#endif /* not lint */ 4159243Sobrien 42231990SmpRCSID("$tcsh: sh.c,v 3.174 2011/11/29 18:38:54 christos Exp $") 4359243Sobrien 4459243Sobrien#include "tc.h" 4559243Sobrien#include "ed.h" 4659243Sobrien#include "tw.h" 4759243Sobrien 48145479Smpextern int MapsAreInited; 49145479Smpextern int NLSMapsAreInited; 5059243Sobrien 5159243Sobrien/* 5259243Sobrien * C Shell 5359243Sobrien * 5459243Sobrien * Bill Joy, UC Berkeley, California, USA 5559243Sobrien * October 1978, May 1980 5659243Sobrien * 5759243Sobrien * Jim Kulp, IIASA, Laxenburg, Austria 5859243Sobrien * April 1980 5959243Sobrien * 6059243Sobrien * Filename recognition added: 6159243Sobrien * Ken Greer, Ind. Consultant, Palo Alto CA 6259243Sobrien * October 1983. 6359243Sobrien * 6459243Sobrien * Karl Kleinpaste, Computer Consoles, Inc. 6559243Sobrien * Added precmd, periodic/tperiod, prompt changes, 6659243Sobrien * directory stack hack, and login watch. 6759243Sobrien * Sometime March 1983 - Feb 1984. 6859243Sobrien * 6959243Sobrien * Added scheduled commands, including the "sched" command, 7059243Sobrien * plus the call to sched_run near the precmd et al 7159243Sobrien * routines. 7259243Sobrien * Upgraded scheduled events for running events while 7359243Sobrien * sitting idle at command input. 7459243Sobrien * 7559243Sobrien * Paul Placeway, Ohio State 7659243Sobrien * added stuff for running with twenex/inputl 9 Oct 1984. 7759243Sobrien * 7859243Sobrien * ported to Apple Unix (TM) (OREO) 26 -- 29 Jun 1987 7959243Sobrien */ 8059243Sobrien 81231990Smpjmp_buf_t reslab; 8259243Sobrien 8359243Sobrienstatic const char tcshstr[] = "tcsh"; 8459243Sobrien 85167465Smpstruct sigaction parintr; /* Parents interrupt catch */ 86167465Smpstruct sigaction parterm; /* Parents terminate catch */ 8759243Sobrien 8859243Sobrien#ifdef TESLA 8959243Sobrienint do_logout = 0; 9059243Sobrien#endif /* TESLA */ 9159243Sobrien 9259243Sobrien 93145479Smpint use_fork = 0; /* use fork() instead of vfork()? */ 9459243Sobrien 9559243Sobrien/* 9659243Sobrien * Magic pointer values. Used to specify other invalid conditions aside 9759243Sobrien * from null. 9859243Sobrien */ 9959243Sobrienstatic Char INVCHAR; 10059243SobrienChar *INVPTR = &INVCHAR; 10159243SobrienChar **INVPPTR = &INVPTR; 10259243Sobrien 103167465Smpstatic int fast = 0; 104145479Smpstatic int mflag = 0; 105145479Smpstatic int prompt = 1; 106145479Smpint enterhist = 0; 107145479Smpint tellwhat = 0; 10859243Sobrientime_t t_period; 10959243SobrienChar *ffile = NULL; 110145479Smpint dolzero = 0; 11159243Sobrienint insource = 0; 11269408Sacheint exitset = 0; 11359243Sobrienstatic time_t chktim; /* Time mail last checked */ 11459243Sobrienchar *progname; 11559243Sobrienint tcsh; 11659243Sobrien 11759243Sobrien/* 11859243Sobrien * This preserves the input state of the shell. It is used by 11959243Sobrien * st_save and st_restore to manupulate shell state. 12059243Sobrien */ 12159243Sobrienstruct saved_state { 12259243Sobrien int insource; 123100616Smp int OLDSTD; 12459243Sobrien int SHIN; 125100616Smp int SHOUT; 126100616Smp int SHDIAG; 12759243Sobrien int intty; 12859243Sobrien struct whyle *whyles; 12959243Sobrien Char *gointr; 13059243Sobrien Char *arginp; 13159243Sobrien Char *evalp; 13259243Sobrien Char **evalvec; 13359243Sobrien Char *alvecp; 13459243Sobrien Char **alvec; 13559243Sobrien int onelflg; 136145479Smp int enterhist; 13759243Sobrien Char **argv; 138167465Smp Char **av; 13959243Sobrien Char HIST; 140145479Smp int cantell; 14159243Sobrien struct Bin B; 142195609Smp int justpr; 14359243Sobrien}; 14459243Sobrien 145167465Smpstatic int srccat (Char *, Char *); 14683098Smp#ifndef WINNT_NATIVE 147167465Smpstatic int srcfile (const char *, int, int, Char **); 14883098Smp#else 149167465Smpint srcfile (const char *, int, int, Char **); 15083098Smp#endif /*WINNT_NATIVE*/ 151167465Smpstatic void srcunit (int, int, int, Char **); 152167465Smpstatic void mailchk (void); 15359243Sobrien#ifndef _PATH_DEFPATH 154167465Smpstatic Char **defaultpath (void); 15559243Sobrien#endif 156167465Smpstatic void record (void); 157167465Smpstatic void st_save (struct saved_state *, int, int, 158167465Smp Char **, Char **); 159167465Smpstatic void st_restore (void *); 16059243Sobrien 161167465Smp int main (int, char **); 16259243Sobrien 163231990Smp#ifndef LOCALEDIR 164231990Smp#define LOCALEDIR "/usr/share/locale" 165231990Smp#endif 166231990Smp 167231990Smp#ifdef NLS_CATALOGS 168231990Smpstatic void 169231990Smpadd_localedir_to_nlspath(const char *path) 170231990Smp{ 171231990Smp static const char msgs_LOC[] = "/%L/LC_MESSAGES/%N.cat"; 172231990Smp static const char msgs_lang[] = "/%l/LC_MESSAGES/%N.cat"; 173231990Smp char *old; 174231990Smp char *new, *new_p; 175231990Smp size_t len; 176231990Smp int add_LOC = 1; 177231990Smp int add_lang = 1; 178231990Smp char trypath[MAXPATHLEN]; 179231990Smp struct stat st; 180231990Smp 181231990Smp if (path == NULL) 182231990Smp return; 183231990Smp 184231990Smp (void) xsnprintf(trypath, sizeof(trypath), "%s/en/LC_MESSAGES/tcsh.cat", 185231990Smp path); 186231990Smp if (stat(trypath, &st) == -1) 187231990Smp return; 188231990Smp 189231990Smp if ((old = getenv("NLSPATH")) != NULL) 190231990Smp len = strlen(old) + 1; /* don't forget the colon. */ 191231990Smp else 192231990Smp len = 0; 193231990Smp 194231990Smp len += 2 * strlen(path) + 195231990Smp sizeof(msgs_LOC) + sizeof(msgs_lang); /* includes the extra colon */ 196231990Smp 197231990Smp new = new_p = xcalloc(len, 1); 198231990Smp 199231990Smp if (old != NULL) { 200231990Smp size_t pathlen = strlen(path); 201231990Smp char *old_p; 202231990Smp 203231990Smp (void) xsnprintf(new_p, len, "%s", old); 204231990Smp new_p += strlen(new_p); 205231990Smp len -= new_p - new; 206231990Smp 207231990Smp /* Check if the paths we try to add are already present in NLSPATH. 208231990Smp If so, note it by setting the appropriate flag to 0. */ 209231990Smp for (old_p = old; old_p; old_p = strchr(old_p, ':'), 210231990Smp old_p = old_p ? old_p + 1 : NULL) { 211231990Smp if (strncmp(old_p, path, pathlen) != 0) 212231990Smp continue; 213231990Smp if (strncmp(old_p + pathlen, msgs_LOC, sizeof(msgs_LOC) - 1) == 0) 214231990Smp add_LOC = 0; 215231990Smp else if (strncmp(old_p + pathlen, msgs_lang, 216231990Smp sizeof(msgs_lang) - 1) == 0) 217231990Smp add_lang = 0; 218231990Smp } 219231990Smp } 220231990Smp 221231990Smp /* Add the message catalog paths not already present to NLSPATH. */ 222231990Smp if (add_LOC || add_lang) 223231990Smp (void) xsnprintf(new_p, len, "%s%s%s%s%s%s", 224231990Smp old ? ":" : "", 225231990Smp add_LOC ? path : "", add_LOC ? msgs_LOC : "", 226231990Smp add_LOC && add_lang ? ":" : "", 227231990Smp add_lang ? path : "", add_lang ? msgs_lang : ""); 228231990Smp 229231990Smp tsetenv(STRNLSPATH, str2short(new)); 230231990Smp free(new); 231231990Smp} 232231990Smp#endif 233231990Smp 23459243Sobrienint 235167465Smpmain(int argc, char **argv) 23659243Sobrien{ 237167465Smp int batch = 0; 238167465Smp volatile int nexececho = 0; 239167465Smp int nofile = 0; 240167465Smp volatile int nverbose = 0; 241167465Smp volatile int rdirs = 0; 242167465Smp int quitit = 0; 243145479Smp Char *cp; 24459243Sobrien#ifdef AUTOLOGOUT 245145479Smp Char *cp2; 24659243Sobrien#endif 247145479Smp char *tcp, *ttyn; 248167465Smp int f, reenter; 249145479Smp char **tempv; 250131962Smp int osetintr; 251167465Smp struct sigaction oparintr; 25259243Sobrien 253231990Smp (void)memset(&reslab, 0, sizeof(reslab)); 25469408Sache#ifdef WINNT_NATIVE 25559243Sobrien nt_init(); 25669408Sache#endif /* WINNT_NATIVE */ 25759243Sobrien#if defined(NLS_CATALOGS) && defined(LC_MESSAGES) 25859243Sobrien (void) setlocale(LC_MESSAGES, ""); 25959243Sobrien#endif /* NLS_CATALOGS && LC_MESSAGES */ 26059243Sobrien 26159243Sobrien#ifdef NLS 26259243Sobrien# ifdef LC_CTYPE 26359243Sobrien (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 26459243Sobrien# endif /* LC_CTYPE */ 26559243Sobrien#endif /* NLS */ 26659243Sobrien 267231990Smp STR_environ = blk2short(environ); 268231990Smp environ = short2blk(STR_environ); /* So that we can free it */ 269231990Smp 270231990Smp#ifdef NLS_CATALOGS 271231990Smp add_localedir_to_nlspath(LOCALEDIR); 272231990Smp#endif 273231990Smp 27459243Sobrien nlsinit(); 27559243Sobrien 27659243Sobrien#ifdef MALLOC_TRACE 277167465Smp mal_setstatsfile(fdopen(dmove(xopen("/tmp/tcsh.trace", 278145479Smp O_WRONLY|O_CREAT|O_LARGEFILE, 0666), 25), "w")); 279145479Smp mal_trace(1); 28059243Sobrien#endif /* MALLOC_TRACE */ 28159243Sobrien 28259243Sobrien#if !(defined(BSDTIMES) || defined(_SEQUENT_)) && defined(POSIX) 28359243Sobrien# ifdef _SC_CLK_TCK 28459243Sobrien clk_tck = (clock_t) sysconf(_SC_CLK_TCK); 28559243Sobrien# else /* ! _SC_CLK_TCK */ 28659243Sobrien# ifdef CLK_TCK 28759243Sobrien clk_tck = CLK_TCK; 28859243Sobrien# else /* !CLK_TCK */ 28959243Sobrien clk_tck = HZ; 29059243Sobrien# endif /* CLK_TCK */ 29159243Sobrien# endif /* _SC_CLK_TCK */ 29259243Sobrien#endif /* !BSDTIMES && POSIX */ 29359243Sobrien 29459243Sobrien settimes(); /* Immed. estab. timing base */ 29559243Sobrien#ifdef TESLA 29659243Sobrien do_logout = 0; 29759243Sobrien#endif /* TESLA */ 29859243Sobrien 29959243Sobrien /* 30059243Sobrien * Make sure we have 0, 1, 2 open 30159243Sobrien * Otherwise `` jobs will not work... (From knaff@poly.polytechnique.fr) 30259243Sobrien */ 30359243Sobrien { 30459243Sobrien do 305167465Smp if ((f = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE)) == -1 && 306167465Smp (f = xopen("/", O_RDONLY|O_LARGEFILE)) == -1) 30759243Sobrien exit(1); 30859243Sobrien while (f < 3); 309167465Smp xclose(f); 31059243Sobrien } 31159243Sobrien 31259243Sobrien osinit(); /* Os dependent initialization */ 31359243Sobrien 31459243Sobrien 31559243Sobrien { 31659243Sobrien char *t; 31759243Sobrien 31859243Sobrien t = strrchr(argv[0], '/'); 31969408Sache#ifdef WINNT_NATIVE 32059243Sobrien { 32159243Sobrien char *s = strrchr(argv[0], '\\'); 32259243Sobrien if (s) 32359243Sobrien t = s; 32459243Sobrien } 32569408Sache#endif /* WINNT_NATIVE */ 32659243Sobrien t = t ? t + 1 : argv[0]; 32759243Sobrien if (*t == '-') t++; 32859243Sobrien progname = strsave((t && *t) ? t : tcshstr); /* never want a null */ 329231990Smp tcsh = strncmp(progname, tcshstr, sizeof(tcshstr) - 1) == 0; 33059243Sobrien } 33159243Sobrien 33259243Sobrien /* 33359243Sobrien * Initialize non constant strings 33459243Sobrien */ 33559243Sobrien#ifdef _PATH_BSHELL 33659243Sobrien STR_BSHELL = SAVE(_PATH_BSHELL); 33759243Sobrien#endif 33859243Sobrien#ifdef _PATH_TCSHELL 33959243Sobrien STR_SHELLPATH = SAVE(_PATH_TCSHELL); 34059243Sobrien#else 34159243Sobrien# ifdef _PATH_CSHELL 34259243Sobrien STR_SHELLPATH = SAVE(_PATH_CSHELL); 34359243Sobrien# endif 34459243Sobrien#endif 34559243Sobrien STR_WORD_CHARS = SAVE(WORD_CHARS); 34659243Sobrien 34759243Sobrien HIST = '!'; 34859243Sobrien HISTSUB = '^'; 349231990Smp PRCH = tcsh ? '>' : '%'; /* to replace %# in $prompt for normal users */ 350231990Smp PRCHROOT = '#'; /* likewise for root */ 35159243Sobrien word_chars = STR_WORD_CHARS; 35259243Sobrien bslash_quote = 0; /* PWP: do tcsh-style backslash quoting? */ 353231990Smp anyerror = 1; /* for compatibility */ 354231990Smp setcopy(STRanyerror, STRNULL, VAR_READWRITE); 35559243Sobrien 35659243Sobrien /* Default history size to 100 */ 357167465Smp setcopy(STRhistory, str2short("100"), VAR_READWRITE); 35859243Sobrien 35959243Sobrien tempv = argv; 36059243Sobrien ffile = SAVE(tempv[0]); 36159243Sobrien dolzero = 0; 36259243Sobrien if (eq(ffile, STRaout)) /* A.out's are quittable */ 36359243Sobrien quitit = 1; 36459243Sobrien uid = getuid(); 36559243Sobrien gid = getgid(); 36659243Sobrien euid = geteuid(); 36759243Sobrien egid = getegid(); 36859243Sobrien /* 36959243Sobrien * We are a login shell if: 1. we were invoked as -<something> with 37059243Sobrien * optional arguments 2. or we were invoked only with the -l flag 37159243Sobrien */ 37259243Sobrien loginsh = (**tempv == '-') || (argc == 2 && 37359243Sobrien tempv[1][0] == '-' && tempv[1][1] == 'l' && 37459243Sobrien tempv[1][2] == '\0'); 37559243Sobrien#ifdef _VMS_POSIX 37659243Sobrien /* No better way to find if we are a login shell */ 37759243Sobrien if (!loginsh) { 37859243Sobrien loginsh = (argc == 1 && getppid() == 1); 37959243Sobrien **tempv = '-'; /* Avoid giving VMS an acidic stomach */ 38059243Sobrien } 38159243Sobrien#endif /* _VMS_POSIX */ 38259243Sobrien 38359243Sobrien if (loginsh && **tempv != '-') { 384167465Smp char *argv0; 385167465Smp 38659243Sobrien /* 38759243Sobrien * Mangle the argv space 38859243Sobrien */ 38959243Sobrien tempv[1][0] = '\0'; 39059243Sobrien tempv[1][1] = '\0'; 39159243Sobrien tempv[1] = NULL; 392167465Smp argv0 = strspl("-", *tempv); 393167465Smp *tempv = argv0; 39459243Sobrien argc--; 39559243Sobrien } 39659243Sobrien if (loginsh) { 39759243Sobrien (void) time(&chktim); 398167465Smp setNS(STRloginsh); 39959243Sobrien } 40059243Sobrien 40159243Sobrien NoNLSRebind = getenv("NOREBIND") != NULL; 40259243Sobrien#ifdef NLS 40359243Sobrien# ifdef SETLOCALEBUG 40459243Sobrien dont_free = 1; 40559243Sobrien# endif /* SETLOCALEBUG */ 40659243Sobrien (void) setlocale(LC_ALL, ""); 40759243Sobrien# ifdef LC_COLLATE 40859243Sobrien (void) setlocale(LC_COLLATE, ""); 40959243Sobrien# endif 41059243Sobrien# ifdef SETLOCALEBUG 41159243Sobrien dont_free = 0; 41259243Sobrien# endif /* SETLOCALEBUG */ 41359243Sobrien# ifdef STRCOLLBUG 41459243Sobrien fix_strcoll_bug(); 41559243Sobrien# endif /* STRCOLLBUG */ 41659243Sobrien 417231990Smp /* 418231990Smp * On solaris ISO8859-1 contains no printable characters in the upper half 419231990Smp * so we need to test only for MB_CUR_MAX == 1, otherwise for multi-byte 420231990Smp * locales we are always AsciiOnly == 0. 421231990Smp */ 422231990Smp if (MB_CUR_MAX == 1) { 42359243Sobrien int k; 42459243Sobrien 425231990Smp for (k = 0200; k <= 0377 && !isprint(CTL_ESC(k)); k++) 42659243Sobrien continue; 427231990Smp AsciiOnly = k > 0377; 428231990Smp } else 429231990Smp AsciiOnly = 0; 43059243Sobrien#else 43159243Sobrien AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL; 43259243Sobrien#endif /* NLS */ 43359243Sobrien if (MapsAreInited && !NLSMapsAreInited) 43459243Sobrien ed_InitNLSMaps(); 43559243Sobrien ResetArrowKeys(); 43659243Sobrien 43759243Sobrien /* 43859243Sobrien * Initialize for periodic command intervals. Also, initialize the dummy 43959243Sobrien * tty list for login-watch. 44059243Sobrien */ 44159243Sobrien (void) time(&t_period); 44259243Sobrien#ifndef HAVENOUTMP 44359243Sobrien initwatch(); 44459243Sobrien#endif /* !HAVENOUTMP */ 44559243Sobrien 44659243Sobrien#if defined(alliant) 44759243Sobrien /* 44859243Sobrien * From: Jim Pace <jdp@research.att.com> 44959243Sobrien * tcsh does not work properly on the alliants through an rlogin session. 45059243Sobrien * The shell generally hangs. Also, reference to the controlling terminal 45159243Sobrien * does not work ( ie: echo foo > /dev/tty ). 45259243Sobrien * 45359243Sobrien * A security feature was added to rlogind affecting FX/80's Concentrix 45459243Sobrien * from revision 5.5.xx upwards (through 5.7 where this fix was implemented) 45559243Sobrien * This security change also affects the FX/2800 series. 45659243Sobrien * The security change to rlogind requires the process group of an rlogin 45759243Sobrien * session become disassociated with the tty in rlogind. 45859243Sobrien * 45959243Sobrien * The changes needed are: 46059243Sobrien * 1. set the process group 46159243Sobrien * 2. reenable the control terminal 46259243Sobrien */ 46359243Sobrien if (loginsh && isatty(SHIN)) { 464167465Smp ttyn = ttyname(SHIN); 465167465Smp xclose(SHIN); 466167465Smp SHIN = xopen(ttyn, O_RDWR|O_LARGEFILE); 46759243Sobrien shpgrp = getpid(); 46859243Sobrien (void) ioctl (SHIN, TIOCSPGRP, (ioctl_t) &shpgrp); 46959243Sobrien (void) setpgid(0, shpgrp); 47059243Sobrien } 47159243Sobrien#endif /* alliant */ 47259243Sobrien 47359243Sobrien /* 47459243Sobrien * Move the descriptors to safe places. The variable didfds is 0 while we 47559243Sobrien * have only FSH* to work with. When didfds is true, we have 0,1,2 and 47659243Sobrien * prefer to use these. 47759243Sobrien */ 47859243Sobrien initdesc(); 47959243Sobrien 48059243Sobrien /* 48159243Sobrien * Get and set the tty now 48259243Sobrien */ 48359243Sobrien if ((ttyn = ttyname(SHIN)) != NULL) { 48459243Sobrien /* 48559243Sobrien * Could use rindex to get rid of other possible path components, but 48659243Sobrien * hpux preserves the subdirectory /pty/ when storing the tty name in 48759243Sobrien * utmp, so we keep it too. 48859243Sobrien */ 48959243Sobrien if (strncmp(ttyn, "/dev/", 5) == 0) 490167465Smp setv(STRtty, cp = SAVE(ttyn + 5), VAR_READWRITE); 49159243Sobrien else 492167465Smp setv(STRtty, cp = SAVE(ttyn), VAR_READWRITE); 49359243Sobrien } 49459243Sobrien else 495167465Smp setv(STRtty, cp = SAVE(""), VAR_READWRITE); 49659243Sobrien /* 49759243Sobrien * Initialize the shell variables. ARGV and PROMPT are initialized later. 49859243Sobrien * STATUS is also munged in several places. CHILD is munged when 49959243Sobrien * forking/waiting 50059243Sobrien */ 50159243Sobrien 50259243Sobrien /* 50359243Sobrien * 7-10-87 Paul Placeway autologout should be set ONLY on login shells and 50459243Sobrien * on shells running as root. Out of these, autologout should NOT be set 50559243Sobrien * for any psudo-terminals (this catches most window systems) and not for 50659243Sobrien * any terminal running X windows. 50759243Sobrien * 50859243Sobrien * At Ohio State, we have had problems with a user having his X session 50959243Sobrien * drop out from under him (on a Sun) because the shell in his master 51059243Sobrien * xterm timed out and exited. 51159243Sobrien * 51259243Sobrien * Really, this should be done with a program external to the shell, that 51359243Sobrien * watches for no activity (and NO running programs, such as dump) on a 51459243Sobrien * terminal for a long peroid of time, and then SIGHUPS the shell on that 51559243Sobrien * terminal. 51659243Sobrien * 51759243Sobrien * bugfix by Rich Salz <rsalz@PINEAPPLE.BBN.COM>: For root rsh things 51859243Sobrien * allways first check to see if loginsh or really root, then do things 51959243Sobrien * with ttyname() 52059243Sobrien * 52159243Sobrien * Also by Jean-Francois Lamy <lamy%ai.toronto.edu@RELAY.CS.NET>: check the 52259243Sobrien * value of cp before using it! ("root can rsh too") 52359243Sobrien * 52459243Sobrien * PWP: keep the nested ifs; the order of the tests matters and a good 52559243Sobrien * (smart) C compiler might re-arange things wrong. 52659243Sobrien */ 52759243Sobrien#ifdef AUTOLOGOUT 52859243Sobrien# ifdef convex 529167465Smp if (uid == 0) 53059243Sobrien /* root always has a 15 minute autologout */ 531167465Smp setcopy(STRautologout, STRrootdefautologout, VAR_READWRITE); 53259243Sobrien else 53359243Sobrien if (loginsh) 53459243Sobrien /* users get autologout set to 0 */ 535167465Smp setcopy(STRautologout, STR0, VAR_READWRITE); 53659243Sobrien# else /* convex */ 53759243Sobrien if (loginsh || (uid == 0)) { 53859243Sobrien if (*cp) { 53959243Sobrien /* only for login shells or root and we must have a tty */ 540231990Smp if (((cp2 = Strrchr(cp, (Char) '/')) != NULL) && 541231990Smp (Strncmp(cp, STRptssl, 3) != 0)) { 542172665Smp cp2 = cp2 + 1; 54359243Sobrien } 54459243Sobrien else 54559243Sobrien cp2 = cp; 54659243Sobrien if (!(((Strncmp(cp2, STRtty, 3) == 0) && Isalpha(cp2[3])) || 547184072Sru Strstr(cp, STRptssl) != NULL)) { 54859243Sobrien if (getenv("DISPLAY") == NULL) { 54959243Sobrien /* NOT on X window shells */ 550167465Smp setcopy(STRautologout, STRdefautologout, VAR_READWRITE); 55159243Sobrien } 55259243Sobrien } 55359243Sobrien } 55459243Sobrien } 55559243Sobrien# endif /* convex */ 55659243Sobrien#endif /* AUTOLOGOUT */ 55759243Sobrien 558167465Smp sigset_interrupting(SIGALRM, queue_alrmcatch); 55959243Sobrien 560167465Smp setcopy(STRstatus, STR0, VAR_READWRITE); 56159243Sobrien 56259243Sobrien /* 563100616Smp * get and set machine specific environment variables 56459243Sobrien */ 56559243Sobrien getmachine(); 56659243Sobrien 56759243Sobrien 56859243Sobrien /* 56959243Sobrien * Publish the selected echo style 57059243Sobrien */ 571100616Smp#if ECHO_STYLE != BSD_ECHO 572100616Smp if (tcsh) { 573100616Smp# if ECHO_STYLE == NONE_ECHO 574167465Smp setcopy(STRecho_style, STRnone, VAR_READWRITE); 575100616Smp# endif /* ECHO_STYLE == NONE_ECHO */ 576100616Smp# if ECHO_STYLE == SYSV_ECHO 577167465Smp setcopy(STRecho_style, STRsysv, VAR_READWRITE); 578100616Smp# endif /* ECHO_STYLE == SYSV_ECHO */ 579100616Smp# if ECHO_STYLE == BOTH_ECHO 580167465Smp setcopy(STRecho_style, STRboth, VAR_READWRITE); 581100616Smp# endif /* ECHO_STYLE == BOTH_ECHO */ 582100616Smp } else 583100616Smp#endif /* ECHO_STYLE != BSD_ECHO */ 584167465Smp setcopy(STRecho_style, STRbsd, VAR_READWRITE); 58559243Sobrien 58659243Sobrien /* 58759243Sobrien * increment the shell level. 58859243Sobrien */ 58959243Sobrien shlvl(1); 59059243Sobrien 591167465Smp if ((tcp = getenv("HOME")) != NULL) 592167465Smp cp = quote(SAVE(tcp)); 593167465Smp else 594231990Smp#ifdef __ANDROID__ 595231990Smp /* On Android, $HOME usually isn't set, so we can't load user RC files. 596231990Smp Check for the environment variable EXTERNAL_STORAGE, which contains 597231990Smp the mount point of the external storage (SD card, mostly). If 598231990Smp EXTERNAL_STORAGE isn't set fall back to "/sdcard". */ 599231990Smp if ((tcp = getenv("EXTERNAL_STORAGE")) != NULL) 600231990Smp cp = quote(SAVE(tcp)); 601231990Smp else 602231990Smp cp = quote(SAVE("/sdcard")); 603231990Smp#else 60459243Sobrien cp = NULL; 605231990Smp#endif 60673393Skris 60759243Sobrien if (cp == NULL) 60859243Sobrien fast = 1; /* No home -> can't read scripts */ 60959243Sobrien else 610167465Smp setv(STRhome, cp, VAR_READWRITE); 61173393Skris 61259243Sobrien dinit(cp); /* dinit thinks that HOME == cwd in a login 61359243Sobrien * shell */ 61459243Sobrien /* 61559243Sobrien * Grab other useful things from the environment. Should we grab 61659243Sobrien * everything?? 61759243Sobrien */ 61859243Sobrien { 61959243Sobrien char *cln, *cus, *cgr; 62059243Sobrien struct passwd *pw; 62159243Sobrien struct group *gr; 62259243Sobrien 62359243Sobrien 62459243Sobrien#ifdef apollo 62559243Sobrien int oid = getoid(); 62659243Sobrien 627167465Smp setv(STRoid, Itoa(oid, 0, 0), VAR_READWRITE); 62859243Sobrien#endif /* apollo */ 62959243Sobrien 630231990Smp setv(STReuid, Itoa(euid, 0, 0), VAR_READWRITE); 631231990Smp if ((pw = xgetpwuid(euid)) == NULL) 632231990Smp setcopy(STReuser, STRunknown, VAR_READWRITE); 633231990Smp else 634231990Smp setcopy(STReuser, str2short(pw->pw_name), VAR_READWRITE); 635231990Smp 636167465Smp setv(STRuid, Itoa(uid, 0, 0), VAR_READWRITE); 63759243Sobrien 638167465Smp setv(STRgid, Itoa(gid, 0, 0), VAR_READWRITE); 63959243Sobrien 64059243Sobrien cln = getenv("LOGNAME"); 64159243Sobrien cus = getenv("USER"); 64259243Sobrien if (cus != NULL) 643167465Smp setv(STRuser, quote(SAVE(cus)), VAR_READWRITE); 64459243Sobrien else if (cln != NULL) 645167465Smp setv(STRuser, quote(SAVE(cln)), VAR_READWRITE); 646167465Smp else if ((pw = xgetpwuid(uid)) == NULL) 647231990Smp setcopy(STRuser, STRunknown, VAR_READWRITE); 64859243Sobrien else 649167465Smp setcopy(STRuser, str2short(pw->pw_name), VAR_READWRITE); 65059243Sobrien if (cln == NULL) 65159243Sobrien tsetenv(STRLOGNAME, varval(STRuser)); 65259243Sobrien if (cus == NULL) 65359243Sobrien tsetenv(STRKUSER, varval(STRuser)); 65459243Sobrien 65559243Sobrien cgr = getenv("GROUP"); 65659243Sobrien if (cgr != NULL) 657167465Smp setv(STRgroup, quote(SAVE(cgr)), VAR_READWRITE); 658167465Smp else if ((gr = xgetgrgid(gid)) == NULL) 659231990Smp setcopy(STRgroup, STRunknown, VAR_READWRITE); 66059243Sobrien else 661167465Smp setcopy(STRgroup, str2short(gr->gr_name), VAR_READWRITE); 66259243Sobrien if (cgr == NULL) 66359243Sobrien tsetenv(STRKGROUP, varval(STRgroup)); 66459243Sobrien } 66559243Sobrien 66659243Sobrien /* 66759243Sobrien * HOST may be wrong, since rexd transports the entire environment on sun 66859243Sobrien * 3.x Just set it again 66959243Sobrien */ 67059243Sobrien { 67159243Sobrien char cbuff[MAXHOSTNAMELEN]; 67259243Sobrien 67359243Sobrien if (gethostname(cbuff, sizeof(cbuff)) >= 0) { 67459243Sobrien cbuff[sizeof(cbuff) - 1] = '\0'; /* just in case */ 67559243Sobrien tsetenv(STRHOST, str2short(cbuff)); 67659243Sobrien } 67759243Sobrien else 678231990Smp tsetenv(STRHOST, STRunknown); 67959243Sobrien } 68059243Sobrien 68159243Sobrien 68259243Sobrien#ifdef REMOTEHOST 68359243Sobrien /* 68459243Sobrien * Try to determine the remote host we were logged in from. 68559243Sobrien */ 68659243Sobrien remotehost(); 68759243Sobrien#endif /* REMOTEHOST */ 68859243Sobrien 68959243Sobrien#ifdef apollo 69059243Sobrien if ((tcp = getenv("SYSTYPE")) == NULL) 69159243Sobrien tcp = "bsd4.3"; 69259243Sobrien tsetenv(STRSYSTYPE, quote(str2short(tcp))); 69359243Sobrien#endif /* apollo */ 69459243Sobrien 69559243Sobrien /* 69659243Sobrien * set editing on by default, unless running under Emacs as an inferior 69759243Sobrien * shell. 69859243Sobrien * We try to do this intelligently. If $TERM is available, then it 69959243Sobrien * should determine if we should edit or not. $TERM is preserved 70059243Sobrien * across rlogin sessions, so we will not get confused if we rlogin 70159243Sobrien * under an emacs shell. Another advantage is that if we run an 70259243Sobrien * xterm under an emacs shell, then the $TERM will be set to 70359243Sobrien * xterm, so we are going to want to edit. Unfortunately emacs 70459243Sobrien * does not restore all the tty modes, so xterm is not very well 70559243Sobrien * set up. But this is not the shell's fault. 70659243Sobrien * Also don't edit if $TERM == wm, for when we're running under an ATK app. 70759243Sobrien * Finally, emacs compiled under terminfo, sets the terminal to dumb, 70859243Sobrien * so disable editing for that too. 70959243Sobrien * 71059243Sobrien * Unfortunately, in some cases the initial $TERM setting is "unknown", 71159243Sobrien * "dumb", or "network" which is then changed in the user's startup files. 71259243Sobrien * We fix this by setting noediting here if $TERM is unknown/dumb and 71359243Sobrien * if noediting is set, we switch on editing if $TERM is changed. 71459243Sobrien */ 71559243Sobrien if ((tcp = getenv("TERM")) != NULL) { 716167465Smp setv(STRterm, quote(SAVE(tcp)), VAR_READWRITE); 71759243Sobrien noediting = strcmp(tcp, "unknown") == 0 || strcmp(tcp, "dumb") == 0 || 71859243Sobrien strcmp(tcp, "network") == 0; 71959243Sobrien editing = strcmp(tcp, "emacs") != 0 && strcmp(tcp, "wm") != 0 && 72059243Sobrien !noediting; 72159243Sobrien } 72259243Sobrien else { 72359243Sobrien noediting = 0; 72459243Sobrien editing = ((tcp = getenv("EMACS")) == NULL || strcmp(tcp, "t") != 0); 72559243Sobrien } 72659243Sobrien 72759243Sobrien /* 72859243Sobrien * The 'edit' variable is either set or unset. It doesn't 72959243Sobrien * need a value. Making it 'emacs' might be confusing. 73059243Sobrien */ 73159243Sobrien if (editing) 732167465Smp setNS(STRedit); 73359243Sobrien 73459243Sobrien 73559243Sobrien /* 73659243Sobrien * still more mutability: make the complete routine automatically add the 73759243Sobrien * suffix of file names... 73859243Sobrien */ 739167465Smp setNS(STRaddsuffix); 74059243Sobrien 74159243Sobrien /* 742145479Smp * Compatibility with tcsh >= 6.12 by default 743145479Smp */ 744167465Smp setNS(STRcsubstnonl); 745145479Smp 746145479Smp /* 74783098Smp * Random default kill ring size 74883098Smp */ 749167465Smp setcopy(STRkillring, str2short("30"), VAR_READWRITE); 75083098Smp 75183098Smp /* 75259243Sobrien * Re-initialize path if set in environment 75359243Sobrien */ 75459243Sobrien if ((tcp = getenv("PATH")) == NULL) 75559243Sobrien#ifdef _PATH_DEFPATH 75659243Sobrien importpath(str2short(_PATH_DEFPATH)); 75759243Sobrien#else /* !_PATH_DEFPATH */ 75859243Sobrien setq(STRpath, defaultpath(), &shvhed, VAR_READWRITE); 75959243Sobrien#endif /* _PATH_DEFPATH */ 76059243Sobrien else 76159243Sobrien /* Importpath() allocates memory for the path, and the 76259243Sobrien * returned pointer from SAVE() was discarded, so 76359243Sobrien * this was a memory leak.. (sg) 76459243Sobrien * 76559243Sobrien * importpath(SAVE(tcp)); 76659243Sobrien */ 76759243Sobrien importpath(str2short(tcp)); 76859243Sobrien 76959243Sobrien 77059243Sobrien { 77159243Sobrien /* If the SHELL environment variable ends with "tcsh", set 77259243Sobrien * STRshell to the same path. This is to facilitate using 77359243Sobrien * the executable in environments where the compiled-in 77459243Sobrien * default isn't appropriate (sg). 77559243Sobrien */ 77659243Sobrien 777167465Smp size_t sh_len = 0; 77859243Sobrien 77959243Sobrien if ((tcp = getenv("SHELL")) != NULL) { 78059243Sobrien sh_len = strlen(tcp); 78159243Sobrien if ((sh_len >= 5 && strcmp(tcp + (sh_len - 5), "/tcsh") == 0) || 78259243Sobrien (!tcsh && sh_len >= 4 && strcmp(tcp + (sh_len - 4), "/csh") == 0)) 783167465Smp setv(STRshell, quote(SAVE(tcp)), VAR_READWRITE); 78459243Sobrien else 78559243Sobrien sh_len = 0; 78659243Sobrien } 78759243Sobrien if (sh_len == 0) 788167465Smp setcopy(STRshell, STR_SHELLPATH, VAR_READWRITE); 78959243Sobrien } 79059243Sobrien 791167465Smp#ifdef _OSD_POSIX /* BS2000 needs this variable set to "SHELL" */ 792167465Smp if ((tcp = getenv("PROGRAM_ENVIRONMENT")) == NULL) 793167465Smp tcp = "SHELL"; 794167465Smp tsetenv(STRPROGRAM_ENVIRONMENT, quote(str2short(tcp))); 795167465Smp#endif /* _OSD_POSIX */ 796167465Smp 79759243Sobrien#ifdef COLOR_LS_F 79859243Sobrien if ((tcp = getenv("LS_COLORS")) != NULL) 79959243Sobrien parseLS_COLORS(str2short(tcp)); 80059243Sobrien#endif /* COLOR_LS_F */ 80159243Sobrien 802231990Smp doldol = putn((tcsh_number_t)getpid()); /* For $$ */ 80369408Sache#ifdef WINNT_NATIVE 80459243Sobrien { 805167465Smp char *tmp; 806167465Smp Char *tmp2; 807167465Smp if ((tmp = getenv("TMP")) != NULL) { 808167465Smp tmp = xasprintf("%s/%s", tmp, "sh"); 809167465Smp tmp2 = SAVE(tmp); 810231990Smp xfree(tmp); 811231990Smp } 812167465Smp else { 813167465Smp tmp2 = SAVE(""); 814167465Smp } 815167465Smp shtemp = Strspl(tmp2, doldol); /* For << */ 816167465Smp xfree(tmp2); 817167465Smp } 81869408Sache#else /* !WINNT_NATIVE */ 819231990Smp#ifdef HAVE_MKSTEMP 820231990Smp { 821231990Smp char *tmpdir = getenv ("TMPDIR"); 822231990Smp if (!tmpdir) 823231990Smp tmpdir = "/tmp"; 824231990Smp shtemp = Strspl(SAVE(tmpdir), SAVE("/sh" TMP_TEMPLATE)); /* For << */ 825231990Smp } 826231990Smp#else /* !HAVE_MKSTEMP */ 82759243Sobrien shtemp = Strspl(STRtmpsh, doldol); /* For << */ 828231990Smp#endif /* HAVE_MKSTEMP */ 82969408Sache#endif /* WINNT_NATIVE */ 83059243Sobrien 83159243Sobrien /* 83259243Sobrien * Record the interrupt states from the parent process. If the parent is 83359243Sobrien * non-interruptible our hand must be forced or we (and our children) won't 83459243Sobrien * be either. Our children inherit termination from our parent. We catch it 83559243Sobrien * only if we are the login shell. 83659243Sobrien */ 837167465Smp sigaction(SIGINT, NULL, &parintr); 838167465Smp sigaction(SIGTERM, NULL, &parterm); 83959243Sobrien 84059243Sobrien 84159243Sobrien#ifdef TCF 84259243Sobrien /* Enable process migration on ourselves and our progeny */ 84359243Sobrien (void) signal(SIGMIGRATE, SIG_DFL); 84459243Sobrien#endif /* TCF */ 84559243Sobrien 84659243Sobrien /* 84769408Sache * dspkanji/dspmbyte autosetting 84869408Sache */ 84969408Sache /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 85069408Sache#if defined(DSPMBYTE) 85169408Sache#if defined(NLS) && defined(LC_CTYPE) 852231990Smp if (((tcp = setlocale(LC_CTYPE, NULL)) != NULL || (tcp = getenv("LANG")) != NULL) && !adrof(CHECK_MBYTEVAR)) 85369408Sache#else 854231990Smp if ((tcp = getenv("LANG")) != NULL && !adrof(CHECK_MBYTEVAR)) 85569408Sache#endif 856231990Smp { 85769408Sache autoset_dspmbyte(str2short(tcp)); 85869408Sache } 85969408Sache#if defined(WINNT_NATIVE) 86069408Sache else if (!adrof(CHECK_MBYTEVAR)) 86169408Sache nt_autoset_dspmbyte(); 86269408Sache#endif /* WINNT_NATIVE */ 86369408Sache#endif 864231990Smp#if defined(AUTOSET_KANJI) 865231990Smp# if defined(NLS) && defined(LC_CTYPE) 866231990Smp if (setlocale(LC_CTYPE, NULL) != NULL || getenv("LANG") != NULL) 867231990Smp# else 868231990Smp if (getenv("LANG") != NULL) 869231990Smp# endif 870231990Smp autoset_kanji(); 871231990Smp#endif /* AUTOSET_KANJI */ 872100616Smp fix_version(); /* publish the shell version */ 873100616Smp 874100616Smp if (argc > 1 && strcmp(argv[1], "--version") == 0) { 875100616Smp xprintf("%S\n", varval(STRversion)); 876100616Smp xexit(0); 877100616Smp } 878145479Smp if (argc > 1 && strcmp(argv[1], "--help") == 0) { 879145479Smp xprintf("%S\n\n", varval(STRversion)); 880195609Smp xprintf("%s", CGETS(11, 8, HELP_STRING)); 881145479Smp xexit(0); 882145479Smp } 88369408Sache /* 88459243Sobrien * Process the arguments. 88559243Sobrien * 88659243Sobrien * Note that processing of -v/-x is actually delayed till after script 88759243Sobrien * processing. 88859243Sobrien * 88959243Sobrien * We set the first character of our name to be '-' if we are a shell 89059243Sobrien * running interruptible commands. Many programs which examine ps'es 89159243Sobrien * use this to filter such shells out. 89259243Sobrien */ 89359243Sobrien argc--, tempv++; 89459243Sobrien while (argc > 0 && (tcp = tempv[0])[0] == '-' && 89559243Sobrien *++tcp != '\0' && !batch) { 89659243Sobrien do 89759243Sobrien switch (*tcp++) { 89859243Sobrien 89959243Sobrien case 0: /* - Interruptible, no prompt */ 90059243Sobrien prompt = 0; 90159243Sobrien setintr = 1; 90259243Sobrien nofile = 1; 90359243Sobrien break; 90459243Sobrien 90559243Sobrien case 'b': /* -b Next arg is input file */ 90659243Sobrien batch = 1; 90759243Sobrien break; 90859243Sobrien 90959243Sobrien case 'c': /* -c Command input from arg */ 91059243Sobrien if (argc == 1) 91159243Sobrien xexit(0); 91259243Sobrien argc--, tempv++; 91359243Sobrien#ifdef M_XENIX 91459243Sobrien /* Xenix Vi bug: 91559243Sobrien it relies on a 7 bit environment (/bin/sh), so it 91659243Sobrien pass ascii arguments with the 8th bit set */ 91759243Sobrien if (!strcmp(argv[0], "sh")) 91859243Sobrien { 91959243Sobrien char *p; 92059243Sobrien 92159243Sobrien for (p = tempv[0]; *p; ++p) 92259243Sobrien *p &= ASCII; 92359243Sobrien } 92459243Sobrien#endif 92559243Sobrien arginp = SAVE(tempv[0]); 92659243Sobrien 92759243Sobrien /* 92859243Sobrien * we put the command into a variable 92959243Sobrien */ 93059243Sobrien if (arginp != NULL) 931167465Smp setv(STRcommand, quote(Strsave(arginp)), VAR_READWRITE); 93259243Sobrien 93359243Sobrien /* 93459243Sobrien * * Give an error on -c arguments that end in * backslash to 93559243Sobrien * ensure that you don't make * nonportable csh scripts. 93659243Sobrien */ 93759243Sobrien { 938145479Smp int count; 93959243Sobrien 940167465Smp cp = Strend(arginp); 94159243Sobrien count = 0; 94259243Sobrien while (cp > arginp && *--cp == '\\') 94359243Sobrien ++count; 94459243Sobrien if ((count & 1) != 0) { 94559243Sobrien exiterr = 1; 94659243Sobrien stderror(ERR_ARGC); 94759243Sobrien } 94859243Sobrien } 94959243Sobrien prompt = 0; 95059243Sobrien nofile = 1; 95159243Sobrien break; 95259243Sobrien case 'd': /* -d Load directory stack from file */ 95359243Sobrien rdirs = 1; 95459243Sobrien break; 95559243Sobrien 95659243Sobrien#ifdef apollo 95759243Sobrien case 'D': /* -D Define environment variable */ 95859243Sobrien { 959145479Smp Char *dp; 96059243Sobrien 96159243Sobrien cp = str2short(tcp); 96259243Sobrien if (dp = Strchr(cp, '=')) { 96359243Sobrien *dp++ = '\0'; 96459243Sobrien tsetenv(cp, dp); 96559243Sobrien } 96659243Sobrien else 96759243Sobrien tsetenv(cp, STRNULL); 96859243Sobrien } 96959243Sobrien *tcp = '\0'; /* done with this argument */ 97059243Sobrien break; 97159243Sobrien#endif /* apollo */ 97259243Sobrien 97359243Sobrien case 'e': /* -e Exit on any error */ 97459243Sobrien exiterr = 1; 97559243Sobrien break; 97659243Sobrien 97759243Sobrien case 'f': /* -f Fast start */ 97859243Sobrien fast = 1; 97959243Sobrien break; 98059243Sobrien 98159243Sobrien case 'i': /* -i Interactive, even if !intty */ 98259243Sobrien intact = 1; 98359243Sobrien nofile = 1; 98459243Sobrien break; 98559243Sobrien 98659243Sobrien case 'm': /* -m read .cshrc (from su) */ 98759243Sobrien mflag = 1; 98859243Sobrien break; 98959243Sobrien 99059243Sobrien case 'n': /* -n Don't execute */ 99159243Sobrien noexec = 1; 99259243Sobrien break; 99359243Sobrien 99459243Sobrien case 'q': /* -q (Undoc'd) ... die on quit */ 99559243Sobrien quitit = 1; 99659243Sobrien break; 99759243Sobrien 99859243Sobrien case 's': /* -s Read from std input */ 99959243Sobrien nofile = 1; 100059243Sobrien break; 100159243Sobrien 100259243Sobrien case 't': /* -t Read one line from input */ 100359243Sobrien onelflg = 2; 100459243Sobrien prompt = 0; 100559243Sobrien nofile = 1; 100659243Sobrien break; 100759243Sobrien 100859243Sobrien case 'v': /* -v Echo hist expanded input */ 100959243Sobrien nverbose = 1; /* ... later */ 101059243Sobrien break; 101159243Sobrien 101259243Sobrien case 'x': /* -x Echo just before execution */ 101359243Sobrien nexececho = 1; /* ... later */ 101459243Sobrien break; 101559243Sobrien 101659243Sobrien case 'V': /* -V Echo hist expanded input */ 101759243Sobrien setNS(STRverbose); /* NOW! */ 101859243Sobrien break; 101959243Sobrien 102059243Sobrien case 'X': /* -X Echo just before execution */ 102159243Sobrien setNS(STRecho); /* NOW! */ 102259243Sobrien break; 102359243Sobrien 1024167465Smp case 'F': 102559243Sobrien /* 102659243Sobrien * This will cause children to be created using fork instead of 102759243Sobrien * vfork. 102859243Sobrien */ 102959243Sobrien use_fork = 1; 103059243Sobrien break; 103159243Sobrien 103259243Sobrien case ' ': 103359243Sobrien case '\t': 1034231990Smp case '\r': 1035231990Smp case '\n': 103659243Sobrien /* 103759243Sobrien * for O/S's that don't do the argument parsing right in 103859243Sobrien * "#!/foo -f " scripts 103959243Sobrien */ 104059243Sobrien break; 104159243Sobrien 104259243Sobrien default: /* Unknown command option */ 104359243Sobrien exiterr = 1; 104459243Sobrien stderror(ERR_TCSHUSAGE, tcp-1, progname); 104559243Sobrien break; 104659243Sobrien 104759243Sobrien } while (*tcp); 104859243Sobrien tempv++, argc--; 104959243Sobrien } 105059243Sobrien 105159243Sobrien if (quitit) /* With all due haste, for debugging */ 105259243Sobrien (void) signal(SIGQUIT, SIG_DFL); 105359243Sobrien 105459243Sobrien /* 105559243Sobrien * Unless prevented by -, -c, -i, -s, or -t, if there are remaining 105659243Sobrien * arguments the first of them is the name of a shell file from which to 105759243Sobrien * read commands. 105859243Sobrien */ 105959243Sobrien if (nofile == 0 && argc > 0) { 1060167465Smp nofile = xopen(tempv[0], O_RDONLY|O_LARGEFILE); 106159243Sobrien if (nofile < 0) { 106259243Sobrien child = 1; /* So this ... */ 106359243Sobrien /* ... doesn't return */ 106459243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 106559243Sobrien } 1066167465Smp xfree(ffile); 106759243Sobrien dolzero = 1; 106859243Sobrien ffile = SAVE(tempv[0]); 106959243Sobrien /* 107059243Sobrien * Replace FSHIN. Handle /dev/std{in,out,err} specially 107159243Sobrien * since once they are closed we cannot open them again. 107259243Sobrien * In that case we use our own saved descriptors 107359243Sobrien */ 107459243Sobrien if ((SHIN = dmove(nofile, FSHIN)) < 0) 107559243Sobrien switch(nofile) { 107659243Sobrien case 0: 107759243Sobrien SHIN = FSHIN; 107859243Sobrien break; 107959243Sobrien case 1: 108059243Sobrien SHIN = FSHOUT; 108159243Sobrien break; 108259243Sobrien case 2: 108359243Sobrien SHIN = FSHDIAG; 108459243Sobrien break; 108559243Sobrien default: 108659243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 108759243Sobrien break; 108859243Sobrien } 108959243Sobrien (void) close_on_exec(SHIN, 1); 109059243Sobrien prompt = 0; 109159243Sobrien /* argc not used any more */ tempv++; 109259243Sobrien } 109359243Sobrien 1094100616Smp /* 1095100616Smp * Call to closem() used to be part of initdesc(). Now called below where 1096100616Smp * the script name argument has become stdin. Kernel may have used a file 1097100616Smp * descriptor to hold the name of the script (setuid case) and this name 1098100616Smp * mustn't be lost by closing the fd too soon. 1099100616Smp */ 1100100616Smp closem(); 110159243Sobrien 110259243Sobrien /* 110359243Sobrien * Consider input a tty if it really is or we are interactive. but not for 110459243Sobrien * editing (christos) 110559243Sobrien */ 110659243Sobrien if (!(intty = isatty(SHIN))) { 110759243Sobrien if (adrof(STRedit)) 110859243Sobrien unsetv(STRedit); 110959243Sobrien editing = 0; 111059243Sobrien } 111159243Sobrien intty |= intact; 111259243Sobrien#ifndef convex 111359243Sobrien if (intty || (intact && isatty(SHOUT))) { 111459243Sobrien if (!batch && (uid != euid || gid != egid)) { 111559243Sobrien errno = EACCES; 111659243Sobrien child = 1; /* So this ... */ 111759243Sobrien /* ... doesn't return */ 111859243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 111959243Sobrien } 112059243Sobrien } 112159243Sobrien#endif /* convex */ 112259243Sobrien isoutatty = isatty(SHOUT); 112359243Sobrien isdiagatty = isatty(SHDIAG); 112459243Sobrien /* 112559243Sobrien * Decide whether we should play with signals or not. If we are explicitly 112659243Sobrien * told (via -i, or -) or we are a login shell (arg0 starts with -) or the 112759243Sobrien * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 112859243Sobrien * Note that in only the login shell is it likely that parent may have set 112959243Sobrien * signals to be ignored 113059243Sobrien */ 113159243Sobrien if (loginsh || intact || (intty && isatty(SHOUT))) 113259243Sobrien setintr = 1; 113359243Sobrien settell(); 113459243Sobrien /* 113559243Sobrien * Save the remaining arguments in argv. 113659243Sobrien */ 113759243Sobrien setq(STRargv, blk2short(tempv), &shvhed, VAR_READWRITE); 113859243Sobrien 113959243Sobrien /* 114059243Sobrien * Set up the prompt. 114159243Sobrien */ 114259243Sobrien if (prompt) { 1143231990Smp setcopy(STRprompt, STRdefprompt, VAR_READWRITE); 114459243Sobrien /* that's a meta-questionmark */ 1145167465Smp setcopy(STRprompt2, STRmquestion, VAR_READWRITE); 1146167465Smp setcopy(STRprompt3, STRKCORRECT, VAR_READWRITE); 114759243Sobrien } 114859243Sobrien 114959243Sobrien /* 115059243Sobrien * If we are an interactive shell, then start fiddling with the signals; 115159243Sobrien * this is a tricky game. 115259243Sobrien */ 115359243Sobrien shpgrp = mygetpgrp(); 115459243Sobrien opgrp = tpgrp = -1; 115559243Sobrien if (setintr) { 1156167465Smp struct sigaction osig; 1157167465Smp 115859243Sobrien **argv = '-'; 115959243Sobrien if (!quitit) /* Wary! */ 116059243Sobrien (void) signal(SIGQUIT, SIG_IGN); 1161167465Smp pintr_disabled = 1; 1162167465Smp sigset_interrupting(SIGINT, queue_pintr); 116359243Sobrien (void) signal(SIGTERM, SIG_IGN); 116459243Sobrien 116559243Sobrien /* 116659243Sobrien * No reason I can see not to save history on all these events.. 116759243Sobrien * Most usual occurrence is in a window system, where we're not a login 116859243Sobrien * shell, but might as well be... (sg) 116959243Sobrien * But there might be races when lots of shells exit together... 117059243Sobrien * [this is also incompatible]. 117159243Sobrien * We have to be mre careful here. If the parent wants to 117259243Sobrien * ignore the signals then we leave them untouched... 117359243Sobrien * We also only setup the handlers for shells that are trully 117459243Sobrien * interactive. 117559243Sobrien */ 1176167465Smp sigaction(SIGHUP, NULL, &osig); 1177167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1178167465Smp /* exit processing on HUP */ 1179167465Smp sigset_interrupting(SIGHUP, queue_phup); 118059243Sobrien#ifdef SIGXCPU 1181167465Smp sigaction(SIGXCPU, NULL, &osig); 1182167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1183167465Smp /* exit processing on XCPU */ 1184167465Smp sigset_interrupting(SIGXCPU, queue_phup); 118559243Sobrien#endif 118659243Sobrien#ifdef SIGXFSZ 1187167465Smp sigaction(SIGXFSZ, NULL, &osig); 1188167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1189167465Smp /* exit processing on XFSZ */ 1190167465Smp sigset_interrupting(SIGXFSZ, queue_phup); 119159243Sobrien#endif 119259243Sobrien 119359243Sobrien if (quitit == 0 && arginp == 0) { 119459243Sobrien#ifdef SIGTSTP 119559243Sobrien (void) signal(SIGTSTP, SIG_IGN); 119659243Sobrien#endif 119759243Sobrien#ifdef SIGTTIN 119859243Sobrien (void) signal(SIGTTIN, SIG_IGN); 119959243Sobrien#endif 120059243Sobrien#ifdef SIGTTOU 120159243Sobrien (void) signal(SIGTTOU, SIG_IGN); 120259243Sobrien#endif 120359243Sobrien /* 120459243Sobrien * Wait till in foreground, in case someone stupidly runs csh & 120559243Sobrien * dont want to try to grab away the tty. 120659243Sobrien */ 120759243Sobrien if (isatty(FSHDIAG)) 120859243Sobrien f = FSHDIAG; 120959243Sobrien else if (isatty(FSHOUT)) 121059243Sobrien f = FSHOUT; 121159243Sobrien else if (isatty(OLDSTD)) 121259243Sobrien f = OLDSTD; 121359243Sobrien else 121459243Sobrien f = -1; 121559243Sobrien 121659243Sobrien#ifdef NeXT 121759243Sobrien /* NeXT 2.0 /usr/etc/rlogind, does not set our process group! */ 121859243Sobrien if (shpgrp == 0) { 121959243Sobrien shpgrp = getpid(); 122059243Sobrien (void) setpgid(0, shpgrp); 122159243Sobrien (void) tcsetpgrp(f, shpgrp); 122259243Sobrien } 122359243Sobrien#endif /* NeXT */ 122459243Sobrien#ifdef BSDJOBS /* if we have tty job control */ 1225195609Smp if (grabpgrp(f, shpgrp) != -1) { 122659243Sobrien /* 122759243Sobrien * Thanks to Matt Day for the POSIX references, and to 122859243Sobrien * Paul Close for the SGI clarification. 122959243Sobrien */ 123059243Sobrien if (setdisc(f) != -1) { 123159243Sobrien opgrp = shpgrp; 123259243Sobrien shpgrp = getpid(); 123359243Sobrien tpgrp = shpgrp; 123459243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 123559243Sobrien /* 123659243Sobrien * On hpux 7.03 this fails with EPERM. This happens on 123759243Sobrien * the 800 when opgrp != shpgrp at this point. (we were 123859243Sobrien * forked from a non job control shell) 123959243Sobrien * POSIX 7.2.4, says we failed because the process 124059243Sobrien * group specified did not belong to a process 124159243Sobrien * in the same session with the tty. So we set our 124259243Sobrien * process group and try again. 124359243Sobrien */ 124459243Sobrien if (setpgid(0, shpgrp) == -1) { 124559243Sobrien xprintf("setpgid:"); 124659243Sobrien goto notty; 124759243Sobrien } 124859243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 124959243Sobrien xprintf("tcsetpgrp:"); 125059243Sobrien goto notty; 125159243Sobrien } 125259243Sobrien } 125359243Sobrien /* 125459243Sobrien * We check the process group now. If it is the same, then 125559243Sobrien * we don't need to set it again. On hpux 7.0 on the 300's 125659243Sobrien * if we set it again it fails with EPERM. This is the 125759243Sobrien * correct behavior according to POSIX 4.3.3 if the process 125859243Sobrien * was a session leader . 125959243Sobrien */ 126059243Sobrien else if (shpgrp != mygetpgrp()) { 126159243Sobrien if(setpgid(0, shpgrp) == -1) { 126259243Sobrien xprintf("setpgid:"); 126359243Sobrien goto notty; 126459243Sobrien } 126559243Sobrien } 126659243Sobrien#ifdef IRIS4D 126759243Sobrien /* 126859243Sobrien * But on irix 3.3 we need to set it again, even if it is 126959243Sobrien * the same. We do that to tell the system that we 127059243Sobrien * need BSD process group compatibility. 127159243Sobrien */ 127259243Sobrien else 127359243Sobrien (void) setpgid(0, shpgrp); 127459243Sobrien#endif 127559243Sobrien (void) close_on_exec(dcopy(f, FSHTTY), 1); 127659243Sobrien } 127759243Sobrien else 127859243Sobrien tpgrp = -1; 127959243Sobrien } 128059243Sobrien if (tpgrp == -1) { 128159243Sobrien notty: 1282167465Smp xprintf(CGETS(11, 1, "Warning: no access to tty (%s).\n"), 1283195609Smp strerror(errno)); 1284195609Smp xprintf("%s", 1285195609Smp CGETS(11, 2, "Thus no job control in this shell.\n")); 128659243Sobrien /* 128759243Sobrien * Fix from:Sakari Jalovaara <sja@sirius.hut.fi> if we don't 128859243Sobrien * have access to tty, disable editing too 128959243Sobrien */ 129059243Sobrien if (adrof(STRedit)) 129159243Sobrien unsetv(STRedit); 129259243Sobrien editing = 0; 129359243Sobrien } 129459243Sobrien#else /* BSDJOBS */ /* don't have job control, so frotz it */ 129559243Sobrien tpgrp = -1; 129659243Sobrien#endif /* BSDJOBS */ 129759243Sobrien } 129859243Sobrien } 1299167465Smp if (setintr == 0 && parintr.sa_handler == SIG_DFL) 130059243Sobrien setintr = 1; 130159243Sobrien 130259243Sobrien/* 130359243Sobrien * SVR4 doesn't send a SIGCHLD when a child is stopped or continued if the 130459243Sobrien * handler is installed with signal(2) or sigset(2). sigaction(2) must 130559243Sobrien * be used instead. 130659243Sobrien * 130759243Sobrien * David Dawes (dawes@physics.su.oz.au) Sept 1991 130859243Sobrien */ 1309167465Smp sigset_interrupting(SIGCHLD, queue_pchild); 131059243Sobrien 131159243Sobrien if (intty && !arginp) 131259243Sobrien (void) ed_Setup(editing);/* Get the tty state, and set defaults */ 131359243Sobrien /* Only alter the tty state if editing */ 131459243Sobrien 131559243Sobrien /* 131659243Sobrien * Set an exit here in case of an interrupt or error reading the shell 131759243Sobrien * start-up scripts. 131859243Sobrien */ 1319131962Smp osetintr = setintr; 1320131962Smp oparintr = parintr; 1321167465Smp (void)cleanup_push_mark(); /* There is no outer handler */ 1322167465Smp if (setexit() != 0) /* PWP */ 1323167465Smp reenter = 1; 1324167465Smp else 1325167465Smp reenter = 0; 132669408Sache exitset++; 132759243Sobrien haderr = 0; /* In case second time through */ 132859243Sobrien if (!fast && reenter == 0) { 132959243Sobrien /* Will have varval(STRhome) here because set fast if don't */ 133059243Sobrien { 1331167465Smp pintr_disabled++; 1332167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1333167465Smp setintr = 0;/*FIXRESET:cleanup*/ 1334167465Smp /* onintr in /etc/ files has no effect */ 1335167465Smp parintr.sa_handler = SIG_IGN;/*FIXRESET: cleanup*/ 133659243Sobrien#ifdef LOGINFIRST 133759243Sobrien#ifdef _PATH_DOTLOGIN 133859243Sobrien if (loginsh) 1339167465Smp (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 134059243Sobrien#endif 134159243Sobrien#endif 134259243Sobrien 134359243Sobrien#ifdef _PATH_DOTCSHRC 134459243Sobrien (void) srcfile(_PATH_DOTCSHRC, 0, 0, NULL); 134559243Sobrien#endif 134659243Sobrien if (!arginp && !onelflg && !havhash) 134759243Sobrien dohash(NULL,NULL); 134859243Sobrien#ifndef LOGINFIRST 134959243Sobrien#ifdef _PATH_DOTLOGIN 135059243Sobrien if (loginsh) 135159243Sobrien (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 135259243Sobrien#endif 135359243Sobrien#endif 1354167465Smp cleanup_until(&pintr_disabled); 135559243Sobrien setintr = osetintr; 135659243Sobrien parintr = oparintr; 135759243Sobrien } 135859243Sobrien#ifdef LOGINFIRST 135959243Sobrien if (loginsh) 136059243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 136159243Sobrien#endif 136259243Sobrien /* upward compat. */ 136359243Sobrien if (!srccat(varval(STRhome), STRsldottcshrc)) 136459243Sobrien (void) srccat(varval(STRhome), STRsldotcshrc); 136559243Sobrien 1366167465Smp if (!arginp && !onelflg && !havhash) 136759243Sobrien dohash(NULL,NULL); 136859243Sobrien 136959243Sobrien /* 137059243Sobrien * Source history before .login so that it is available in .login 137159243Sobrien */ 137259243Sobrien loadhist(NULL, 0); 137359243Sobrien#ifndef LOGINFIRST 137459243Sobrien if (loginsh) 137559243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 137659243Sobrien#endif 1377167465Smp if (loginsh || rdirs) 137859243Sobrien loaddirs(NULL); 137959243Sobrien } 1380131962Smp /* Reset interrupt flag */ 1381131962Smp setintr = osetintr; 1382131962Smp parintr = oparintr; 1383167465Smp exitset--; 1384131962Smp 138559243Sobrien /* Initing AFTER .cshrc is the Right Way */ 138659243Sobrien if (intty && !arginp) { /* PWP setup stuff */ 138759243Sobrien ed_Init(); /* init the new line editor */ 138859243Sobrien#ifdef SIG_WINDOW 138959243Sobrien check_window_size(1); /* mung environment */ 139059243Sobrien#endif /* SIG_WINDOW */ 139159243Sobrien } 139259243Sobrien 139359243Sobrien /* 139459243Sobrien * Now are ready for the -v and -x flags 139559243Sobrien */ 139659243Sobrien if (nverbose) 139759243Sobrien setNS(STRverbose); 139859243Sobrien if (nexececho) 139959243Sobrien setNS(STRecho); 140059243Sobrien 140159243Sobrien /* 140259243Sobrien * All the rest of the world is inside this call. The argument to process 140359243Sobrien * indicates whether it should catch "error unwinds". Thus if we are a 140459243Sobrien * interactive shell our call here will never return by being blown past on 140559243Sobrien * an error. 140659243Sobrien */ 140759243Sobrien process(setintr); 140859243Sobrien 140959243Sobrien /* 141059243Sobrien * Mop-up. 141159243Sobrien */ 1412197812Srdivacky /* Take care of these (especially HUP) here instead of inside flush. */ 1413197812Srdivacky handle_pending_signals(); 141459243Sobrien if (intty) { 141559243Sobrien if (loginsh) { 141659243Sobrien xprintf("logout\n"); 1417167465Smp xclose(SHIN); 141859243Sobrien child = 1; 141959243Sobrien#ifdef TESLA 142059243Sobrien do_logout = 1; 142159243Sobrien#endif /* TESLA */ 142259243Sobrien goodbye(NULL, NULL); 142359243Sobrien } 142459243Sobrien else { 142559243Sobrien xprintf("exit\n"); 142659243Sobrien } 142759243Sobrien } 142859243Sobrien record(); 142959243Sobrien exitstat(); 143059243Sobrien return (0); 143159243Sobrien} 143259243Sobrien 143359243Sobrienvoid 1434167465Smpuntty(void) 143559243Sobrien{ 143659243Sobrien#ifdef BSDJOBS 143759243Sobrien if (tpgrp > 0 && opgrp != shpgrp) { 143859243Sobrien (void) setpgid(0, opgrp); 143959243Sobrien (void) tcsetpgrp(FSHTTY, opgrp); 144059243Sobrien (void) resetdisc(FSHTTY); 144159243Sobrien } 144259243Sobrien#endif /* BSDJOBS */ 144359243Sobrien} 144459243Sobrien 144559243Sobrienvoid 1446167465Smpimportpath(Char *cp) 144759243Sobrien{ 1448167465Smp size_t i = 0; 1449145479Smp Char *dp; 1450145479Smp Char **pv; 145159243Sobrien int c; 145259243Sobrien 145359243Sobrien for (dp = cp; *dp; dp++) 145459243Sobrien if (*dp == PATHSEP) 145559243Sobrien i++; 145659243Sobrien /* 145759243Sobrien * i+2 where i is the number of colons in the path. There are i+1 145859243Sobrien * directories in the path plus we need room for a zero terminator. 145959243Sobrien */ 1460167465Smp pv = xcalloc(i + 2, sizeof(Char *)); 146159243Sobrien dp = cp; 146259243Sobrien i = 0; 146359243Sobrien if (*dp) 146459243Sobrien for (;;) { 146559243Sobrien if ((c = *dp) == PATHSEP || c == 0) { 146659243Sobrien *dp = 0; 146759243Sobrien pv[i++] = Strsave(*cp ? cp : STRdot); 146859243Sobrien if (c) { 146959243Sobrien cp = dp + 1; 147059243Sobrien *dp = PATHSEP; 147159243Sobrien } 147259243Sobrien else 147359243Sobrien break; 147459243Sobrien } 147569408Sache#ifdef WINNT_NATIVE 147659243Sobrien else if (*dp == '\\') 147759243Sobrien *dp = '/'; 147869408Sache#endif /* WINNT_NATIVE */ 147959243Sobrien dp++; 148059243Sobrien } 148159243Sobrien pv[i] = 0; 1482167465Smp cleanup_push(pv, blk_cleanup); 148359243Sobrien setq(STRpath, pv, &shvhed, VAR_READWRITE); 1484167465Smp cleanup_ignore(pv); 1485167465Smp cleanup_until(pv); 148659243Sobrien} 148759243Sobrien 148859243Sobrien/* 148959243Sobrien * Source to the file which is the catenation of the argument names. 149059243Sobrien */ 149159243Sobrienstatic int 1492167465Smpsrccat(Char *cp, Char *dp) 149359243Sobrien{ 149459243Sobrien if (cp[0] == '/' && cp[1] == '\0') 149559243Sobrien return srcfile(short2str(dp), (mflag ? 0 : 1), 0, NULL); 149659243Sobrien else { 1497145479Smp Char *ep; 149859243Sobrien char *ptr; 149959243Sobrien int rv; 150059243Sobrien 150169408Sache#ifdef WINNT_NATIVE 1502167465Smp ep = Strend(cp); 1503167465Smp if (ep != cp && ep[-1] == '/' && dp[0] == '/') /* silly win95 */ 150459243Sobrien dp++; 150569408Sache#endif /* WINNT_NATIVE */ 150659243Sobrien 150759243Sobrien ep = Strspl(cp, dp); 1508167465Smp cleanup_push(ep, xfree); 150959243Sobrien ptr = short2str(ep); 151059243Sobrien 151159243Sobrien rv = srcfile(ptr, (mflag ? 0 : 1), 0, NULL); 1512167465Smp cleanup_until(ep); 151359243Sobrien return rv; 151459243Sobrien } 151559243Sobrien} 151659243Sobrien 151759243Sobrien/* 151859243Sobrien * Source to a file putting the file descriptor in a safe place (> 2). 151959243Sobrien */ 152083098Smp#ifndef WINNT_NATIVE 152159243Sobrienstatic int 152283098Smp#else 152383098Smpint 152483098Smp#endif /*WINNT_NATIVE*/ 1525167465Smpsrcfile(const char *f, int onlyown, int flag, Char **av) 152659243Sobrien{ 1527145479Smp int unit; 152859243Sobrien 1529167465Smp if ((unit = xopen(f, O_RDONLY|O_LARGEFILE)) == -1) 153059243Sobrien return 0; 1531167465Smp cleanup_push(&unit, open_cleanup); 153259243Sobrien unit = dmove(unit, -1); 1533167465Smp cleanup_ignore(&unit); 1534167465Smp cleanup_until(&unit); 153559243Sobrien 153659243Sobrien (void) close_on_exec(unit, 1); 153759243Sobrien srcunit(unit, onlyown, flag, av); 153859243Sobrien return 1; 153959243Sobrien} 154059243Sobrien 154159243Sobrien 154259243Sobrien/* 154359243Sobrien * Save the shell state, and establish new argument vector, and new input 154459243Sobrien * fd. 154559243Sobrien */ 154659243Sobrienstatic void 1547167465Smpst_save(struct saved_state *st, int unit, int hflg, Char **al, Char **av) 154859243Sobrien{ 154959243Sobrien st->insource = insource; 155059243Sobrien st->SHIN = SHIN; 1551100616Smp /* Want to preserve the meaning of "source file >output". 1552100616Smp * Save old descriptors, move new 0,1,2 to safe places and assign 1553100616Smp * them to SH* and let process() redo 0,1,2 from them. 1554100616Smp * 1555100616Smp * The macro returns true if d1 and d2 are good and they point to 1556100616Smp * different things. If you don't avoid saving duplicate 1557100616Smp * descriptors, you really limit the depth of "source" recursion 1558100616Smp * you can do because of all the open file descriptors. -IAN! 1559100616Smp */ 1560100616Smp#define NEED_SAVE_FD(d1,d2) \ 1561100616Smp (fstat(d1, &s1) != -1 && fstat(d2, &s2) != -1 \ 1562100616Smp && (s1.st_ino != s2.st_ino || s1.st_dev != s2.st_dev) ) 1563100616Smp 1564100616Smp st->OLDSTD = st->SHOUT = st->SHDIAG = -1;/* test later to restore these */ 1565100616Smp if (didfds) { 1566100616Smp struct stat s1, s2; 1567145479Smp if (NEED_SAVE_FD(0,OLDSTD)) { 1568145479Smp st->OLDSTD = OLDSTD; 1569145479Smp OLDSTD = dmove(0, -1); 1570145479Smp (void)close_on_exec(OLDSTD, 1); 1571145479Smp } 1572145479Smp if (NEED_SAVE_FD(1,SHOUT)) { 1573145479Smp st->SHOUT = SHOUT; 1574145479Smp SHOUT = dmove(1, -1); 1575145479Smp (void)close_on_exec(SHOUT, 1); 1576145479Smp } 1577145479Smp if (NEED_SAVE_FD(2,SHDIAG)) { 1578145479Smp st->SHDIAG = SHDIAG; 1579145479Smp SHDIAG = dmove(2, -1); 1580145479Smp (void)close_on_exec(SHDIAG, 1); 1581145479Smp } 1582100616Smp donefds(); 1583100616Smp } 1584100616Smp 158559243Sobrien st->intty = intty; 158659243Sobrien st->whyles = whyles; 158759243Sobrien st->gointr = gointr; 158859243Sobrien st->arginp = arginp; 158959243Sobrien st->evalp = evalp; 159059243Sobrien st->evalvec = evalvec; 159159243Sobrien st->alvecp = alvecp; 159259243Sobrien st->alvec = alvec; 159359243Sobrien st->onelflg = onelflg; 159459243Sobrien st->enterhist = enterhist; 1595195609Smp st->justpr = justpr; 159659243Sobrien if (hflg) 159759243Sobrien st->HIST = HIST; 159859243Sobrien else 159959243Sobrien st->HIST = '\0'; 160059243Sobrien st->cantell = cantell; 160159243Sobrien cpybin(st->B, B); 160259243Sobrien 160359243Sobrien /* 160459243Sobrien * we can now pass arguments to source. 160559243Sobrien * For compatibility we do that only if arguments were really 160659243Sobrien * passed, otherwise we keep the old, global $argv like before. 160759243Sobrien */ 160859243Sobrien if (av != NULL && *av != NULL) { 160959243Sobrien struct varent *vp; 1610100616Smp if ((vp = adrof(STRargv)) != NULL && vp->vec != NULL) 161159243Sobrien st->argv = saveblk(vp->vec); 161259243Sobrien else 161359243Sobrien st->argv = NULL; 161459243Sobrien setq(STRargv, saveblk(av), &shvhed, VAR_READWRITE); 161559243Sobrien } 161659243Sobrien else 161759243Sobrien st->argv = NULL; 1618167465Smp st->av = av; 161959243Sobrien 162059243Sobrien SHIN = unit; /* Do this first */ 162159243Sobrien 162259243Sobrien /* Establish new input arena */ 162359243Sobrien { 162459243Sobrien fbuf = NULL; 162559243Sobrien fseekp = feobp = fblocks = 0; 162659243Sobrien settell(); 162759243Sobrien } 162859243Sobrien 162959243Sobrien arginp = 0; 163059243Sobrien onelflg = 0; 163159243Sobrien intty = isatty(SHIN); 163259243Sobrien whyles = 0; 163359243Sobrien gointr = 0; 163459243Sobrien evalvec = 0; 163559243Sobrien evalp = 0; 163659243Sobrien alvec = al; 163759243Sobrien alvecp = 0; 163859243Sobrien enterhist = hflg; 163959243Sobrien if (enterhist) 164059243Sobrien HIST = '\0'; 164159243Sobrien insource = 1; 164259243Sobrien} 164359243Sobrien 164459243Sobrien 164559243Sobrien/* 164659243Sobrien * Restore the shell to a saved state 164759243Sobrien */ 164859243Sobrienstatic void 1649167465Smpst_restore(void *xst) 1650167465Smp{ 165159243Sobrien struct saved_state *st; 1652167465Smp 1653167465Smp st = xst; 165459243Sobrien if (st->SHIN == -1) 165559243Sobrien return; 165659243Sobrien 165759243Sobrien /* Reset input arena */ 165859243Sobrien { 1659145479Smp int i; 1660145479Smp Char** nfbuf = fbuf; 1661145479Smp int nfblocks = fblocks; 166259243Sobrien 166359243Sobrien fblocks = 0; 166459243Sobrien fbuf = NULL; 166559243Sobrien for (i = 0; i < nfblocks; i++) 1666167465Smp xfree(nfbuf[i]); 1667167465Smp xfree(nfbuf); 166859243Sobrien } 166959243Sobrien cpybin(B, st->B); 167059243Sobrien 1671167465Smp xclose(SHIN); 167259243Sobrien 167359243Sobrien insource = st->insource; 167459243Sobrien SHIN = st->SHIN; 1675100616Smp if (st->OLDSTD != -1) 1676167465Smp xclose(OLDSTD), OLDSTD = st->OLDSTD; 1677100616Smp if (st->SHOUT != -1) 1678167465Smp xclose(SHOUT), SHOUT = st->SHOUT; 1679100616Smp if (st->SHDIAG != -1) 1680167465Smp xclose(SHDIAG), SHDIAG = st->SHDIAG; 168159243Sobrien arginp = st->arginp; 168259243Sobrien onelflg = st->onelflg; 168359243Sobrien evalp = st->evalp; 168459243Sobrien evalvec = st->evalvec; 168559243Sobrien alvecp = st->alvecp; 168659243Sobrien alvec = st->alvec; 168759243Sobrien intty = st->intty; 168859243Sobrien whyles = st->whyles; 168959243Sobrien gointr = st->gointr; 169059243Sobrien if (st->HIST != '\0') 169159243Sobrien HIST = st->HIST; 169259243Sobrien enterhist = st->enterhist; 169359243Sobrien cantell = st->cantell; 1694195609Smp justpr = st->justpr; 169559243Sobrien 169659243Sobrien if (st->argv != NULL) 169759243Sobrien setq(STRargv, st->argv, &shvhed, VAR_READWRITE); 1698167465Smp else if (st->av != NULL && *st->av != NULL && adrof(STRargv) != NULL) 169959243Sobrien unsetv(STRargv); 170059243Sobrien} 170159243Sobrien 170259243Sobrien/* 170359243Sobrien * Source to a unit. If onlyown it must be our file or our group or 170459243Sobrien * we don't chance it. This occurs on ".cshrc"s and the like. 170559243Sobrien */ 170659243Sobrienstatic void 1707167465Smpsrcunit(int unit, int onlyown, int hflg, Char **av) 170859243Sobrien{ 170959243Sobrien struct saved_state st; 1710167465Smp 171159243Sobrien st.SHIN = -1; /* st_restore checks this */ 171259243Sobrien 171359243Sobrien if (unit < 0) 171459243Sobrien return; 171559243Sobrien 171659243Sobrien if (onlyown) { 171759243Sobrien struct stat stb; 171859243Sobrien 171959243Sobrien if (fstat(unit, &stb) < 0) { 1720167465Smp xclose(unit); 172159243Sobrien return; 172259243Sobrien } 172359243Sobrien } 172459243Sobrien 1725167465Smp /* Does nothing before st_save() because st.SHIN == -1 */ 1726167465Smp cleanup_push(&st, st_restore); 1727167465Smp if (setintr) { 1728167465Smp pintr_disabled++; 1729167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1730167465Smp } 173159243Sobrien 173259243Sobrien /* Save the current state and move us to a new state */ 173359243Sobrien st_save(&st, unit, hflg, NULL, av); 173459243Sobrien 173559243Sobrien /* 173659243Sobrien * Now if we are allowing commands to be interrupted, we let ourselves be 173759243Sobrien * interrupted. 173859243Sobrien */ 1739167465Smp if (setintr) { 1740167465Smp cleanup_until(&pintr_disabled); 1741167465Smp pintr_disabled++; 1742167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 174359243Sobrien } 174459243Sobrien 1745167465Smp process(0); /* 0 -> blow away on errors */ 174659243Sobrien 174759243Sobrien /* Restore the old state */ 1748167465Smp cleanup_until(&st); 174959243Sobrien} 175059243Sobrien 175159243Sobrien 175259243Sobrien/*ARGSUSED*/ 175359243Sobrienvoid 1754167465Smpgoodbye(Char **v, struct command *c) 175559243Sobrien{ 1756145479Smp USE(v); 175759243Sobrien USE(c); 175859243Sobrien record(); 175959243Sobrien 176059243Sobrien if (loginsh) { 1761167465Smp size_t omark; 1762167465Smp sigset_t set; 1763167465Smp 1764195609Smp sigemptyset(&set); 1765167465Smp signal(SIGQUIT, SIG_IGN); 1766167465Smp sigaddset(&set, SIGQUIT); 1767167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 1768167465Smp signal(SIGINT, SIG_IGN); 1769167465Smp sigaddset(&set, SIGINT); 1770167465Smp signal(SIGTERM, SIG_IGN); 1771167465Smp sigaddset(&set, SIGTERM); 1772167465Smp signal(SIGHUP, SIG_IGN); 1773167465Smp sigaddset(&set, SIGHUP); 1774167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 1775167465Smp phup_disabled = 1; 177659243Sobrien setintr = 0; /* No interrupts after "logout" */ 177759243Sobrien /* Trap errors inside .logout */ 1778167465Smp omark = cleanup_push_mark(); 1779167465Smp if (setexit() == 0) { 1780167465Smp if (!(adrof(STRlogout))) 1781167465Smp setcopy(STRlogout, STRnormal, VAR_READWRITE); 178259243Sobrien#ifdef _PATH_DOTLOGOUT 1783167465Smp (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 178459243Sobrien#endif 1785167465Smp if (adrof(STRhome)) 1786167465Smp (void) srccat(varval(STRhome), STRsldtlogout); 178759243Sobrien#ifdef TESLA 1788167465Smp do_logout = 1; 178959243Sobrien#endif /* TESLA */ 1790167465Smp } 1791167465Smp cleanup_pop_mark(omark); 179259243Sobrien } 179359243Sobrien exitstat(); 179459243Sobrien} 179559243Sobrien 179659243Sobrienvoid 1797167465Smpexitstat(void) 179859243Sobrien{ 179959243Sobrien#ifdef PROF 1800231990Smp _mcleanup(); 180159243Sobrien#endif 180259243Sobrien /* 180359243Sobrien * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit 180459243Sobrien * directly because we poke child here. Otherwise we might continue 180559243Sobrien * unwarrantedly (sic). 180659243Sobrien */ 180759243Sobrien child = 1; 180859243Sobrien 180959243Sobrien xexit(getn(varval(STRstatus))); 181059243Sobrien} 181159243Sobrien 181259243Sobrien/* 181359243Sobrien * in the event of a HUP we want to save the history 181459243Sobrien */ 1815167465Smpvoid 1816167465Smpphup(void) 181759243Sobrien{ 181859243Sobrien if (loginsh) { 1819167465Smp setcopy(STRlogout, STRhangup, VAR_READWRITE); 182059243Sobrien#ifdef _PATH_DOTLOGOUT 182159243Sobrien (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 182259243Sobrien#endif 182359243Sobrien if (adrof(STRhome)) 182459243Sobrien (void) srccat(varval(STRhome), STRsldtlogout); 182559243Sobrien } 182659243Sobrien 182759243Sobrien record(); 182859243Sobrien 182959243Sobrien#ifdef POSIXJOBS 183059243Sobrien /* 183159243Sobrien * We kill the last foreground process group. It then becomes 183259243Sobrien * responsible to propagate the SIGHUP to its progeny. 183359243Sobrien */ 183459243Sobrien { 183559243Sobrien struct process *pp, *np; 183659243Sobrien 183759243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 183859243Sobrien np = pp; 183959243Sobrien /* 184059243Sobrien * Find if this job is in the foreground. It could be that 184159243Sobrien * the process leader has exited and the foreground flag 184259243Sobrien * is cleared for it. 184359243Sobrien */ 184459243Sobrien do 184559243Sobrien /* 184659243Sobrien * If a process is in the foreground we try to kill 184759243Sobrien * it's process group. If we succeed, then the 184859243Sobrien * whole job is gone. Otherwise we keep going... 184959243Sobrien * But avoid sending HUP to the shell again. 185059243Sobrien */ 185159243Sobrien if (((np->p_flags & PFOREGND) != 0) && np->p_jobid != shpgrp) { 185259243Sobrien np->p_flags &= ~PHUP; 185359243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 185459243Sobrien /* In case the job was suspended... */ 185559243Sobrien#ifdef SIGCONT 185659243Sobrien (void) killpg(np->p_jobid, SIGCONT); 185759243Sobrien#endif 185859243Sobrien break; 185959243Sobrien } 186059243Sobrien } 186159243Sobrien while ((np = np->p_friends) != pp); 186259243Sobrien } 186359243Sobrien } 186459243Sobrien#endif /* POSIXJOBS */ 186559243Sobrien 1866167465Smp xexit(SIGHUP); 186759243Sobrien} 186859243Sobrien 186959243Sobrienstatic Char *jobargv[2] = {STRjobs, 0}; 187059243Sobrien 187159243Sobrien/* 187259243Sobrien * Catch an interrupt, e.g. during lexical input. 187359243Sobrien * If we are an interactive shell, we reset the interrupt catch 187459243Sobrien * immediately. In any case we drain the shell output, 187559243Sobrien * and finally go through the normal error mechanism, which 187659243Sobrien * gets a chance to make the shell go away. 187759243Sobrien */ 1878167465Smpint just_signaled; /* bugfix by Michael Bloom (mg@ttidca.TTI.COM) */ 187959243Sobrien 1880167465Smpvoid 1881167465Smppintr(void) 188259243Sobrien{ 188359243Sobrien just_signaled = 1; 188459243Sobrien pintr1(1); 188559243Sobrien} 188659243Sobrien 188759243Sobrienvoid 1888167465Smppintr1(int wantnl) 188959243Sobrien{ 189059243Sobrien if (setintr) { 189159243Sobrien if (pjobs) { 189259243Sobrien pjobs = 0; 189359243Sobrien xputchar('\n'); 189459243Sobrien dojobs(jobargv, NULL); 189559243Sobrien stderror(ERR_NAME | ERR_INTR); 189659243Sobrien } 189759243Sobrien } 189859243Sobrien /* MH - handle interrupted completions specially */ 189959243Sobrien { 190059243Sobrien if (InsideCompletion) 190159243Sobrien stderror(ERR_SILENT); 190259243Sobrien } 190359243Sobrien /* JV - Make sure we shut off inputl */ 190459243Sobrien { 190559243Sobrien (void) Cookedmode(); 190659243Sobrien GettingInput = 0; 190759243Sobrien } 190859243Sobrien drainoline(); 1909145479Smp#ifdef HAVE_GETPWENT 191059243Sobrien (void) endpwent(); 1911145479Smp#endif 191259243Sobrien 191359243Sobrien /* 191459243Sobrien * If we have an active "onintr" then we search for the label. Note that if 191559243Sobrien * one does "onintr -" then we shan't be interruptible so we needn't worry 191659243Sobrien * about that here. 191759243Sobrien */ 191859243Sobrien if (gointr) { 191959243Sobrien gotolab(gointr); 192059243Sobrien reset(); 192159243Sobrien } 192259243Sobrien else if (intty && wantnl) { 192359243Sobrien if (editing) { 192459243Sobrien /* 192559243Sobrien * If we are editing a multi-line input command, and move to 192659243Sobrien * the beginning of the line, we don't want to trash it when 192759243Sobrien * we hit ^C 192859243Sobrien */ 192959243Sobrien PastBottom(); 193059243Sobrien ClearLines(); 193159243Sobrien ClearDisp(); 193259243Sobrien } 193359243Sobrien else { 193459243Sobrien /* xputchar('\n'); *//* Some like this, others don't */ 193559243Sobrien (void) putraw('\r'); 193659243Sobrien (void) putraw('\n'); 193759243Sobrien } 193859243Sobrien } 193959243Sobrien stderror(ERR_SILENT); 194059243Sobrien} 194159243Sobrien 194259243Sobrien/* 194359243Sobrien * Process is the main driving routine for the shell. 194459243Sobrien * It runs all command processing, except for those within { ... } 194559243Sobrien * in expressions (which is run by a routine evalav in sh.exp.c which 194659243Sobrien * is a stripped down process), and `...` evaluation which is run 194759243Sobrien * also by a subset of this code in sh.glob.c in the routine backeval. 194859243Sobrien * 194959243Sobrien * The code here is a little strange because part of it is interruptible 195059243Sobrien * and hence freeing of structures appears to occur when none is necessary 195159243Sobrien * if this is ignored. 195259243Sobrien * 195359243Sobrien * Note that if catch is not set then we will unwind on any error. 195459243Sobrien * If an end-of-file occurs, we return. 195559243Sobrien */ 195659243Sobrienvoid 1957167465Smpprocess(int catch) 195859243Sobrien{ 195959243Sobrien jmp_buf_t osetexit; 1960231990Smp /* PWP: This might get nuked by longjmp so don't make it a register var */ 1961167465Smp size_t omark; 1962195609Smp volatile int didexitset = 0; 196359243Sobrien 196459243Sobrien getexit(osetexit); 1965167465Smp omark = cleanup_push_mark(); 196659243Sobrien for (;;) { 1967167465Smp struct command *t; 1968167465Smp int hadhist, old_pintr_disabled; 196959243Sobrien 1970195609Smp (void)setexit(); 1971195609Smp if (didexitset == 0) { 1972195609Smp exitset++; 1973195609Smp didexitset++; 1974195609Smp } 197559243Sobrien pendjob(); 197659243Sobrien 197759243Sobrien justpr = enterhist; /* execute if not entering history */ 197859243Sobrien 197959243Sobrien if (haderr) { 198059243Sobrien if (!catch) { 198159243Sobrien /* unwind */ 198259243Sobrien doneinp = 0; 1983167465Smp cleanup_pop_mark(omark); 198459243Sobrien resexit(osetexit); 198559243Sobrien reset(); 198659243Sobrien } 198759243Sobrien haderr = 0; 198859243Sobrien /* 198959243Sobrien * Every error is eventually caught here or the shell dies. It is 199059243Sobrien * at this point that we clean up any left-over open files, by 199159243Sobrien * closing all but a fixed number of pre-defined files. Thus 199259243Sobrien * routines don't have to worry about leaving files open due to 199359243Sobrien * deeper errors... they will get closed here. 199459243Sobrien */ 199559243Sobrien closem(); 199659243Sobrien continue; 199759243Sobrien } 199859243Sobrien if (doneinp) { 199959243Sobrien doneinp = 0; 200059243Sobrien break; 200159243Sobrien } 200259243Sobrien if (chkstop) 200359243Sobrien chkstop--; 200459243Sobrien if (neednote) 200559243Sobrien pnote(); 200659243Sobrien if (intty && prompt && evalvec == 0) { 200759243Sobrien just_signaled = 0; 200859243Sobrien mailchk(); 200959243Sobrien /* 201059243Sobrien * Watch for logins/logouts. Next is scheduled commands stored 201159243Sobrien * previously using "sched." Then execute periodic commands. 201259243Sobrien * Following that, the prompt precmd is run. 201359243Sobrien */ 201459243Sobrien#ifndef HAVENOUTMP 201559243Sobrien watch_login(0); 201659243Sobrien#endif /* !HAVENOUTMP */ 2017167465Smp sched_run(); 201859243Sobrien period_cmd(); 201959243Sobrien precmd(); 202059243Sobrien /* 202159243Sobrien * If we are at the end of the input buffer then we are going to 202259243Sobrien * read fresh stuff. Otherwise, we are rereading input and don't 202359243Sobrien * need or want to prompt. 202459243Sobrien */ 202569408Sache if (fseekp == feobp && aret == TCSH_F_SEEK) 202659243Sobrien printprompt(0, NULL); 202759243Sobrien flush(); 202859243Sobrien setalarm(1); 202959243Sobrien } 203059243Sobrien if (seterr) { 2031167465Smp xfree(seterr); 203259243Sobrien seterr = NULL; 203359243Sobrien } 203459243Sobrien 203559243Sobrien /* 2036167465Smp * Interruptible during interactive reads 2037167465Smp */ 2038167465Smp if (setintr) 2039167465Smp pintr_push_enable(&old_pintr_disabled); 2040167465Smp hadhist = lex(¶ml); 2041167465Smp if (setintr) 2042167465Smp cleanup_until(&old_pintr_disabled); 2043167465Smp cleanup_push(¶ml, lex_cleanup); 2044167465Smp 2045167465Smp /* 204659243Sobrien * Echo not only on VERBOSE, but also with history expansion. If there 204759243Sobrien * is a lexical error then we forego history echo. 2048231990Smp * Do not echo if we're only entering history (source -h). 204959243Sobrien */ 2050167465Smp if ((hadhist && !seterr && intty && !tellwhat && !Expand && !whyles) || 2051231990Smp (!enterhist && adrof(STRverbose))) 2052231990Smp { 2053100616Smp int odidfds = didfds; 205459243Sobrien haderr = 1; 2055100616Smp didfds = 0; 205659243Sobrien prlex(¶ml); 2057100616Smp flush(); 205859243Sobrien haderr = 0; 2059100616Smp didfds = odidfds; 206059243Sobrien } 206159243Sobrien (void) alarm(0); /* Autologout OFF */ 2062167465Smp alrmcatch_disabled = 1; 206359243Sobrien 206459243Sobrien /* 206559243Sobrien * Save input text on the history list if reading in old history, or it 206659243Sobrien * is from the terminal at the top level and not in a loop. 206759243Sobrien * 206859243Sobrien * PWP: entry of items in the history list while in a while loop is done 206959243Sobrien * elsewhere... 207059243Sobrien */ 207159243Sobrien if (enterhist || (catch && intty && !whyles && !tellwhat && !arun)) 207259243Sobrien savehist(¶ml, enterhist > 1); 207359243Sobrien 207459243Sobrien if (Expand && seterr) 207559243Sobrien Expand = 0; 207659243Sobrien 207759243Sobrien /* 207859243Sobrien * Print lexical error messages, except when sourcing history lists. 207959243Sobrien */ 208059243Sobrien if (!enterhist && seterr) 208159243Sobrien stderror(ERR_OLD); 208259243Sobrien 208359243Sobrien /* 208459243Sobrien * If had a history command :p modifier then this is as far as we 208559243Sobrien * should go 208659243Sobrien */ 208759243Sobrien if (justpr) 2088167465Smp goto cmd_done; 208959243Sobrien 209059243Sobrien /* 209159243Sobrien * If had a tellwhat from twenex() then do 209259243Sobrien */ 209359243Sobrien if (tellwhat) { 209459243Sobrien (void) tellmewhat(¶ml, NULL); 2095167465Smp goto cmd_done; 209659243Sobrien } 209759243Sobrien 209859243Sobrien alias(¶ml); 209959243Sobrien 210059243Sobrien#ifdef BSDJOBS 210159243Sobrien /* 210259243Sobrien * If we are interactive, try to continue jobs that we have stopped 210359243Sobrien */ 210459243Sobrien if (prompt) 210559243Sobrien continue_jobs(¶ml); 210659243Sobrien#endif /* BSDJOBS */ 210759243Sobrien 210859243Sobrien /* 210959243Sobrien * Check to see if the user typed "rm * .o" or something 211059243Sobrien */ 211159243Sobrien if (prompt) 211259243Sobrien rmstar(¶ml); 211359243Sobrien /* 211459243Sobrien * Parse the words of the input into a parse tree. 211559243Sobrien */ 2116167465Smp t = syntax(paraml.next, ¶ml, 0); 2117231990Smp /* 2118231990Smp * We cannot cleanup push here, because cd /blah; echo foo 2119231990Smp * would rewind t on the chdir error, and free the rest of the command 2120231990Smp */ 2121231990Smp if (seterr) { 2122231990Smp freesyn(t); 212359243Sobrien stderror(ERR_OLD); 2124231990Smp } 212559243Sobrien 212659243Sobrien postcmd(); 212759243Sobrien /* 212859243Sobrien * Execute the parse tree From: Michael Schroeder 212959243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> was execute(t, tpgrp); 213059243Sobrien */ 2131167465Smp execute(t, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 2132231990Smp freesyn(t); 213359243Sobrien 213459243Sobrien /* 213559243Sobrien * Made it! 213659243Sobrien */ 213759243Sobrien#ifdef SIG_WINDOW 2138100616Smp if (windowchg || (catch && intty && !whyles && !tellwhat)) { 2139100616Smp (void) check_window_size(0); /* for window systems */ 2140100616Smp } 214159243Sobrien#endif /* SIG_WINDOW */ 2142167465Smp setcopy(STR_, InputBuf, VAR_READWRITE | VAR_NOGLOB); 2143167465Smp cmd_done: 2144231990Smp if (cleanup_reset()) 2145231990Smp cleanup_until(¶ml); 2146231990Smp else 2147231990Smp haderr = 1; 214859243Sobrien } 2149167465Smp cleanup_pop_mark(omark); 215059243Sobrien resexit(osetexit); 2151195609Smp exitset--; 2152231990Smp handle_pending_signals(); 215359243Sobrien} 215459243Sobrien 215559243Sobrien/*ARGSUSED*/ 215659243Sobrienvoid 2157167465Smpdosource(Char **t, struct command *c) 215859243Sobrien{ 2159145479Smp Char *f; 2160145479Smp int hflg = 0; 2161167465Smp char *file; 216259243Sobrien 216359243Sobrien USE(c); 216459243Sobrien t++; 216559243Sobrien if (*t && eq(*t, STRmh)) { 216659243Sobrien if (*++t == NULL) 216759243Sobrien stderror(ERR_NAME | ERR_HFLAG); 216859243Sobrien hflg++; 216959243Sobrien } 217059243Sobrien else if (*t && eq(*t, STRmm)) { 217159243Sobrien if (*++t == NULL) 217259243Sobrien stderror(ERR_NAME | ERR_MFLAG); 217359243Sobrien hflg = 2; 217459243Sobrien } 217559243Sobrien 217659243Sobrien f = globone(*t++, G_ERROR); 2177167465Smp file = strsave(short2str(f)); 2178167465Smp cleanup_push(file, xfree); 2179167465Smp xfree(f); 2180167465Smp t = glob_all_or_error(t); 2181167465Smp if ((!srcfile(file, 0, hflg, t)) && (!hflg) && (!bequiet)) 2182167465Smp stderror(ERR_SYSTEM, file, strerror(errno)); 2183167465Smp cleanup_until(file); 218459243Sobrien} 218559243Sobrien 218659243Sobrien/* 218759243Sobrien * Check for mail. 218859243Sobrien * If we are a login shell, then we don't want to tell 218959243Sobrien * about any mail file unless its been modified 219059243Sobrien * after the time we started. 219159243Sobrien * This prevents us from telling the user things he already 219259243Sobrien * knows, since the login program insists on saying 219359243Sobrien * "You have mail." 219459243Sobrien */ 219559243Sobrien 219659243Sobrien/* 219759243Sobrien * The AMS version. 219859243Sobrien * This version checks if the file is a directory, and if so, 219959243Sobrien * tells you the number of files in it, otherwise do the old thang. 220059243Sobrien * The magic "+1" in the time calculation is to compensate for 220159243Sobrien * an AFS bug where directory mtimes are set to 1 second in 220259243Sobrien * the future. 220359243Sobrien */ 220459243Sobrien 220559243Sobrienstatic void 2206167465Smpmailchk(void) 220759243Sobrien{ 2208145479Smp struct varent *v; 2209145479Smp Char **vp; 221059243Sobrien time_t t; 221159243Sobrien int intvl, cnt; 221259243Sobrien struct stat stb; 2213145479Smp int new; 221459243Sobrien 221559243Sobrien v = adrof(STRmail); 2216100616Smp if (v == NULL || v->vec == NULL) 221759243Sobrien return; 221859243Sobrien (void) time(&t); 221959243Sobrien vp = v->vec; 222059243Sobrien cnt = blklen(vp); 222159243Sobrien intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 222259243Sobrien if (intvl < 1) 222359243Sobrien intvl = 1; 222459243Sobrien if (chktim + intvl > t) 222559243Sobrien return; 222659243Sobrien for (; *vp; vp++) { 222759243Sobrien char *filename = short2str(*vp); 222859243Sobrien char *mboxdir = filename; 222959243Sobrien 223059243Sobrien if (stat(filename, &stb) < 0) 223159243Sobrien continue; 223259243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 223359243Sobrien new = stb.st_mtime > time0.tv_sec; 223459243Sobrien#else 223559415Sobrien new = stb.st_mtime > seconds0; 223659243Sobrien#endif 223759243Sobrien if (S_ISDIR(stb.st_mode)) { 223859243Sobrien DIR *mailbox; 223959243Sobrien int mailcount = 0; 2240167465Smp char *tempfilename; 224159243Sobrien struct stat stc; 224259243Sobrien 2243167465Smp tempfilename = xasprintf("%s/new", filename); 224459243Sobrien 224559243Sobrien if (stat(tempfilename, &stc) != -1 && S_ISDIR(stc.st_mode)) { 224659243Sobrien /* 224759243Sobrien * "filename/new" exists and is a directory; you are 224859243Sobrien * using Qmail. 224959243Sobrien */ 225059243Sobrien stb = stc; 225159243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 225259243Sobrien new = stb.st_mtime > time0.tv_sec; 225359243Sobrien#else 225459415Sobrien new = stb.st_mtime > seconds0; 225559243Sobrien#endif 225659243Sobrien mboxdir = tempfilename; 225759243Sobrien } 225859243Sobrien 2259167465Smp if (stb.st_mtime <= chktim + 1 || (loginsh && !new)) { 2260167465Smp xfree(tempfilename); 226159243Sobrien continue; 2262167465Smp } 226359243Sobrien 2264167465Smp mailbox = opendir(mboxdir); 2265167465Smp xfree(tempfilename); 2266167465Smp if (mailbox == NULL) 226759243Sobrien continue; 226859243Sobrien 226959243Sobrien /* skip . and .. */ 2270231990Smp if (!readdir(mailbox) || !readdir(mailbox)) { 2271231990Smp (void)closedir(mailbox); 227259243Sobrien continue; 2273231990Smp } 227459243Sobrien 227559243Sobrien while (readdir(mailbox)) 227659243Sobrien mailcount++; 227759243Sobrien 2278231990Smp (void)closedir(mailbox); 227959243Sobrien if (mailcount == 0) 228059243Sobrien continue; 228159243Sobrien 228259243Sobrien if (cnt == 1) 228359243Sobrien xprintf(CGETS(11, 3, "You have %d mail messages.\n"), 228459243Sobrien mailcount); 228559243Sobrien else 228659243Sobrien xprintf(CGETS(11, 4, "You have %d mail messages in %s.\n"), 228759243Sobrien mailcount, filename); 228859243Sobrien } 228959243Sobrien else { 2290145479Smp char *type; 2291145479Smp 2292231990Smp if (stb.st_size == 0 || stb.st_atime >= stb.st_mtime || 229359243Sobrien (stb.st_atime <= chktim && stb.st_mtime <= chktim) || 229459243Sobrien (loginsh && !new)) 229559243Sobrien continue; 2296145479Smp type = strsave(new ? CGETS(11, 6, "new ") : ""); 2297167465Smp cleanup_push(type, xfree); 229859243Sobrien if (cnt == 1) 2299145479Smp xprintf(CGETS(11, 5, "You have %smail.\n"), type); 230059243Sobrien else 2301145479Smp xprintf(CGETS(11, 7, "You have %smail in %s.\n"), type, filename); 2302167465Smp cleanup_until(type); 230359243Sobrien } 230459243Sobrien } 230559243Sobrien chktim = t; 230659243Sobrien} 230759243Sobrien 230859243Sobrien/* 230959243Sobrien * Extract a home directory from the password file 231059243Sobrien * The argument points to a buffer where the name of the 231159243Sobrien * user whose home directory is sought is currently. 2312167465Smp * We return home directory of the user, or NULL. 231359243Sobrien */ 2314167465SmpChar * 2315167465Smpgethdir(const Char *home) 231659243Sobrien{ 231759243Sobrien Char *h; 231859243Sobrien 231959243Sobrien /* 232059243Sobrien * Is it us? 232159243Sobrien */ 232259243Sobrien if (*home == '\0') { 2323167465Smp if ((h = varval(STRhome)) != STRNULL) 2324167465Smp return Strsave(h); 232559243Sobrien else 2326167465Smp return NULL; 232759243Sobrien } 232859243Sobrien 232959243Sobrien /* 233059243Sobrien * Look in the cache 233159243Sobrien */ 233259243Sobrien if ((h = gettilde(home)) == NULL) 2333167465Smp return NULL; 2334167465Smp else 2335167465Smp return Strsave(h); 233659243Sobrien} 233759243Sobrien 233859243Sobrien/* 233959243Sobrien * Move the initial descriptors to their eventual 234059243Sobrien * resting places, closing all other units. 234159243Sobrien */ 234259243Sobrienvoid 2343167465Smpinitdesc(void) 234459243Sobrien{ 234559243Sobrien#ifdef NLS_BUGS 234659243Sobrien#ifdef NLS_CATALOGS 2347145479Smp nlsclose(); 234859243Sobrien#endif /* NLS_CATALOGS */ 234959243Sobrien#endif /* NLS_BUGS */ 235059243Sobrien 235159243Sobrien 235259243Sobrien didfds = 0; /* 0, 1, 2 aren't set up */ 235359243Sobrien (void) close_on_exec(SHIN = dcopy(0, FSHIN), 1); 235459243Sobrien (void) close_on_exec(SHOUT = dcopy(1, FSHOUT), 1); 235559243Sobrien (void) close_on_exec(SHDIAG = dcopy(2, FSHDIAG), 1); 235659243Sobrien (void) close_on_exec(OLDSTD = dcopy(SHIN, FOLDSTD), 1); 235759243Sobrien#ifndef CLOSE_ON_EXEC 235859243Sobrien didcch = 0; /* Havent closed for child */ 235959243Sobrien#endif /* CLOSE_ON_EXEC */ 2360231990Smp if (SHDIAG >= 0) 2361231990Smp isdiagatty = isatty(SHDIAG); 2362231990Smp else 2363231990Smp isdiagatty = 0; 2364231990Smp if (SHDIAG >= 0) 2365231990Smp isoutatty = isatty(SHOUT); 2366231990Smp else 2367231990Smp isoutatty = 0; 236859243Sobrien#ifdef NLS_BUGS 236959243Sobrien#ifdef NLS_CATALOGS 237059243Sobrien nlsinit(); 237159243Sobrien#endif /* NLS_CATALOGS */ 237259243Sobrien#endif /* NLS_BUGS */ 237359243Sobrien} 237459243Sobrien 237559243Sobrien 237659243Sobrienvoid 237759243Sobrien#ifdef PROF 2378167465Smpdone(int i) 237959243Sobrien#else 2380167465Smpxexit(int i) 238159243Sobrien#endif 238259243Sobrien{ 238359243Sobrien#ifdef TESLA 238459243Sobrien if (loginsh && do_logout) { 238559243Sobrien /* this is to send hangup signal to the develcon */ 238659243Sobrien /* we toggle DTR. clear dtr - sleep 1 - set dtr */ 238759243Sobrien /* ioctl will return ENOTTY for pty's but we ignore it */ 238859243Sobrien /* exitstat will run after disconnect */ 238959243Sobrien /* we sleep for 2 seconds to let things happen in */ 239059243Sobrien /* .logout and rechist() */ 239159243Sobrien#ifdef TIOCCDTR 239259243Sobrien (void) sleep(2); 239359243Sobrien (void) ioctl(FSHTTY, TIOCCDTR, NULL); 239459243Sobrien (void) sleep(1); 239559243Sobrien (void) ioctl(FSHTTY, TIOCSDTR, NULL); 239659243Sobrien#endif /* TIOCCDTR */ 239759243Sobrien } 239859243Sobrien#endif /* TESLA */ 239959243Sobrien 240059243Sobrien { 240159243Sobrien struct process *pp, *np; 2402231990Smp pid_t mypid = getpid(); 240359243Sobrien /* Kill all processes marked for hup'ing */ 240459243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 240559243Sobrien np = pp; 2406231990Smp do 2407231990Smp if ((np->p_flags & PHUP) && np->p_jobid != shpgrp && 2408231990Smp np->p_parentid == mypid) { 240959243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 241059243Sobrien /* In case the job was suspended... */ 241159243Sobrien#ifdef SIGCONT 241259243Sobrien (void) killpg(np->p_jobid, SIGCONT); 241359243Sobrien#endif 241459243Sobrien break; 241559243Sobrien } 241659243Sobrien } 241759243Sobrien while ((np = np->p_friends) != pp); 241859243Sobrien } 241959243Sobrien } 242059243Sobrien untty(); 242159243Sobrien#ifdef NLS_CATALOGS 242259243Sobrien /* 242359243Sobrien * We need to call catclose, because SVR4 leaves symlinks behind otherwise 242459243Sobrien * in the catalog directories. We cannot close on a vforked() child, 242559243Sobrien * because messages will stop working on the parent too. 242659243Sobrien */ 242759243Sobrien if (child == 0) 2428145479Smp nlsclose(); 242959243Sobrien#endif /* NLS_CATALOGS */ 243069408Sache#ifdef WINNT_NATIVE 243159243Sobrien nt_cleanup(); 243269408Sache#endif /* WINNT_NATIVE */ 243359243Sobrien _exit(i); 243459243Sobrien} 243559243Sobrien 243659243Sobrien#ifndef _PATH_DEFPATH 243759243Sobrienstatic Char ** 2438167465Smpdefaultpath(void) 243959243Sobrien{ 244059243Sobrien char *ptr; 244159243Sobrien Char **blk, **blkp; 244259243Sobrien struct stat stb; 244359243Sobrien 2444167465Smp blkp = blk = xmalloc(sizeof(Char *) * 10); 244559243Sobrien 244659243Sobrien#ifndef NODOT 244759243Sobrien# ifndef DOTLAST 244859243Sobrien *blkp++ = Strsave(STRdot); 244959243Sobrien# endif 245059243Sobrien#endif 245159243Sobrien 245259243Sobrien#define DIRAPPEND(a) \ 245359243Sobrien if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \ 245459243Sobrien *blkp++ = SAVE(ptr) 245559243Sobrien 245659243Sobrien#ifdef _PATH_LOCAL 245759243Sobrien DIRAPPEND(_PATH_LOCAL); 245859243Sobrien#endif 245959243Sobrien 246059243Sobrien#ifdef _PATH_USRUCB 246159243Sobrien DIRAPPEND(_PATH_USRUCB); 246259243Sobrien#endif 246359243Sobrien 246459243Sobrien#ifdef _PATH_USRBSD 246559243Sobrien DIRAPPEND(_PATH_USRBSD); 246659243Sobrien#endif 246759243Sobrien 246859243Sobrien#ifdef _PATH_BIN 246959243Sobrien DIRAPPEND(_PATH_BIN); 247059243Sobrien#endif 247159243Sobrien 247259243Sobrien#ifdef _PATH_USRBIN 247359243Sobrien DIRAPPEND(_PATH_USRBIN); 247459243Sobrien#endif 247559243Sobrien 247659243Sobrien#undef DIRAPPEND 247759243Sobrien 247859243Sobrien#ifndef NODOT 247959243Sobrien# ifdef DOTLAST 248059243Sobrien *blkp++ = Strsave(STRdot); 248159243Sobrien# endif 248259243Sobrien#endif 248359243Sobrien *blkp = NULL; 248459243Sobrien return (blk); 248559243Sobrien} 248659243Sobrien#endif 248759243Sobrien 248859243Sobrienstatic void 2489167465Smprecord(void) 249059243Sobrien{ 249159243Sobrien if (!fast) { 249259243Sobrien recdirs(NULL, adrof(STRsavedirs) != NULL); 249359243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 249459243Sobrien } 2495231990Smp displayHistStats("Exiting"); /* no-op unless DEBUG_HIST */ 249659243Sobrien} 2497195609Smp 2498195609Smp/* 2499195609Smp * Grab the tty repeatedly, and give up if we are not in the correct 2500195609Smp * tty process group. 2501195609Smp */ 2502195609Smpint 2503195609Smpgrabpgrp(int fd, pid_t desired) 2504195609Smp{ 2505195609Smp struct sigaction old; 2506195609Smp pid_t pgrp; 2507195609Smp size_t i; 2508195609Smp 2509195609Smp for (i = 0; i < 100; i++) { 2510195609Smp if ((pgrp = tcgetpgrp(fd)) == -1) 2511195609Smp return -1; 2512195609Smp if (pgrp == desired) 2513195609Smp return 0; 2514195609Smp (void)sigaction(SIGTTIN, NULL, &old); 2515195609Smp (void)signal(SIGTTIN, SIG_DFL); 2516195609Smp (void)kill(0, SIGTTIN); 2517195609Smp (void)sigaction(SIGTTIN, &old, NULL); 2518195609Smp } 2519195609Smp errno = EPERM; 2520195609Smp return -1; 2521195609Smp} 2522