159243Sobrien/* 259243Sobrien * sh.c: Main shell routines 359243Sobrien */ 459243Sobrien/*- 559243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 659243Sobrien * All rights reserved. 759243Sobrien * 859243Sobrien * Redistribution and use in source and binary forms, with or without 959243Sobrien * modification, are permitted provided that the following conditions 1059243Sobrien * are met: 1159243Sobrien * 1. Redistributions of source code must retain the above copyright 1259243Sobrien * notice, this list of conditions and the following disclaimer. 1359243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1459243Sobrien * notice, this list of conditions and the following disclaimer in the 1559243Sobrien * documentation and/or other materials provided with the distribution. 16100616Smp * 3. Neither the name of the University nor the names of its contributors 1759243Sobrien * may be used to endorse or promote products derived from this software 1859243Sobrien * without specific prior written permission. 1959243Sobrien * 2059243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2159243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2259243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2359243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2459243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2559243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2659243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2759243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2859243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2959243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3059243Sobrien * SUCH DAMAGE. 3159243Sobrien */ 3259243Sobrien#define EXTERN /* Intern */ 3359243Sobrien#include "sh.h" 3459243Sobrien 3559243Sobrien#ifndef lint 3659243Sobrienchar copyright[] = 3759243Sobrien"@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 3859243Sobrien All rights reserved.\n"; 3959243Sobrien#endif /* not lint */ 4059243Sobrien 4159243Sobrien#include "tc.h" 4259243Sobrien#include "ed.h" 4359243Sobrien#include "tw.h" 4459243Sobrien 45145479Smpextern int MapsAreInited; 46145479Smpextern int NLSMapsAreInited; 4759243Sobrien 4859243Sobrien/* 4959243Sobrien * C Shell 5059243Sobrien * 5159243Sobrien * Bill Joy, UC Berkeley, California, USA 5259243Sobrien * October 1978, May 1980 5359243Sobrien * 5459243Sobrien * Jim Kulp, IIASA, Laxenburg, Austria 5559243Sobrien * April 1980 5659243Sobrien * 5759243Sobrien * Filename recognition added: 5859243Sobrien * Ken Greer, Ind. Consultant, Palo Alto CA 5959243Sobrien * October 1983. 6059243Sobrien * 6159243Sobrien * Karl Kleinpaste, Computer Consoles, Inc. 6259243Sobrien * Added precmd, periodic/tperiod, prompt changes, 6359243Sobrien * directory stack hack, and login watch. 6459243Sobrien * Sometime March 1983 - Feb 1984. 6559243Sobrien * 6659243Sobrien * Added scheduled commands, including the "sched" command, 6759243Sobrien * plus the call to sched_run near the precmd et al 6859243Sobrien * routines. 6959243Sobrien * Upgraded scheduled events for running events while 7059243Sobrien * sitting idle at command input. 7159243Sobrien * 7259243Sobrien * Paul Placeway, Ohio State 7359243Sobrien * added stuff for running with twenex/inputl 9 Oct 1984. 7459243Sobrien * 7559243Sobrien * ported to Apple Unix (TM) (OREO) 26 -- 29 Jun 1987 7659243Sobrien */ 7759243Sobrien 78316957Sdchaginjmp_buf_t reslab IZERO_STRUCT; 79316957Sdchaginstruct wordent paraml IZERO_STRUCT; 8059243Sobrien 8159243Sobrienstatic const char tcshstr[] = "tcsh"; 8259243Sobrien 83167465Smpstruct sigaction parintr; /* Parents interrupt catch */ 84167465Smpstruct sigaction parterm; /* Parents terminate catch */ 8559243Sobrien 8659243Sobrien#ifdef TESLA 8759243Sobrienint do_logout = 0; 8859243Sobrien#endif /* TESLA */ 8959243Sobrien 9059243Sobrien 91145479Smpint use_fork = 0; /* use fork() instead of vfork()? */ 9259243Sobrien 9359243Sobrien/* 9459243Sobrien * Magic pointer values. Used to specify other invalid conditions aside 9559243Sobrien * from null. 9659243Sobrien */ 9759243Sobrienstatic Char INVCHAR; 9859243SobrienChar *INVPTR = &INVCHAR; 9959243SobrienChar **INVPPTR = &INVPTR; 10059243Sobrien 101167465Smpstatic int fast = 0; 102145479Smpstatic int mflag = 0; 103145479Smpstatic int prompt = 1; 104145479Smpint enterhist = 0; 105145479Smpint tellwhat = 0; 10659243Sobrientime_t t_period; 10759243SobrienChar *ffile = NULL; 108145479Smpint dolzero = 0; 10959243Sobrienint insource = 0; 11069408Sacheint exitset = 0; 11159243Sobrienstatic time_t chktim; /* Time mail last checked */ 11259243Sobrienchar *progname; 11359243Sobrienint tcsh; 11459243Sobrien 11559243Sobrien/* 11659243Sobrien * This preserves the input state of the shell. It is used by 11759243Sobrien * st_save and st_restore to manupulate shell state. 11859243Sobrien */ 11959243Sobrienstruct saved_state { 12059243Sobrien int insource; 121100616Smp int OLDSTD; 12259243Sobrien int SHIN; 123100616Smp int SHOUT; 124100616Smp int SHDIAG; 12559243Sobrien int intty; 12659243Sobrien struct whyle *whyles; 12759243Sobrien Char *gointr; 12859243Sobrien Char *arginp; 12959243Sobrien Char *evalp; 13059243Sobrien Char **evalvec; 13159243Sobrien Char *alvecp; 13259243Sobrien Char **alvec; 13359243Sobrien int onelflg; 134145479Smp int enterhist; 13559243Sobrien Char **argv; 136167465Smp Char **av; 13759243Sobrien Char HIST; 138145479Smp int cantell; 13959243Sobrien struct Bin B; 140195609Smp int justpr; 14159243Sobrien}; 14259243Sobrien 143167465Smpstatic int srccat (Char *, Char *); 14483098Smp#ifndef WINNT_NATIVE 145167465Smpstatic int srcfile (const char *, int, int, Char **); 14683098Smp#else 147167465Smpint srcfile (const char *, int, int, Char **); 14883098Smp#endif /*WINNT_NATIVE*/ 149167465Smpstatic void srcunit (int, int, int, Char **); 150167465Smpstatic void mailchk (void); 15159243Sobrien#ifndef _PATH_DEFPATH 152167465Smpstatic Char **defaultpath (void); 15359243Sobrien#endif 154167465Smpstatic void record (void); 155167465Smpstatic void st_save (struct saved_state *, int, int, 156167465Smp Char **, Char **); 157167465Smpstatic void st_restore (void *); 15859243Sobrien 159167465Smp int main (int, char **); 16059243Sobrien 161231990Smp#ifndef LOCALEDIR 162231990Smp#define LOCALEDIR "/usr/share/locale" 163231990Smp#endif 164231990Smp 165231990Smp#ifdef NLS_CATALOGS 166231990Smpstatic void 167231990Smpadd_localedir_to_nlspath(const char *path) 168231990Smp{ 169231990Smp static const char msgs_LOC[] = "/%L/LC_MESSAGES/%N.cat"; 170231990Smp static const char msgs_lang[] = "/%l/LC_MESSAGES/%N.cat"; 171231990Smp char *old; 172231990Smp char *new, *new_p; 173231990Smp size_t len; 174231990Smp int add_LOC = 1; 175231990Smp int add_lang = 1; 176231990Smp char trypath[MAXPATHLEN]; 177231990Smp struct stat st; 178231990Smp 179231990Smp if (path == NULL) 180231990Smp return; 181231990Smp 182231990Smp (void) xsnprintf(trypath, sizeof(trypath), "%s/en/LC_MESSAGES/tcsh.cat", 183231990Smp path); 184231990Smp if (stat(trypath, &st) == -1) 185231990Smp return; 186231990Smp 187231990Smp if ((old = getenv("NLSPATH")) != NULL) 188231990Smp len = strlen(old) + 1; /* don't forget the colon. */ 189231990Smp else 190231990Smp len = 0; 191231990Smp 192231990Smp len += 2 * strlen(path) + 193231990Smp sizeof(msgs_LOC) + sizeof(msgs_lang); /* includes the extra colon */ 194231990Smp 195231990Smp new = new_p = xcalloc(len, 1); 196231990Smp 197231990Smp if (old != NULL) { 198231990Smp size_t pathlen = strlen(path); 199231990Smp char *old_p; 200231990Smp 201231990Smp (void) xsnprintf(new_p, len, "%s", old); 202231990Smp new_p += strlen(new_p); 203231990Smp len -= new_p - new; 204231990Smp 205231990Smp /* Check if the paths we try to add are already present in NLSPATH. 206231990Smp If so, note it by setting the appropriate flag to 0. */ 207231990Smp for (old_p = old; old_p; old_p = strchr(old_p, ':'), 208231990Smp old_p = old_p ? old_p + 1 : NULL) { 209231990Smp if (strncmp(old_p, path, pathlen) != 0) 210231990Smp continue; 211231990Smp if (strncmp(old_p + pathlen, msgs_LOC, sizeof(msgs_LOC) - 1) == 0) 212231990Smp add_LOC = 0; 213231990Smp else if (strncmp(old_p + pathlen, msgs_lang, 214231990Smp sizeof(msgs_lang) - 1) == 0) 215231990Smp add_lang = 0; 216231990Smp } 217231990Smp } 218231990Smp 219231990Smp /* Add the message catalog paths not already present to NLSPATH. */ 220231990Smp if (add_LOC || add_lang) 221231990Smp (void) xsnprintf(new_p, len, "%s%s%s%s%s%s", 222231990Smp old ? ":" : "", 223231990Smp add_LOC ? path : "", add_LOC ? msgs_LOC : "", 224231990Smp add_LOC && add_lang ? ":" : "", 225231990Smp add_lang ? path : "", add_lang ? msgs_lang : ""); 226231990Smp 227231990Smp tsetenv(STRNLSPATH, str2short(new)); 228231990Smp free(new); 229231990Smp} 230231990Smp#endif 231231990Smp 23259243Sobrienint 233167465Smpmain(int argc, char **argv) 23459243Sobrien{ 235167465Smp int batch = 0; 236167465Smp volatile int nexececho = 0; 237167465Smp int nofile = 0; 238167465Smp volatile int nverbose = 0; 239167465Smp volatile int rdirs = 0; 240354195Sbrooks volatile int exitcode = 0; 241167465Smp int quitit = 0; 242145479Smp Char *cp; 24359243Sobrien#ifdef AUTOLOGOUT 244145479Smp Char *cp2; 24559243Sobrien#endif 246145479Smp char *tcp, *ttyn; 247167465Smp int f, reenter; 248145479Smp char **tempv; 249354195Sbrooks static const char *targinp = NULL; 250131962Smp int osetintr; 251167465Smp struct sigaction oparintr; 25259243Sobrien 25369408Sache#ifdef WINNT_NATIVE 25459243Sobrien nt_init(); 25569408Sache#endif /* WINNT_NATIVE */ 256316957Sdchagin 257316957Sdchagin (void)memset(&reslab, 0, sizeof(reslab)); 25859243Sobrien#if defined(NLS_CATALOGS) && defined(LC_MESSAGES) 25959243Sobrien (void) setlocale(LC_MESSAGES, ""); 26059243Sobrien#endif /* NLS_CATALOGS && LC_MESSAGES */ 26159243Sobrien 26259243Sobrien#ifdef NLS 26359243Sobrien# ifdef LC_CTYPE 26459243Sobrien (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 26559243Sobrien# endif /* LC_CTYPE */ 26659243Sobrien#endif /* NLS */ 26759243Sobrien 268231990Smp STR_environ = blk2short(environ); 269231990Smp environ = short2blk(STR_environ); /* So that we can free it */ 270231990Smp 271231990Smp#ifdef NLS_CATALOGS 272231990Smp add_localedir_to_nlspath(LOCALEDIR); 273231990Smp#endif 274231990Smp 27559243Sobrien nlsinit(); 276316957Sdchagin initlex(¶ml); 27759243Sobrien 27859243Sobrien#ifdef MALLOC_TRACE 279167465Smp mal_setstatsfile(fdopen(dmove(xopen("/tmp/tcsh.trace", 280145479Smp O_WRONLY|O_CREAT|O_LARGEFILE, 0666), 25), "w")); 281145479Smp mal_trace(1); 28259243Sobrien#endif /* MALLOC_TRACE */ 28359243Sobrien 28459243Sobrien#if !(defined(BSDTIMES) || defined(_SEQUENT_)) && defined(POSIX) 28559243Sobrien# ifdef _SC_CLK_TCK 28659243Sobrien clk_tck = (clock_t) sysconf(_SC_CLK_TCK); 28759243Sobrien# else /* ! _SC_CLK_TCK */ 28859243Sobrien# ifdef CLK_TCK 28959243Sobrien clk_tck = CLK_TCK; 29059243Sobrien# else /* !CLK_TCK */ 29159243Sobrien clk_tck = HZ; 29259243Sobrien# endif /* CLK_TCK */ 29359243Sobrien# endif /* _SC_CLK_TCK */ 29459243Sobrien#endif /* !BSDTIMES && POSIX */ 29559243Sobrien 29659243Sobrien settimes(); /* Immed. estab. timing base */ 29759243Sobrien#ifdef TESLA 29859243Sobrien do_logout = 0; 29959243Sobrien#endif /* TESLA */ 30059243Sobrien 30159243Sobrien /* 30259243Sobrien * Make sure we have 0, 1, 2 open 30359243Sobrien * Otherwise `` jobs will not work... (From knaff@poly.polytechnique.fr) 30459243Sobrien */ 30559243Sobrien { 30659243Sobrien do 307167465Smp if ((f = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE)) == -1 && 308167465Smp (f = xopen("/", O_RDONLY|O_LARGEFILE)) == -1) 30959243Sobrien exit(1); 31059243Sobrien while (f < 3); 311167465Smp xclose(f); 31259243Sobrien } 31359243Sobrien 31459243Sobrien osinit(); /* Os dependent initialization */ 31559243Sobrien 31659243Sobrien 31759243Sobrien { 31859243Sobrien char *t; 31959243Sobrien 32059243Sobrien t = strrchr(argv[0], '/'); 32169408Sache#ifdef WINNT_NATIVE 32259243Sobrien { 32359243Sobrien char *s = strrchr(argv[0], '\\'); 32459243Sobrien if (s) 32559243Sobrien t = s; 32659243Sobrien } 32769408Sache#endif /* WINNT_NATIVE */ 32859243Sobrien t = t ? t + 1 : argv[0]; 32959243Sobrien if (*t == '-') t++; 33059243Sobrien progname = strsave((t && *t) ? t : tcshstr); /* never want a null */ 331231990Smp tcsh = strncmp(progname, tcshstr, sizeof(tcshstr) - 1) == 0; 33259243Sobrien } 33359243Sobrien 33459243Sobrien /* 33559243Sobrien * Initialize non constant strings 33659243Sobrien */ 33759243Sobrien#ifdef _PATH_BSHELL 33859243Sobrien STR_BSHELL = SAVE(_PATH_BSHELL); 33959243Sobrien#endif 34059243Sobrien#ifdef _PATH_TCSHELL 34159243Sobrien STR_SHELLPATH = SAVE(_PATH_TCSHELL); 34259243Sobrien#else 34359243Sobrien# ifdef _PATH_CSHELL 34459243Sobrien STR_SHELLPATH = SAVE(_PATH_CSHELL); 34559243Sobrien# endif 34659243Sobrien#endif 34759243Sobrien STR_WORD_CHARS = SAVE(WORD_CHARS); 348316957Sdchagin STR_WORD_CHARS_VI = SAVE(WORD_CHARS_VI); 34959243Sobrien 35059243Sobrien HIST = '!'; 35159243Sobrien HISTSUB = '^'; 352231990Smp PRCH = tcsh ? '>' : '%'; /* to replace %# in $prompt for normal users */ 353231990Smp PRCHROOT = '#'; /* likewise for root */ 35459243Sobrien word_chars = STR_WORD_CHARS; 35559243Sobrien bslash_quote = 0; /* PWP: do tcsh-style backslash quoting? */ 356231990Smp anyerror = 1; /* for compatibility */ 357231990Smp setcopy(STRanyerror, STRNULL, VAR_READWRITE); 35859243Sobrien 35959243Sobrien /* Default history size to 100 */ 360167465Smp setcopy(STRhistory, str2short("100"), VAR_READWRITE); 361316957Sdchagin sethistory(100); 36259243Sobrien 36359243Sobrien tempv = argv; 36459243Sobrien ffile = SAVE(tempv[0]); 36559243Sobrien dolzero = 0; 36659243Sobrien if (eq(ffile, STRaout)) /* A.out's are quittable */ 36759243Sobrien quitit = 1; 36859243Sobrien uid = getuid(); 36959243Sobrien gid = getgid(); 37059243Sobrien euid = geteuid(); 37159243Sobrien egid = getegid(); 37259243Sobrien /* 37359243Sobrien * We are a login shell if: 1. we were invoked as -<something> with 37459243Sobrien * optional arguments 2. or we were invoked only with the -l flag 37559243Sobrien */ 37659243Sobrien loginsh = (**tempv == '-') || (argc == 2 && 37759243Sobrien tempv[1][0] == '-' && tempv[1][1] == 'l' && 37859243Sobrien tempv[1][2] == '\0'); 37959243Sobrien#ifdef _VMS_POSIX 38059243Sobrien /* No better way to find if we are a login shell */ 38159243Sobrien if (!loginsh) { 38259243Sobrien loginsh = (argc == 1 && getppid() == 1); 38359243Sobrien **tempv = '-'; /* Avoid giving VMS an acidic stomach */ 38459243Sobrien } 38559243Sobrien#endif /* _VMS_POSIX */ 38659243Sobrien 38759243Sobrien if (loginsh && **tempv != '-') { 388167465Smp char *argv0; 389167465Smp 39059243Sobrien /* 39159243Sobrien * Mangle the argv space 39259243Sobrien */ 39359243Sobrien tempv[1][0] = '\0'; 39459243Sobrien tempv[1][1] = '\0'; 39559243Sobrien tempv[1] = NULL; 396167465Smp argv0 = strspl("-", *tempv); 397167465Smp *tempv = argv0; 39859243Sobrien argc--; 39959243Sobrien } 40059243Sobrien if (loginsh) { 40159243Sobrien (void) time(&chktim); 402167465Smp setNS(STRloginsh); 40359243Sobrien } 40459243Sobrien 40559243Sobrien NoNLSRebind = getenv("NOREBIND") != NULL; 40659243Sobrien#ifdef NLS 40759243Sobrien# ifdef SETLOCALEBUG 40859243Sobrien dont_free = 1; 40959243Sobrien# endif /* SETLOCALEBUG */ 41059243Sobrien (void) setlocale(LC_ALL, ""); 41159243Sobrien# ifdef LC_COLLATE 41259243Sobrien (void) setlocale(LC_COLLATE, ""); 41359243Sobrien# endif 41459243Sobrien# ifdef SETLOCALEBUG 41559243Sobrien dont_free = 0; 41659243Sobrien# endif /* SETLOCALEBUG */ 41759243Sobrien# ifdef STRCOLLBUG 41859243Sobrien fix_strcoll_bug(); 41959243Sobrien# endif /* STRCOLLBUG */ 42059243Sobrien 421231990Smp /* 422231990Smp * On solaris ISO8859-1 contains no printable characters in the upper half 423231990Smp * so we need to test only for MB_CUR_MAX == 1, otherwise for multi-byte 424231990Smp * locales we are always AsciiOnly == 0. 425231990Smp */ 426231990Smp if (MB_CUR_MAX == 1) { 42759243Sobrien int k; 42859243Sobrien 429231990Smp for (k = 0200; k <= 0377 && !isprint(CTL_ESC(k)); k++) 43059243Sobrien continue; 431231990Smp AsciiOnly = k > 0377; 432231990Smp } else 433231990Smp AsciiOnly = 0; 43459243Sobrien#else 43559243Sobrien AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL; 43659243Sobrien#endif /* NLS */ 43759243Sobrien if (MapsAreInited && !NLSMapsAreInited) 43859243Sobrien ed_InitNLSMaps(); 43959243Sobrien ResetArrowKeys(); 44059243Sobrien 44159243Sobrien /* 44259243Sobrien * Initialize for periodic command intervals. Also, initialize the dummy 44359243Sobrien * tty list for login-watch. 44459243Sobrien */ 44559243Sobrien (void) time(&t_period); 44659243Sobrien#ifndef HAVENOUTMP 44759243Sobrien initwatch(); 44859243Sobrien#endif /* !HAVENOUTMP */ 44959243Sobrien 45059243Sobrien#if defined(alliant) 45159243Sobrien /* 45259243Sobrien * From: Jim Pace <jdp@research.att.com> 45359243Sobrien * tcsh does not work properly on the alliants through an rlogin session. 45459243Sobrien * The shell generally hangs. Also, reference to the controlling terminal 45559243Sobrien * does not work ( ie: echo foo > /dev/tty ). 45659243Sobrien * 45759243Sobrien * A security feature was added to rlogind affecting FX/80's Concentrix 45859243Sobrien * from revision 5.5.xx upwards (through 5.7 where this fix was implemented) 45959243Sobrien * This security change also affects the FX/2800 series. 46059243Sobrien * The security change to rlogind requires the process group of an rlogin 46159243Sobrien * session become disassociated with the tty in rlogind. 46259243Sobrien * 46359243Sobrien * The changes needed are: 46459243Sobrien * 1. set the process group 46559243Sobrien * 2. reenable the control terminal 46659243Sobrien */ 46759243Sobrien if (loginsh && isatty(SHIN)) { 468167465Smp ttyn = ttyname(SHIN); 469167465Smp xclose(SHIN); 470167465Smp SHIN = xopen(ttyn, O_RDWR|O_LARGEFILE); 47159243Sobrien shpgrp = getpid(); 47259243Sobrien (void) ioctl (SHIN, TIOCSPGRP, (ioctl_t) &shpgrp); 47359243Sobrien (void) setpgid(0, shpgrp); 47459243Sobrien } 47559243Sobrien#endif /* alliant */ 47659243Sobrien 47759243Sobrien /* 47859243Sobrien * Move the descriptors to safe places. The variable didfds is 0 while we 47959243Sobrien * have only FSH* to work with. When didfds is true, we have 0,1,2 and 48059243Sobrien * prefer to use these. 48159243Sobrien */ 48259243Sobrien initdesc(); 48359243Sobrien 484316957Sdchagin cdtohome = 1; 485316957Sdchagin setv(STRcdtohome, SAVE(""), VAR_READWRITE); 486316957Sdchagin 48759243Sobrien /* 48859243Sobrien * Get and set the tty now 48959243Sobrien */ 49059243Sobrien if ((ttyn = ttyname(SHIN)) != NULL) { 49159243Sobrien /* 49259243Sobrien * Could use rindex to get rid of other possible path components, but 49359243Sobrien * hpux preserves the subdirectory /pty/ when storing the tty name in 49459243Sobrien * utmp, so we keep it too. 49559243Sobrien */ 49659243Sobrien if (strncmp(ttyn, "/dev/", 5) == 0) 497167465Smp setv(STRtty, cp = SAVE(ttyn + 5), VAR_READWRITE); 49859243Sobrien else 499167465Smp setv(STRtty, cp = SAVE(ttyn), VAR_READWRITE); 50059243Sobrien } 50159243Sobrien else 502167465Smp setv(STRtty, cp = SAVE(""), VAR_READWRITE); 503316957Sdchagin 50459243Sobrien /* 50559243Sobrien * Initialize the shell variables. ARGV and PROMPT are initialized later. 50659243Sobrien * STATUS is also munged in several places. CHILD is munged when 50759243Sobrien * forking/waiting 50859243Sobrien */ 50959243Sobrien 51059243Sobrien /* 51159243Sobrien * 7-10-87 Paul Placeway autologout should be set ONLY on login shells and 51259243Sobrien * on shells running as root. Out of these, autologout should NOT be set 51359243Sobrien * for any psudo-terminals (this catches most window systems) and not for 51459243Sobrien * any terminal running X windows. 51559243Sobrien * 51659243Sobrien * At Ohio State, we have had problems with a user having his X session 51759243Sobrien * drop out from under him (on a Sun) because the shell in his master 51859243Sobrien * xterm timed out and exited. 51959243Sobrien * 52059243Sobrien * Really, this should be done with a program external to the shell, that 52159243Sobrien * watches for no activity (and NO running programs, such as dump) on a 52259243Sobrien * terminal for a long peroid of time, and then SIGHUPS the shell on that 52359243Sobrien * terminal. 52459243Sobrien * 52559243Sobrien * bugfix by Rich Salz <rsalz@PINEAPPLE.BBN.COM>: For root rsh things 52659243Sobrien * allways first check to see if loginsh or really root, then do things 52759243Sobrien * with ttyname() 52859243Sobrien * 52959243Sobrien * Also by Jean-Francois Lamy <lamy%ai.toronto.edu@RELAY.CS.NET>: check the 53059243Sobrien * value of cp before using it! ("root can rsh too") 53159243Sobrien * 53259243Sobrien * PWP: keep the nested ifs; the order of the tests matters and a good 53359243Sobrien * (smart) C compiler might re-arange things wrong. 53459243Sobrien */ 53559243Sobrien#ifdef AUTOLOGOUT 53659243Sobrien# ifdef convex 537167465Smp if (uid == 0) 53859243Sobrien /* root always has a 15 minute autologout */ 539167465Smp setcopy(STRautologout, STRrootdefautologout, VAR_READWRITE); 54059243Sobrien else 54159243Sobrien if (loginsh) 54259243Sobrien /* users get autologout set to 0 */ 543167465Smp setcopy(STRautologout, STR0, VAR_READWRITE); 54459243Sobrien# else /* convex */ 54559243Sobrien if (loginsh || (uid == 0)) { 54659243Sobrien if (*cp) { 54759243Sobrien /* only for login shells or root and we must have a tty */ 548231990Smp if (((cp2 = Strrchr(cp, (Char) '/')) != NULL) && 549231990Smp (Strncmp(cp, STRptssl, 3) != 0)) { 550172665Smp cp2 = cp2 + 1; 55159243Sobrien } 55259243Sobrien else 55359243Sobrien cp2 = cp; 55459243Sobrien if (!(((Strncmp(cp2, STRtty, 3) == 0) && Isalpha(cp2[3])) || 555184072Sru Strstr(cp, STRptssl) != NULL)) { 55659243Sobrien if (getenv("DISPLAY") == NULL) { 55759243Sobrien /* NOT on X window shells */ 558167465Smp setcopy(STRautologout, STRdefautologout, VAR_READWRITE); 55959243Sobrien } 56059243Sobrien } 56159243Sobrien } 56259243Sobrien } 56359243Sobrien# endif /* convex */ 56459243Sobrien#endif /* AUTOLOGOUT */ 56559243Sobrien 566167465Smp sigset_interrupting(SIGALRM, queue_alrmcatch); 56759243Sobrien 568167465Smp setcopy(STRstatus, STR0, VAR_READWRITE); 56959243Sobrien 57059243Sobrien /* 571100616Smp * get and set machine specific environment variables 57259243Sobrien */ 57359243Sobrien getmachine(); 57459243Sobrien 57559243Sobrien 57659243Sobrien /* 57759243Sobrien * Publish the selected echo style 57859243Sobrien */ 579100616Smp#if ECHO_STYLE != BSD_ECHO 580100616Smp if (tcsh) { 581100616Smp# if ECHO_STYLE == NONE_ECHO 582167465Smp setcopy(STRecho_style, STRnone, VAR_READWRITE); 583100616Smp# endif /* ECHO_STYLE == NONE_ECHO */ 584100616Smp# if ECHO_STYLE == SYSV_ECHO 585167465Smp setcopy(STRecho_style, STRsysv, VAR_READWRITE); 586100616Smp# endif /* ECHO_STYLE == SYSV_ECHO */ 587100616Smp# if ECHO_STYLE == BOTH_ECHO 588167465Smp setcopy(STRecho_style, STRboth, VAR_READWRITE); 589100616Smp# endif /* ECHO_STYLE == BOTH_ECHO */ 590100616Smp } else 591100616Smp#endif /* ECHO_STYLE != BSD_ECHO */ 592167465Smp setcopy(STRecho_style, STRbsd, VAR_READWRITE); 59359243Sobrien 59459243Sobrien /* 59559243Sobrien * increment the shell level. 59659243Sobrien */ 59759243Sobrien shlvl(1); 59859243Sobrien 599231990Smp#ifdef __ANDROID__ 600316957Sdchagin /* On Android, $HOME either isn't set or set to /data, a R/O location. 601316957Sdchagin Check for the environment variable EXTERNAL_STORAGE, which contains 602316957Sdchagin the mount point of the external storage (SD card, mostly). If 603316957Sdchagin EXTERNAL_STORAGE isn't set fall back to "/sdcard". Eventually 604316957Sdchagin override $HOME so the environment is on the same page. */ 605316957Sdchagin if (((tcp = getenv("HOME")) != NULL && strcmp (tcp, "/data") != 0) 606316957Sdchagin || (tcp = getenv("EXTERNAL_STORAGE")) != NULL) { 607231990Smp cp = quote(SAVE(tcp)); 608316957Sdchagin } else 609231990Smp cp = quote(SAVE("/sdcard")); 610316957Sdchagin tsetenv(STRKHOME, cp); 611231990Smp#else 612316957Sdchagin if ((tcp = getenv("HOME")) != NULL) 613316957Sdchagin cp = quote(SAVE(tcp)); 614316957Sdchagin else 61559243Sobrien cp = NULL; 616231990Smp#endif 61773393Skris 61859243Sobrien if (cp == NULL) 61959243Sobrien fast = 1; /* No home -> can't read scripts */ 62059243Sobrien else 621167465Smp setv(STRhome, cp, VAR_READWRITE); 62273393Skris 62359243Sobrien dinit(cp); /* dinit thinks that HOME == cwd in a login 62459243Sobrien * shell */ 62559243Sobrien /* 62659243Sobrien * Grab other useful things from the environment. Should we grab 62759243Sobrien * everything?? 62859243Sobrien */ 62959243Sobrien { 63059243Sobrien char *cln, *cus, *cgr; 63159243Sobrien struct passwd *pw; 63259243Sobrien struct group *gr; 63359243Sobrien 63459243Sobrien 63559243Sobrien#ifdef apollo 63659243Sobrien int oid = getoid(); 63759243Sobrien 638167465Smp setv(STRoid, Itoa(oid, 0, 0), VAR_READWRITE); 63959243Sobrien#endif /* apollo */ 64059243Sobrien 641231990Smp setv(STReuid, Itoa(euid, 0, 0), VAR_READWRITE); 642231990Smp if ((pw = xgetpwuid(euid)) == NULL) 643231990Smp setcopy(STReuser, STRunknown, VAR_READWRITE); 644231990Smp else 645231990Smp setcopy(STReuser, str2short(pw->pw_name), VAR_READWRITE); 646231990Smp 647167465Smp setv(STRuid, Itoa(uid, 0, 0), VAR_READWRITE); 64859243Sobrien 649167465Smp setv(STRgid, Itoa(gid, 0, 0), VAR_READWRITE); 65059243Sobrien 65159243Sobrien cln = getenv("LOGNAME"); 65259243Sobrien cus = getenv("USER"); 65359243Sobrien if (cus != NULL) 654167465Smp setv(STRuser, quote(SAVE(cus)), VAR_READWRITE); 65559243Sobrien else if (cln != NULL) 656167465Smp setv(STRuser, quote(SAVE(cln)), VAR_READWRITE); 657167465Smp else if ((pw = xgetpwuid(uid)) == NULL) 658231990Smp setcopy(STRuser, STRunknown, VAR_READWRITE); 65959243Sobrien else 660167465Smp setcopy(STRuser, str2short(pw->pw_name), VAR_READWRITE); 66159243Sobrien if (cln == NULL) 66259243Sobrien tsetenv(STRLOGNAME, varval(STRuser)); 66359243Sobrien if (cus == NULL) 66459243Sobrien tsetenv(STRKUSER, varval(STRuser)); 66559243Sobrien 66659243Sobrien cgr = getenv("GROUP"); 66759243Sobrien if (cgr != NULL) 668167465Smp setv(STRgroup, quote(SAVE(cgr)), VAR_READWRITE); 669167465Smp else if ((gr = xgetgrgid(gid)) == NULL) 670231990Smp setcopy(STRgroup, STRunknown, VAR_READWRITE); 67159243Sobrien else 672167465Smp setcopy(STRgroup, str2short(gr->gr_name), VAR_READWRITE); 67359243Sobrien if (cgr == NULL) 67459243Sobrien tsetenv(STRKGROUP, varval(STRgroup)); 67559243Sobrien } 67659243Sobrien 67759243Sobrien /* 67859243Sobrien * HOST may be wrong, since rexd transports the entire environment on sun 67959243Sobrien * 3.x Just set it again 68059243Sobrien */ 68159243Sobrien { 68259243Sobrien char cbuff[MAXHOSTNAMELEN]; 68359243Sobrien 68459243Sobrien if (gethostname(cbuff, sizeof(cbuff)) >= 0) { 68559243Sobrien cbuff[sizeof(cbuff) - 1] = '\0'; /* just in case */ 68659243Sobrien tsetenv(STRHOST, str2short(cbuff)); 68759243Sobrien } 68859243Sobrien else 689231990Smp tsetenv(STRHOST, STRunknown); 69059243Sobrien } 69159243Sobrien 69259243Sobrien 69359243Sobrien#ifdef REMOTEHOST 69459243Sobrien /* 69559243Sobrien * Try to determine the remote host we were logged in from. 69659243Sobrien */ 69759243Sobrien remotehost(); 69859243Sobrien#endif /* REMOTEHOST */ 69959243Sobrien 70059243Sobrien#ifdef apollo 70159243Sobrien if ((tcp = getenv("SYSTYPE")) == NULL) 70259243Sobrien tcp = "bsd4.3"; 70359243Sobrien tsetenv(STRSYSTYPE, quote(str2short(tcp))); 70459243Sobrien#endif /* apollo */ 70559243Sobrien 70659243Sobrien /* 70759243Sobrien * set editing on by default, unless running under Emacs as an inferior 70859243Sobrien * shell. 70959243Sobrien * We try to do this intelligently. If $TERM is available, then it 71059243Sobrien * should determine if we should edit or not. $TERM is preserved 71159243Sobrien * across rlogin sessions, so we will not get confused if we rlogin 71259243Sobrien * under an emacs shell. Another advantage is that if we run an 71359243Sobrien * xterm under an emacs shell, then the $TERM will be set to 71459243Sobrien * xterm, so we are going to want to edit. Unfortunately emacs 71559243Sobrien * does not restore all the tty modes, so xterm is not very well 71659243Sobrien * set up. But this is not the shell's fault. 71759243Sobrien * Also don't edit if $TERM == wm, for when we're running under an ATK app. 71859243Sobrien * Finally, emacs compiled under terminfo, sets the terminal to dumb, 71959243Sobrien * so disable editing for that too. 72059243Sobrien * 72159243Sobrien * Unfortunately, in some cases the initial $TERM setting is "unknown", 72259243Sobrien * "dumb", or "network" which is then changed in the user's startup files. 72359243Sobrien * We fix this by setting noediting here if $TERM is unknown/dumb and 72459243Sobrien * if noediting is set, we switch on editing if $TERM is changed. 72559243Sobrien */ 72659243Sobrien if ((tcp = getenv("TERM")) != NULL) { 727167465Smp setv(STRterm, quote(SAVE(tcp)), VAR_READWRITE); 72859243Sobrien noediting = strcmp(tcp, "unknown") == 0 || strcmp(tcp, "dumb") == 0 || 72959243Sobrien strcmp(tcp, "network") == 0; 73059243Sobrien editing = strcmp(tcp, "emacs") != 0 && strcmp(tcp, "wm") != 0 && 73159243Sobrien !noediting; 73259243Sobrien } 73359243Sobrien else { 73459243Sobrien noediting = 0; 73559243Sobrien editing = ((tcp = getenv("EMACS")) == NULL || strcmp(tcp, "t") != 0); 73659243Sobrien } 73759243Sobrien 73859243Sobrien /* 73959243Sobrien * The 'edit' variable is either set or unset. It doesn't 74059243Sobrien * need a value. Making it 'emacs' might be confusing. 74159243Sobrien */ 74259243Sobrien if (editing) 743167465Smp setNS(STRedit); 74459243Sobrien 74559243Sobrien 74659243Sobrien /* 74759243Sobrien * still more mutability: make the complete routine automatically add the 74859243Sobrien * suffix of file names... 74959243Sobrien */ 750167465Smp setNS(STRaddsuffix); 75159243Sobrien 75259243Sobrien /* 753145479Smp * Compatibility with tcsh >= 6.12 by default 754145479Smp */ 755167465Smp setNS(STRcsubstnonl); 756145479Smp 757145479Smp /* 75883098Smp * Random default kill ring size 75983098Smp */ 760167465Smp setcopy(STRkillring, str2short("30"), VAR_READWRITE); 76183098Smp 76283098Smp /* 76359243Sobrien * Re-initialize path if set in environment 76459243Sobrien */ 76559243Sobrien if ((tcp = getenv("PATH")) == NULL) 76659243Sobrien#ifdef _PATH_DEFPATH 76759243Sobrien importpath(str2short(_PATH_DEFPATH)); 76859243Sobrien#else /* !_PATH_DEFPATH */ 76959243Sobrien setq(STRpath, defaultpath(), &shvhed, VAR_READWRITE); 77059243Sobrien#endif /* _PATH_DEFPATH */ 77159243Sobrien else 77259243Sobrien /* Importpath() allocates memory for the path, and the 77359243Sobrien * returned pointer from SAVE() was discarded, so 77459243Sobrien * this was a memory leak.. (sg) 77559243Sobrien * 77659243Sobrien * importpath(SAVE(tcp)); 77759243Sobrien */ 77859243Sobrien importpath(str2short(tcp)); 77959243Sobrien 78059243Sobrien 78159243Sobrien { 78259243Sobrien /* If the SHELL environment variable ends with "tcsh", set 78359243Sobrien * STRshell to the same path. This is to facilitate using 78459243Sobrien * the executable in environments where the compiled-in 78559243Sobrien * default isn't appropriate (sg). 78659243Sobrien */ 78759243Sobrien 788167465Smp size_t sh_len = 0; 78959243Sobrien 79059243Sobrien if ((tcp = getenv("SHELL")) != NULL) { 79159243Sobrien sh_len = strlen(tcp); 79259243Sobrien if ((sh_len >= 5 && strcmp(tcp + (sh_len - 5), "/tcsh") == 0) || 79359243Sobrien (!tcsh && sh_len >= 4 && strcmp(tcp + (sh_len - 4), "/csh") == 0)) 794167465Smp setv(STRshell, quote(SAVE(tcp)), VAR_READWRITE); 79559243Sobrien else 79659243Sobrien sh_len = 0; 79759243Sobrien } 79859243Sobrien if (sh_len == 0) 799167465Smp setcopy(STRshell, STR_SHELLPATH, VAR_READWRITE); 80059243Sobrien } 80159243Sobrien 802167465Smp#ifdef _OSD_POSIX /* BS2000 needs this variable set to "SHELL" */ 803167465Smp if ((tcp = getenv("PROGRAM_ENVIRONMENT")) == NULL) 804167465Smp tcp = "SHELL"; 805167465Smp tsetenv(STRPROGRAM_ENVIRONMENT, quote(str2short(tcp))); 806167465Smp#endif /* _OSD_POSIX */ 807167465Smp 80859243Sobrien#ifdef COLOR_LS_F 80959243Sobrien if ((tcp = getenv("LS_COLORS")) != NULL) 81059243Sobrien parseLS_COLORS(str2short(tcp)); 811316957Sdchagin if ((tcp = getenv("LSCOLORS")) != NULL) 812316957Sdchagin parseLSCOLORS(str2short(tcp)); 81359243Sobrien#endif /* COLOR_LS_F */ 81459243Sobrien 815316957Sdchagin mainpid = getpid(); 816316957Sdchagin doldol = putn((tcsh_number_t)mainpid); /* For $$ */ 81769408Sache#ifdef WINNT_NATIVE 81859243Sobrien { 819167465Smp char *tmp; 820167465Smp Char *tmp2; 821167465Smp if ((tmp = getenv("TMP")) != NULL) { 822167465Smp tmp = xasprintf("%s/%s", tmp, "sh"); 823167465Smp tmp2 = SAVE(tmp); 824231990Smp xfree(tmp); 825231990Smp } 826167465Smp else { 827167465Smp tmp2 = SAVE(""); 828167465Smp } 829167465Smp shtemp = Strspl(tmp2, doldol); /* For << */ 830167465Smp xfree(tmp2); 831167465Smp } 83269408Sache#else /* !WINNT_NATIVE */ 833231990Smp#ifdef HAVE_MKSTEMP 834231990Smp { 835316957Sdchagin const char *tmpdir = getenv ("TMPDIR"); 836231990Smp if (!tmpdir) 837231990Smp tmpdir = "/tmp"; 838231990Smp shtemp = Strspl(SAVE(tmpdir), SAVE("/sh" TMP_TEMPLATE)); /* For << */ 839231990Smp } 840231990Smp#else /* !HAVE_MKSTEMP */ 84159243Sobrien shtemp = Strspl(STRtmpsh, doldol); /* For << */ 842231990Smp#endif /* HAVE_MKSTEMP */ 84369408Sache#endif /* WINNT_NATIVE */ 84459243Sobrien 84559243Sobrien /* 84659243Sobrien * Record the interrupt states from the parent process. If the parent is 84759243Sobrien * non-interruptible our hand must be forced or we (and our children) won't 84859243Sobrien * be either. Our children inherit termination from our parent. We catch it 84959243Sobrien * only if we are the login shell. 85059243Sobrien */ 851167465Smp sigaction(SIGINT, NULL, &parintr); 852167465Smp sigaction(SIGTERM, NULL, &parterm); 85359243Sobrien 85459243Sobrien 85559243Sobrien#ifdef TCF 85659243Sobrien /* Enable process migration on ourselves and our progeny */ 85759243Sobrien (void) signal(SIGMIGRATE, SIG_DFL); 85859243Sobrien#endif /* TCF */ 85959243Sobrien 86059243Sobrien /* 86169408Sache * dspkanji/dspmbyte autosetting 86269408Sache */ 86369408Sache /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 86469408Sache#if defined(DSPMBYTE) 86569408Sache#if defined(NLS) && defined(LC_CTYPE) 866231990Smp if (((tcp = setlocale(LC_CTYPE, NULL)) != NULL || (tcp = getenv("LANG")) != NULL) && !adrof(CHECK_MBYTEVAR)) 86769408Sache#else 868231990Smp if ((tcp = getenv("LANG")) != NULL && !adrof(CHECK_MBYTEVAR)) 86969408Sache#endif 870231990Smp { 87169408Sache autoset_dspmbyte(str2short(tcp)); 87269408Sache } 87369408Sache#if defined(WINNT_NATIVE) 87469408Sache else if (!adrof(CHECK_MBYTEVAR)) 87569408Sache nt_autoset_dspmbyte(); 87669408Sache#endif /* WINNT_NATIVE */ 87769408Sache#endif 878231990Smp#if defined(AUTOSET_KANJI) 879231990Smp# if defined(NLS) && defined(LC_CTYPE) 880231990Smp if (setlocale(LC_CTYPE, NULL) != NULL || getenv("LANG") != NULL) 881231990Smp# else 882231990Smp if (getenv("LANG") != NULL) 883231990Smp# endif 884231990Smp autoset_kanji(); 885231990Smp#endif /* AUTOSET_KANJI */ 886100616Smp fix_version(); /* publish the shell version */ 887100616Smp 888100616Smp if (argc > 1 && strcmp(argv[1], "--version") == 0) { 889100616Smp xprintf("%S\n", varval(STRversion)); 890100616Smp xexit(0); 891100616Smp } 892145479Smp if (argc > 1 && strcmp(argv[1], "--help") == 0) { 893145479Smp xprintf("%S\n\n", varval(STRversion)); 894195609Smp xprintf("%s", CGETS(11, 8, HELP_STRING)); 895145479Smp xexit(0); 896145479Smp } 89769408Sache /* 89859243Sobrien * Process the arguments. 89959243Sobrien * 90059243Sobrien * Note that processing of -v/-x is actually delayed till after script 90159243Sobrien * processing. 90259243Sobrien * 90359243Sobrien * We set the first character of our name to be '-' if we are a shell 90459243Sobrien * running interruptible commands. Many programs which examine ps'es 90559243Sobrien * use this to filter such shells out. 90659243Sobrien */ 90759243Sobrien argc--, tempv++; 90859243Sobrien while (argc > 0 && (tcp = tempv[0])[0] == '-' && 90959243Sobrien *++tcp != '\0' && !batch) { 91059243Sobrien do 91159243Sobrien switch (*tcp++) { 91259243Sobrien 91359243Sobrien case 0: /* - Interruptible, no prompt */ 91459243Sobrien prompt = 0; 91559243Sobrien setintr = 1; 91659243Sobrien nofile = 1; 91759243Sobrien break; 91859243Sobrien 91959243Sobrien case 'b': /* -b Next arg is input file */ 92059243Sobrien batch = 1; 92159243Sobrien break; 92259243Sobrien 92359243Sobrien case 'c': /* -c Command input from arg */ 92459243Sobrien if (argc == 1) 92559243Sobrien xexit(0); 92659243Sobrien argc--, tempv++; 92759243Sobrien#ifdef M_XENIX 92859243Sobrien /* Xenix Vi bug: 92959243Sobrien it relies on a 7 bit environment (/bin/sh), so it 93059243Sobrien pass ascii arguments with the 8th bit set */ 93159243Sobrien if (!strcmp(argv[0], "sh")) 93259243Sobrien { 93359243Sobrien char *p; 93459243Sobrien 93559243Sobrien for (p = tempv[0]; *p; ++p) 93659243Sobrien *p &= ASCII; 93759243Sobrien } 93859243Sobrien#endif 939316957Sdchagin targinp = tempv[0]; 94059243Sobrien prompt = 0; 94159243Sobrien nofile = 1; 94259243Sobrien break; 94359243Sobrien case 'd': /* -d Load directory stack from file */ 94459243Sobrien rdirs = 1; 94559243Sobrien break; 94659243Sobrien 94759243Sobrien#ifdef apollo 94859243Sobrien case 'D': /* -D Define environment variable */ 94959243Sobrien { 950145479Smp Char *dp; 95159243Sobrien 95259243Sobrien cp = str2short(tcp); 95359243Sobrien if (dp = Strchr(cp, '=')) { 95459243Sobrien *dp++ = '\0'; 95559243Sobrien tsetenv(cp, dp); 95659243Sobrien } 95759243Sobrien else 95859243Sobrien tsetenv(cp, STRNULL); 95959243Sobrien } 96059243Sobrien *tcp = '\0'; /* done with this argument */ 96159243Sobrien break; 96259243Sobrien#endif /* apollo */ 96359243Sobrien 96459243Sobrien case 'e': /* -e Exit on any error */ 96559243Sobrien exiterr = 1; 96659243Sobrien break; 96759243Sobrien 96859243Sobrien case 'f': /* -f Fast start */ 96959243Sobrien fast = 1; 97059243Sobrien break; 97159243Sobrien 97259243Sobrien case 'i': /* -i Interactive, even if !intty */ 97359243Sobrien intact = 1; 97459243Sobrien nofile = 1; 97559243Sobrien break; 97659243Sobrien 97759243Sobrien case 'm': /* -m read .cshrc (from su) */ 97859243Sobrien mflag = 1; 97959243Sobrien break; 98059243Sobrien 98159243Sobrien case 'n': /* -n Don't execute */ 98259243Sobrien noexec = 1; 98359243Sobrien break; 98459243Sobrien 98559243Sobrien case 'q': /* -q (Undoc'd) ... die on quit */ 98659243Sobrien quitit = 1; 98759243Sobrien break; 98859243Sobrien 98959243Sobrien case 's': /* -s Read from std input */ 99059243Sobrien nofile = 1; 99159243Sobrien break; 99259243Sobrien 99359243Sobrien case 't': /* -t Read one line from input */ 99459243Sobrien onelflg = 2; 99559243Sobrien prompt = 0; 99659243Sobrien nofile = 1; 99759243Sobrien break; 99859243Sobrien 99959243Sobrien case 'v': /* -v Echo hist expanded input */ 100059243Sobrien nverbose = 1; /* ... later */ 100159243Sobrien break; 100259243Sobrien 100359243Sobrien case 'x': /* -x Echo just before execution */ 100459243Sobrien nexececho = 1; /* ... later */ 100559243Sobrien break; 100659243Sobrien 100759243Sobrien case 'V': /* -V Echo hist expanded input */ 100859243Sobrien setNS(STRverbose); /* NOW! */ 100959243Sobrien break; 101059243Sobrien 101159243Sobrien case 'X': /* -X Echo just before execution */ 101259243Sobrien setNS(STRecho); /* NOW! */ 101359243Sobrien break; 101459243Sobrien 1015167465Smp case 'F': 101659243Sobrien /* 101759243Sobrien * This will cause children to be created using fork instead of 101859243Sobrien * vfork. 101959243Sobrien */ 102059243Sobrien use_fork = 1; 102159243Sobrien break; 102259243Sobrien 102359243Sobrien case ' ': 102459243Sobrien case '\t': 1025231990Smp case '\r': 1026231990Smp case '\n': 102759243Sobrien /* 102859243Sobrien * for O/S's that don't do the argument parsing right in 102959243Sobrien * "#!/foo -f " scripts 103059243Sobrien */ 103159243Sobrien break; 103259243Sobrien 103359243Sobrien default: /* Unknown command option */ 103459243Sobrien exiterr = 1; 103559243Sobrien stderror(ERR_TCSHUSAGE, tcp-1, progname); 103659243Sobrien break; 103759243Sobrien 103859243Sobrien } while (*tcp); 103959243Sobrien tempv++, argc--; 104059243Sobrien } 104159243Sobrien 104259243Sobrien if (quitit) /* With all due haste, for debugging */ 104359243Sobrien (void) signal(SIGQUIT, SIG_DFL); 104459243Sobrien 104559243Sobrien /* 104659243Sobrien * Unless prevented by -, -c, -i, -s, or -t, if there are remaining 104759243Sobrien * arguments the first of them is the name of a shell file from which to 104859243Sobrien * read commands. 104959243Sobrien */ 105059243Sobrien if (nofile == 0 && argc > 0) { 1051167465Smp nofile = xopen(tempv[0], O_RDONLY|O_LARGEFILE); 105259243Sobrien if (nofile < 0) { 105359243Sobrien child = 1; /* So this ... */ 105459243Sobrien /* ... doesn't return */ 105559243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 105659243Sobrien } 1057167465Smp xfree(ffile); 105859243Sobrien dolzero = 1; 105959243Sobrien ffile = SAVE(tempv[0]); 106059243Sobrien /* 106159243Sobrien * Replace FSHIN. Handle /dev/std{in,out,err} specially 106259243Sobrien * since once they are closed we cannot open them again. 106359243Sobrien * In that case we use our own saved descriptors 106459243Sobrien */ 106559243Sobrien if ((SHIN = dmove(nofile, FSHIN)) < 0) 106659243Sobrien switch(nofile) { 106759243Sobrien case 0: 106859243Sobrien SHIN = FSHIN; 106959243Sobrien break; 107059243Sobrien case 1: 107159243Sobrien SHIN = FSHOUT; 107259243Sobrien break; 107359243Sobrien case 2: 107459243Sobrien SHIN = FSHDIAG; 107559243Sobrien break; 107659243Sobrien default: 107759243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 107859243Sobrien break; 107959243Sobrien } 108059243Sobrien (void) close_on_exec(SHIN, 1); 108159243Sobrien prompt = 0; 108259243Sobrien /* argc not used any more */ tempv++; 108359243Sobrien } 108459243Sobrien 1085100616Smp /* 1086100616Smp * Call to closem() used to be part of initdesc(). Now called below where 1087100616Smp * the script name argument has become stdin. Kernel may have used a file 1088100616Smp * descriptor to hold the name of the script (setuid case) and this name 1089100616Smp * mustn't be lost by closing the fd too soon. 1090100616Smp */ 1091100616Smp closem(); 109259243Sobrien 109359243Sobrien /* 109459243Sobrien * Consider input a tty if it really is or we are interactive. but not for 109559243Sobrien * editing (christos) 109659243Sobrien */ 109759243Sobrien if (!(intty = isatty(SHIN))) { 109859243Sobrien if (adrof(STRedit)) 109959243Sobrien unsetv(STRedit); 110059243Sobrien editing = 0; 110159243Sobrien } 110259243Sobrien intty |= intact; 110359243Sobrien#ifndef convex 110459243Sobrien if (intty || (intact && isatty(SHOUT))) { 110559243Sobrien if (!batch && (uid != euid || gid != egid)) { 110659243Sobrien errno = EACCES; 110759243Sobrien child = 1; /* So this ... */ 110859243Sobrien /* ... doesn't return */ 110959243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 111059243Sobrien } 111159243Sobrien } 111259243Sobrien#endif /* convex */ 111359243Sobrien isoutatty = isatty(SHOUT); 111459243Sobrien isdiagatty = isatty(SHDIAG); 111559243Sobrien /* 111659243Sobrien * Decide whether we should play with signals or not. If we are explicitly 111759243Sobrien * told (via -i, or -) or we are a login shell (arg0 starts with -) or the 111859243Sobrien * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 111959243Sobrien * Note that in only the login shell is it likely that parent may have set 112059243Sobrien * signals to be ignored 112159243Sobrien */ 112259243Sobrien if (loginsh || intact || (intty && isatty(SHOUT))) 112359243Sobrien setintr = 1; 112459243Sobrien settell(); 112559243Sobrien /* 112659243Sobrien * Save the remaining arguments in argv. 112759243Sobrien */ 112859243Sobrien setq(STRargv, blk2short(tempv), &shvhed, VAR_READWRITE); 112959243Sobrien 113059243Sobrien /* 113159243Sobrien * Set up the prompt. 113259243Sobrien */ 113359243Sobrien if (prompt) { 1134231990Smp setcopy(STRprompt, STRdefprompt, VAR_READWRITE); 113559243Sobrien /* that's a meta-questionmark */ 1136167465Smp setcopy(STRprompt2, STRmquestion, VAR_READWRITE); 1137167465Smp setcopy(STRprompt3, STRKCORRECT, VAR_READWRITE); 113859243Sobrien } 113959243Sobrien 114059243Sobrien /* 114159243Sobrien * If we are an interactive shell, then start fiddling with the signals; 114259243Sobrien * this is a tricky game. 114359243Sobrien */ 114459243Sobrien shpgrp = mygetpgrp(); 114559243Sobrien opgrp = tpgrp = -1; 114659243Sobrien if (setintr) { 1147167465Smp struct sigaction osig; 1148167465Smp 114959243Sobrien **argv = '-'; 115059243Sobrien if (!quitit) /* Wary! */ 115159243Sobrien (void) signal(SIGQUIT, SIG_IGN); 1152167465Smp pintr_disabled = 1; 1153167465Smp sigset_interrupting(SIGINT, queue_pintr); 115459243Sobrien (void) signal(SIGTERM, SIG_IGN); 115559243Sobrien 115659243Sobrien /* 115759243Sobrien * No reason I can see not to save history on all these events.. 115859243Sobrien * Most usual occurrence is in a window system, where we're not a login 115959243Sobrien * shell, but might as well be... (sg) 116059243Sobrien * But there might be races when lots of shells exit together... 116159243Sobrien * [this is also incompatible]. 116259243Sobrien * We have to be mre careful here. If the parent wants to 116359243Sobrien * ignore the signals then we leave them untouched... 116459243Sobrien * We also only setup the handlers for shells that are trully 116559243Sobrien * interactive. 116659243Sobrien */ 1167167465Smp sigaction(SIGHUP, NULL, &osig); 1168167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1169167465Smp /* exit processing on HUP */ 1170167465Smp sigset_interrupting(SIGHUP, queue_phup); 117159243Sobrien#ifdef SIGXCPU 1172167465Smp sigaction(SIGXCPU, NULL, &osig); 1173167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1174167465Smp /* exit processing on XCPU */ 1175167465Smp sigset_interrupting(SIGXCPU, queue_phup); 117659243Sobrien#endif 117759243Sobrien#ifdef SIGXFSZ 1178167465Smp sigaction(SIGXFSZ, NULL, &osig); 1179167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1180167465Smp /* exit processing on XFSZ */ 1181167465Smp sigset_interrupting(SIGXFSZ, queue_phup); 118259243Sobrien#endif 118359243Sobrien 1184316957Sdchagin if (quitit == 0 && targinp == 0) { 118559243Sobrien#ifdef SIGTSTP 118659243Sobrien (void) signal(SIGTSTP, SIG_IGN); 118759243Sobrien#endif 118859243Sobrien#ifdef SIGTTIN 118959243Sobrien (void) signal(SIGTTIN, SIG_IGN); 119059243Sobrien#endif 119159243Sobrien#ifdef SIGTTOU 119259243Sobrien (void) signal(SIGTTOU, SIG_IGN); 119359243Sobrien#endif 119459243Sobrien /* 119559243Sobrien * Wait till in foreground, in case someone stupidly runs csh & 119659243Sobrien * dont want to try to grab away the tty. 119759243Sobrien */ 119859243Sobrien if (isatty(FSHDIAG)) 119959243Sobrien f = FSHDIAG; 120059243Sobrien else if (isatty(FSHOUT)) 120159243Sobrien f = FSHOUT; 120259243Sobrien else if (isatty(OLDSTD)) 120359243Sobrien f = OLDSTD; 120459243Sobrien else 120559243Sobrien f = -1; 120659243Sobrien 120759243Sobrien#ifdef NeXT 120859243Sobrien /* NeXT 2.0 /usr/etc/rlogind, does not set our process group! */ 1209316957Sdchagin if (f != -1 && shpgrp == 0) { 121059243Sobrien shpgrp = getpid(); 121159243Sobrien (void) setpgid(0, shpgrp); 121259243Sobrien (void) tcsetpgrp(f, shpgrp); 121359243Sobrien } 121459243Sobrien#endif /* NeXT */ 121559243Sobrien#ifdef BSDJOBS /* if we have tty job control */ 1216316957Sdchagin if (f != -1 && grabpgrp(f, shpgrp) != -1) { 121759243Sobrien /* 121859243Sobrien * Thanks to Matt Day for the POSIX references, and to 121959243Sobrien * Paul Close for the SGI clarification. 122059243Sobrien */ 122159243Sobrien if (setdisc(f) != -1) { 122259243Sobrien opgrp = shpgrp; 122359243Sobrien shpgrp = getpid(); 122459243Sobrien tpgrp = shpgrp; 122559243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 122659243Sobrien /* 122759243Sobrien * On hpux 7.03 this fails with EPERM. This happens on 122859243Sobrien * the 800 when opgrp != shpgrp at this point. (we were 122959243Sobrien * forked from a non job control shell) 123059243Sobrien * POSIX 7.2.4, says we failed because the process 123159243Sobrien * group specified did not belong to a process 123259243Sobrien * in the same session with the tty. So we set our 123359243Sobrien * process group and try again. 123459243Sobrien */ 123559243Sobrien if (setpgid(0, shpgrp) == -1) { 123659243Sobrien xprintf("setpgid:"); 123759243Sobrien goto notty; 123859243Sobrien } 123959243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 124059243Sobrien xprintf("tcsetpgrp:"); 124159243Sobrien goto notty; 124259243Sobrien } 124359243Sobrien } 124459243Sobrien /* 124559243Sobrien * We check the process group now. If it is the same, then 124659243Sobrien * we don't need to set it again. On hpux 7.0 on the 300's 124759243Sobrien * if we set it again it fails with EPERM. This is the 124859243Sobrien * correct behavior according to POSIX 4.3.3 if the process 124959243Sobrien * was a session leader . 125059243Sobrien */ 125159243Sobrien else if (shpgrp != mygetpgrp()) { 125259243Sobrien if(setpgid(0, shpgrp) == -1) { 125359243Sobrien xprintf("setpgid:"); 125459243Sobrien goto notty; 125559243Sobrien } 125659243Sobrien } 125759243Sobrien#ifdef IRIS4D 125859243Sobrien /* 125959243Sobrien * But on irix 3.3 we need to set it again, even if it is 126059243Sobrien * the same. We do that to tell the system that we 126159243Sobrien * need BSD process group compatibility. 126259243Sobrien */ 126359243Sobrien else 126459243Sobrien (void) setpgid(0, shpgrp); 126559243Sobrien#endif 126659243Sobrien (void) close_on_exec(dcopy(f, FSHTTY), 1); 126759243Sobrien } 126859243Sobrien else 126959243Sobrien tpgrp = -1; 127059243Sobrien } 127159243Sobrien if (tpgrp == -1) { 127259243Sobrien notty: 1273167465Smp xprintf(CGETS(11, 1, "Warning: no access to tty (%s).\n"), 1274195609Smp strerror(errno)); 1275195609Smp xprintf("%s", 1276195609Smp CGETS(11, 2, "Thus no job control in this shell.\n")); 127759243Sobrien /* 127859243Sobrien * Fix from:Sakari Jalovaara <sja@sirius.hut.fi> if we don't 127959243Sobrien * have access to tty, disable editing too 128059243Sobrien */ 128159243Sobrien if (adrof(STRedit)) 128259243Sobrien unsetv(STRedit); 128359243Sobrien editing = 0; 128459243Sobrien } 128559243Sobrien#else /* BSDJOBS */ /* don't have job control, so frotz it */ 128659243Sobrien tpgrp = -1; 128759243Sobrien#endif /* BSDJOBS */ 128859243Sobrien } 128959243Sobrien } 1290167465Smp if (setintr == 0 && parintr.sa_handler == SIG_DFL) 129159243Sobrien setintr = 1; 129259243Sobrien 129359243Sobrien/* 129459243Sobrien * SVR4 doesn't send a SIGCHLD when a child is stopped or continued if the 129559243Sobrien * handler is installed with signal(2) or sigset(2). sigaction(2) must 129659243Sobrien * be used instead. 129759243Sobrien * 129859243Sobrien * David Dawes (dawes@physics.su.oz.au) Sept 1991 129959243Sobrien */ 1300167465Smp sigset_interrupting(SIGCHLD, queue_pchild); 130159243Sobrien 1302316957Sdchagin if (intty && !targinp) 130359243Sobrien (void) ed_Setup(editing);/* Get the tty state, and set defaults */ 130459243Sobrien /* Only alter the tty state if editing */ 130559243Sobrien 130659243Sobrien /* 130759243Sobrien * Set an exit here in case of an interrupt or error reading the shell 130859243Sobrien * start-up scripts. 130959243Sobrien */ 1310131962Smp osetintr = setintr; 1311131962Smp oparintr = parintr; 1312167465Smp (void)cleanup_push_mark(); /* There is no outer handler */ 1313167465Smp if (setexit() != 0) /* PWP */ 1314167465Smp reenter = 1; 1315167465Smp else 1316167465Smp reenter = 0; 131769408Sache exitset++; 131859243Sobrien haderr = 0; /* In case second time through */ 131959243Sobrien if (!fast && reenter == 0) { 132059243Sobrien /* Will have varval(STRhome) here because set fast if don't */ 132159243Sobrien { 1322167465Smp pintr_disabled++; 1323167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1324167465Smp setintr = 0;/*FIXRESET:cleanup*/ 1325167465Smp /* onintr in /etc/ files has no effect */ 1326167465Smp parintr.sa_handler = SIG_IGN;/*FIXRESET: cleanup*/ 132759243Sobrien#ifdef LOGINFIRST 132859243Sobrien#ifdef _PATH_DOTLOGIN 132959243Sobrien if (loginsh) 1330167465Smp (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 133159243Sobrien#endif 133259243Sobrien#endif 133359243Sobrien 133459243Sobrien#ifdef _PATH_DOTCSHRC 133559243Sobrien (void) srcfile(_PATH_DOTCSHRC, 0, 0, NULL); 133659243Sobrien#endif 1337316957Sdchagin if (!targinp && !onelflg && !havhash) 133859243Sobrien dohash(NULL,NULL); 133959243Sobrien#ifndef LOGINFIRST 134059243Sobrien#ifdef _PATH_DOTLOGIN 134159243Sobrien if (loginsh) 134259243Sobrien (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 134359243Sobrien#endif 134459243Sobrien#endif 1345167465Smp cleanup_until(&pintr_disabled); 134659243Sobrien setintr = osetintr; 134759243Sobrien parintr = oparintr; 134859243Sobrien } 134959243Sobrien#ifdef LOGINFIRST 135059243Sobrien if (loginsh) 135159243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 135259243Sobrien#endif 135359243Sobrien /* upward compat. */ 135459243Sobrien if (!srccat(varval(STRhome), STRsldottcshrc)) 135559243Sobrien (void) srccat(varval(STRhome), STRsldotcshrc); 135659243Sobrien 1357316957Sdchagin if (!targinp && !onelflg && !havhash) 135859243Sobrien dohash(NULL,NULL); 135959243Sobrien 136059243Sobrien /* 136159243Sobrien * Source history before .login so that it is available in .login 136259243Sobrien */ 136359243Sobrien loadhist(NULL, 0); 136459243Sobrien#ifndef LOGINFIRST 136559243Sobrien if (loginsh) 136659243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 136759243Sobrien#endif 1368167465Smp if (loginsh || rdirs) 136959243Sobrien loaddirs(NULL); 137059243Sobrien } 1371131962Smp /* Reset interrupt flag */ 1372131962Smp setintr = osetintr; 1373131962Smp parintr = oparintr; 1374167465Smp exitset--; 1375131962Smp 137659243Sobrien /* Initing AFTER .cshrc is the Right Way */ 1377316957Sdchagin if (intty && !targinp) { /* PWP setup stuff */ 137859243Sobrien ed_Init(); /* init the new line editor */ 137959243Sobrien#ifdef SIG_WINDOW 138059243Sobrien check_window_size(1); /* mung environment */ 138159243Sobrien#endif /* SIG_WINDOW */ 138259243Sobrien } 138359243Sobrien 138459243Sobrien /* 138559243Sobrien * Now are ready for the -v and -x flags 138659243Sobrien */ 138759243Sobrien if (nverbose) 138859243Sobrien setNS(STRverbose); 138959243Sobrien if (nexececho) 139059243Sobrien setNS(STRecho); 139159243Sobrien 1392316957Sdchagin 1393316957Sdchagin if (targinp) { 1394354195Sbrooks /* If this -c command caused an error before, skip processing */ 1395354195Sbrooks if (reenter && arginp) { 1396354195Sbrooks exitcode = 1; 1397354195Sbrooks goto done; 1398354195Sbrooks } 1399354195Sbrooks 1400316957Sdchagin arginp = SAVE(targinp); 1401316957Sdchagin /* 1402316957Sdchagin * we put the command into a variable 1403316957Sdchagin */ 1404316957Sdchagin if (arginp != NULL) 1405316957Sdchagin setv(STRcommand, quote(Strsave(arginp)), VAR_READWRITE); 1406316957Sdchagin 1407316957Sdchagin /* 1408316957Sdchagin * * Give an error on -c arguments that end in * backslash to 1409316957Sdchagin * ensure that you don't make * nonportable csh scripts. 1410316957Sdchagin */ 1411316957Sdchagin { 1412316957Sdchagin int count; 1413316957Sdchagin 1414316957Sdchagin cp = Strend(arginp); 1415316957Sdchagin count = 0; 1416316957Sdchagin while (cp > arginp && *--cp == '\\') 1417316957Sdchagin ++count; 1418316957Sdchagin if ((count & 1) != 0) { 1419316957Sdchagin exiterr = 1; 1420316957Sdchagin stderror(ERR_ARGC); 1421316957Sdchagin } 1422316957Sdchagin } 1423316957Sdchagin } 142459243Sobrien /* 142559243Sobrien * All the rest of the world is inside this call. The argument to process 142659243Sobrien * indicates whether it should catch "error unwinds". Thus if we are a 142759243Sobrien * interactive shell our call here will never return by being blown past on 142859243Sobrien * an error. 142959243Sobrien */ 143059243Sobrien process(setintr); 143159243Sobrien 1432354195Sbrooksdone: 143359243Sobrien /* 143459243Sobrien * Mop-up. 143559243Sobrien */ 1436197812Srdivacky /* Take care of these (especially HUP) here instead of inside flush. */ 1437197812Srdivacky handle_pending_signals(); 143859243Sobrien if (intty) { 143959243Sobrien if (loginsh) { 144059243Sobrien xprintf("logout\n"); 1441167465Smp xclose(SHIN); 144259243Sobrien child = 1; 144359243Sobrien#ifdef TESLA 144459243Sobrien do_logout = 1; 144559243Sobrien#endif /* TESLA */ 144659243Sobrien goodbye(NULL, NULL); 144759243Sobrien } 144859243Sobrien else { 144959243Sobrien xprintf("exit\n"); 145059243Sobrien } 145159243Sobrien } 145259243Sobrien record(); 145359243Sobrien exitstat(); 1454354195Sbrooks return exitcode; 145559243Sobrien} 145659243Sobrien 145759243Sobrienvoid 1458167465Smpuntty(void) 145959243Sobrien{ 146059243Sobrien#ifdef BSDJOBS 146159243Sobrien if (tpgrp > 0 && opgrp != shpgrp) { 146259243Sobrien (void) setpgid(0, opgrp); 146359243Sobrien (void) tcsetpgrp(FSHTTY, opgrp); 146459243Sobrien (void) resetdisc(FSHTTY); 146559243Sobrien } 146659243Sobrien#endif /* BSDJOBS */ 146759243Sobrien} 146859243Sobrien 146959243Sobrienvoid 1470167465Smpimportpath(Char *cp) 147159243Sobrien{ 1472167465Smp size_t i = 0; 1473145479Smp Char *dp; 1474145479Smp Char **pv; 147559243Sobrien int c; 147659243Sobrien 147759243Sobrien for (dp = cp; *dp; dp++) 147859243Sobrien if (*dp == PATHSEP) 147959243Sobrien i++; 148059243Sobrien /* 148159243Sobrien * i+2 where i is the number of colons in the path. There are i+1 148259243Sobrien * directories in the path plus we need room for a zero terminator. 148359243Sobrien */ 1484167465Smp pv = xcalloc(i + 2, sizeof(Char *)); 148559243Sobrien dp = cp; 148659243Sobrien i = 0; 148759243Sobrien if (*dp) 148859243Sobrien for (;;) { 148959243Sobrien if ((c = *dp) == PATHSEP || c == 0) { 149059243Sobrien *dp = 0; 149159243Sobrien pv[i++] = Strsave(*cp ? cp : STRdot); 149259243Sobrien if (c) { 149359243Sobrien cp = dp + 1; 149459243Sobrien *dp = PATHSEP; 149559243Sobrien } 149659243Sobrien else 149759243Sobrien break; 149859243Sobrien } 149969408Sache#ifdef WINNT_NATIVE 150059243Sobrien else if (*dp == '\\') 150159243Sobrien *dp = '/'; 150269408Sache#endif /* WINNT_NATIVE */ 150359243Sobrien dp++; 150459243Sobrien } 150559243Sobrien pv[i] = 0; 1506167465Smp cleanup_push(pv, blk_cleanup); 150759243Sobrien setq(STRpath, pv, &shvhed, VAR_READWRITE); 1508167465Smp cleanup_ignore(pv); 1509167465Smp cleanup_until(pv); 151059243Sobrien} 151159243Sobrien 151259243Sobrien/* 151359243Sobrien * Source to the file which is the catenation of the argument names. 151459243Sobrien */ 151559243Sobrienstatic int 1516167465Smpsrccat(Char *cp, Char *dp) 151759243Sobrien{ 151859243Sobrien if (cp[0] == '/' && cp[1] == '\0') 151959243Sobrien return srcfile(short2str(dp), (mflag ? 0 : 1), 0, NULL); 152059243Sobrien else { 1521145479Smp Char *ep; 152259243Sobrien char *ptr; 152359243Sobrien int rv; 152459243Sobrien 152569408Sache#ifdef WINNT_NATIVE 1526167465Smp ep = Strend(cp); 1527167465Smp if (ep != cp && ep[-1] == '/' && dp[0] == '/') /* silly win95 */ 152859243Sobrien dp++; 152969408Sache#endif /* WINNT_NATIVE */ 153059243Sobrien 153159243Sobrien ep = Strspl(cp, dp); 1532167465Smp cleanup_push(ep, xfree); 153359243Sobrien ptr = short2str(ep); 153459243Sobrien 153559243Sobrien rv = srcfile(ptr, (mflag ? 0 : 1), 0, NULL); 1536167465Smp cleanup_until(ep); 153759243Sobrien return rv; 153859243Sobrien } 153959243Sobrien} 154059243Sobrien 154159243Sobrien/* 154259243Sobrien * Source to a file putting the file descriptor in a safe place (> 2). 154359243Sobrien */ 154483098Smp#ifndef WINNT_NATIVE 154559243Sobrienstatic int 154683098Smp#else 154783098Smpint 154883098Smp#endif /*WINNT_NATIVE*/ 1549167465Smpsrcfile(const char *f, int onlyown, int flag, Char **av) 155059243Sobrien{ 1551145479Smp int unit; 155259243Sobrien 1553167465Smp if ((unit = xopen(f, O_RDONLY|O_LARGEFILE)) == -1) 155459243Sobrien return 0; 1555167465Smp cleanup_push(&unit, open_cleanup); 155659243Sobrien unit = dmove(unit, -1); 1557167465Smp cleanup_ignore(&unit); 1558167465Smp cleanup_until(&unit); 155959243Sobrien 156059243Sobrien (void) close_on_exec(unit, 1); 156159243Sobrien srcunit(unit, onlyown, flag, av); 156259243Sobrien return 1; 156359243Sobrien} 156459243Sobrien 156559243Sobrien 156659243Sobrien/* 156759243Sobrien * Save the shell state, and establish new argument vector, and new input 156859243Sobrien * fd. 156959243Sobrien */ 157059243Sobrienstatic void 1571167465Smpst_save(struct saved_state *st, int unit, int hflg, Char **al, Char **av) 157259243Sobrien{ 157359243Sobrien st->insource = insource; 157459243Sobrien st->SHIN = SHIN; 1575100616Smp /* Want to preserve the meaning of "source file >output". 1576100616Smp * Save old descriptors, move new 0,1,2 to safe places and assign 1577100616Smp * them to SH* and let process() redo 0,1,2 from them. 1578100616Smp * 1579100616Smp * The macro returns true if d1 and d2 are good and they point to 1580100616Smp * different things. If you don't avoid saving duplicate 1581100616Smp * descriptors, you really limit the depth of "source" recursion 1582100616Smp * you can do because of all the open file descriptors. -IAN! 1583100616Smp */ 1584100616Smp#define NEED_SAVE_FD(d1,d2) \ 1585100616Smp (fstat(d1, &s1) != -1 && fstat(d2, &s2) != -1 \ 1586100616Smp && (s1.st_ino != s2.st_ino || s1.st_dev != s2.st_dev) ) 1587100616Smp 1588100616Smp st->OLDSTD = st->SHOUT = st->SHDIAG = -1;/* test later to restore these */ 1589100616Smp if (didfds) { 1590100616Smp struct stat s1, s2; 1591145479Smp if (NEED_SAVE_FD(0,OLDSTD)) { 1592145479Smp st->OLDSTD = OLDSTD; 1593145479Smp OLDSTD = dmove(0, -1); 1594145479Smp (void)close_on_exec(OLDSTD, 1); 1595145479Smp } 1596145479Smp if (NEED_SAVE_FD(1,SHOUT)) { 1597145479Smp st->SHOUT = SHOUT; 1598145479Smp SHOUT = dmove(1, -1); 1599145479Smp (void)close_on_exec(SHOUT, 1); 1600145479Smp } 1601145479Smp if (NEED_SAVE_FD(2,SHDIAG)) { 1602145479Smp st->SHDIAG = SHDIAG; 1603145479Smp SHDIAG = dmove(2, -1); 1604145479Smp (void)close_on_exec(SHDIAG, 1); 1605145479Smp } 1606100616Smp donefds(); 1607100616Smp } 1608100616Smp 160959243Sobrien st->intty = intty; 161059243Sobrien st->whyles = whyles; 161159243Sobrien st->gointr = gointr; 161259243Sobrien st->arginp = arginp; 161359243Sobrien st->evalp = evalp; 161459243Sobrien st->evalvec = evalvec; 161559243Sobrien st->alvecp = alvecp; 161659243Sobrien st->alvec = alvec; 161759243Sobrien st->onelflg = onelflg; 161859243Sobrien st->enterhist = enterhist; 1619195609Smp st->justpr = justpr; 162059243Sobrien if (hflg) 162159243Sobrien st->HIST = HIST; 162259243Sobrien else 162359243Sobrien st->HIST = '\0'; 162459243Sobrien st->cantell = cantell; 162559243Sobrien cpybin(st->B, B); 162659243Sobrien 162759243Sobrien /* 162859243Sobrien * we can now pass arguments to source. 162959243Sobrien * For compatibility we do that only if arguments were really 163059243Sobrien * passed, otherwise we keep the old, global $argv like before. 163159243Sobrien */ 163259243Sobrien if (av != NULL && *av != NULL) { 163359243Sobrien struct varent *vp; 1634100616Smp if ((vp = adrof(STRargv)) != NULL && vp->vec != NULL) 163559243Sobrien st->argv = saveblk(vp->vec); 163659243Sobrien else 163759243Sobrien st->argv = NULL; 163859243Sobrien setq(STRargv, saveblk(av), &shvhed, VAR_READWRITE); 163959243Sobrien } 164059243Sobrien else 164159243Sobrien st->argv = NULL; 1642167465Smp st->av = av; 164359243Sobrien 164459243Sobrien SHIN = unit; /* Do this first */ 164559243Sobrien 164659243Sobrien /* Establish new input arena */ 164759243Sobrien { 164859243Sobrien fbuf = NULL; 164959243Sobrien fseekp = feobp = fblocks = 0; 165059243Sobrien settell(); 165159243Sobrien } 165259243Sobrien 165359243Sobrien arginp = 0; 165459243Sobrien onelflg = 0; 165559243Sobrien intty = isatty(SHIN); 165659243Sobrien whyles = 0; 165759243Sobrien gointr = 0; 165859243Sobrien evalvec = 0; 165959243Sobrien evalp = 0; 166059243Sobrien alvec = al; 166159243Sobrien alvecp = 0; 166259243Sobrien enterhist = hflg; 166359243Sobrien if (enterhist) 166459243Sobrien HIST = '\0'; 166559243Sobrien insource = 1; 166659243Sobrien} 166759243Sobrien 166859243Sobrien 166959243Sobrien/* 167059243Sobrien * Restore the shell to a saved state 167159243Sobrien */ 167259243Sobrienstatic void 1673167465Smpst_restore(void *xst) 1674167465Smp{ 167559243Sobrien struct saved_state *st; 1676167465Smp 1677167465Smp st = xst; 167859243Sobrien if (st->SHIN == -1) 167959243Sobrien return; 168059243Sobrien 168159243Sobrien /* Reset input arena */ 168259243Sobrien { 1683145479Smp int i; 1684145479Smp Char** nfbuf = fbuf; 1685145479Smp int nfblocks = fblocks; 168659243Sobrien 168759243Sobrien fblocks = 0; 168859243Sobrien fbuf = NULL; 168959243Sobrien for (i = 0; i < nfblocks; i++) 1690167465Smp xfree(nfbuf[i]); 1691167465Smp xfree(nfbuf); 169259243Sobrien } 169359243Sobrien cpybin(B, st->B); 169459243Sobrien 1695167465Smp xclose(SHIN); 169659243Sobrien 169759243Sobrien insource = st->insource; 169859243Sobrien SHIN = st->SHIN; 1699100616Smp if (st->OLDSTD != -1) 1700167465Smp xclose(OLDSTD), OLDSTD = st->OLDSTD; 1701100616Smp if (st->SHOUT != -1) 1702167465Smp xclose(SHOUT), SHOUT = st->SHOUT; 1703100616Smp if (st->SHDIAG != -1) 1704167465Smp xclose(SHDIAG), SHDIAG = st->SHDIAG; 170559243Sobrien arginp = st->arginp; 170659243Sobrien onelflg = st->onelflg; 170759243Sobrien evalp = st->evalp; 170859243Sobrien evalvec = st->evalvec; 170959243Sobrien alvecp = st->alvecp; 171059243Sobrien alvec = st->alvec; 171159243Sobrien intty = st->intty; 171259243Sobrien whyles = st->whyles; 171359243Sobrien gointr = st->gointr; 171459243Sobrien if (st->HIST != '\0') 171559243Sobrien HIST = st->HIST; 171659243Sobrien enterhist = st->enterhist; 171759243Sobrien cantell = st->cantell; 1718195609Smp justpr = st->justpr; 171959243Sobrien 172059243Sobrien if (st->argv != NULL) 172159243Sobrien setq(STRargv, st->argv, &shvhed, VAR_READWRITE); 1722167465Smp else if (st->av != NULL && *st->av != NULL && adrof(STRargv) != NULL) 172359243Sobrien unsetv(STRargv); 172459243Sobrien} 172559243Sobrien 172659243Sobrien/* 172759243Sobrien * Source to a unit. If onlyown it must be our file or our group or 172859243Sobrien * we don't chance it. This occurs on ".cshrc"s and the like. 172959243Sobrien */ 173059243Sobrienstatic void 1731167465Smpsrcunit(int unit, int onlyown, int hflg, Char **av) 173259243Sobrien{ 173359243Sobrien struct saved_state st; 1734167465Smp 173559243Sobrien st.SHIN = -1; /* st_restore checks this */ 173659243Sobrien 173759243Sobrien if (unit < 0) 173859243Sobrien return; 173959243Sobrien 174059243Sobrien if (onlyown) { 174159243Sobrien struct stat stb; 174259243Sobrien 174359243Sobrien if (fstat(unit, &stb) < 0) { 1744167465Smp xclose(unit); 174559243Sobrien return; 174659243Sobrien } 174759243Sobrien } 174859243Sobrien 1749167465Smp /* Does nothing before st_save() because st.SHIN == -1 */ 1750167465Smp cleanup_push(&st, st_restore); 1751167465Smp if (setintr) { 1752167465Smp pintr_disabled++; 1753167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1754167465Smp } 175559243Sobrien 175659243Sobrien /* Save the current state and move us to a new state */ 175759243Sobrien st_save(&st, unit, hflg, NULL, av); 175859243Sobrien 175959243Sobrien /* 176059243Sobrien * Now if we are allowing commands to be interrupted, we let ourselves be 176159243Sobrien * interrupted. 176259243Sobrien */ 1763167465Smp if (setintr) { 1764167465Smp cleanup_until(&pintr_disabled); 1765167465Smp pintr_disabled++; 1766167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 176759243Sobrien } 176859243Sobrien 1769167465Smp process(0); /* 0 -> blow away on errors */ 177059243Sobrien 177159243Sobrien /* Restore the old state */ 1772167465Smp cleanup_until(&st); 177359243Sobrien} 177459243Sobrien 177559243Sobrien 177659243Sobrien/*ARGSUSED*/ 177759243Sobrienvoid 1778167465Smpgoodbye(Char **v, struct command *c) 177959243Sobrien{ 1780145479Smp USE(v); 178159243Sobrien USE(c); 178259243Sobrien record(); 178359243Sobrien 178459243Sobrien if (loginsh) { 1785167465Smp size_t omark; 1786167465Smp sigset_t set; 1787167465Smp 1788195609Smp sigemptyset(&set); 1789167465Smp signal(SIGQUIT, SIG_IGN); 1790167465Smp sigaddset(&set, SIGQUIT); 1791167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 1792167465Smp signal(SIGINT, SIG_IGN); 1793167465Smp sigaddset(&set, SIGINT); 1794167465Smp signal(SIGTERM, SIG_IGN); 1795167465Smp sigaddset(&set, SIGTERM); 1796167465Smp signal(SIGHUP, SIG_IGN); 1797167465Smp sigaddset(&set, SIGHUP); 1798167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 1799167465Smp phup_disabled = 1; 180059243Sobrien setintr = 0; /* No interrupts after "logout" */ 180159243Sobrien /* Trap errors inside .logout */ 1802167465Smp omark = cleanup_push_mark(); 1803167465Smp if (setexit() == 0) { 1804167465Smp if (!(adrof(STRlogout))) 1805167465Smp setcopy(STRlogout, STRnormal, VAR_READWRITE); 180659243Sobrien#ifdef _PATH_DOTLOGOUT 1807167465Smp (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 180859243Sobrien#endif 1809167465Smp if (adrof(STRhome)) 1810167465Smp (void) srccat(varval(STRhome), STRsldtlogout); 181159243Sobrien#ifdef TESLA 1812167465Smp do_logout = 1; 181359243Sobrien#endif /* TESLA */ 1814167465Smp } 1815167465Smp cleanup_pop_mark(omark); 181659243Sobrien } 181759243Sobrien exitstat(); 181859243Sobrien} 181959243Sobrien 182059243Sobrienvoid 1821167465Smpexitstat(void) 182259243Sobrien{ 182359243Sobrien#ifdef PROF 1824231990Smp _mcleanup(); 182559243Sobrien#endif 182659243Sobrien /* 182759243Sobrien * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit 182859243Sobrien * directly because we poke child here. Otherwise we might continue 182959243Sobrien * unwarrantedly (sic). 183059243Sobrien */ 183159243Sobrien child = 1; 183259243Sobrien 183359243Sobrien xexit(getn(varval(STRstatus))); 183459243Sobrien} 183559243Sobrien 183659243Sobrien/* 183759243Sobrien * in the event of a HUP we want to save the history 183859243Sobrien */ 1839167465Smpvoid 1840167465Smpphup(void) 184159243Sobrien{ 184259243Sobrien if (loginsh) { 1843167465Smp setcopy(STRlogout, STRhangup, VAR_READWRITE); 184459243Sobrien#ifdef _PATH_DOTLOGOUT 184559243Sobrien (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 184659243Sobrien#endif 184759243Sobrien if (adrof(STRhome)) 184859243Sobrien (void) srccat(varval(STRhome), STRsldtlogout); 184959243Sobrien } 185059243Sobrien 185159243Sobrien record(); 185259243Sobrien 185359243Sobrien#ifdef POSIXJOBS 185459243Sobrien /* 185559243Sobrien * We kill the last foreground process group. It then becomes 185659243Sobrien * responsible to propagate the SIGHUP to its progeny. 185759243Sobrien */ 185859243Sobrien { 185959243Sobrien struct process *pp, *np; 186059243Sobrien 186159243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 186259243Sobrien np = pp; 186359243Sobrien /* 186459243Sobrien * Find if this job is in the foreground. It could be that 186559243Sobrien * the process leader has exited and the foreground flag 186659243Sobrien * is cleared for it. 186759243Sobrien */ 186859243Sobrien do 186959243Sobrien /* 187059243Sobrien * If a process is in the foreground we try to kill 187159243Sobrien * it's process group. If we succeed, then the 187259243Sobrien * whole job is gone. Otherwise we keep going... 187359243Sobrien * But avoid sending HUP to the shell again. 187459243Sobrien */ 187559243Sobrien if (((np->p_flags & PFOREGND) != 0) && np->p_jobid != shpgrp) { 187659243Sobrien np->p_flags &= ~PHUP; 187759243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 187859243Sobrien /* In case the job was suspended... */ 187959243Sobrien#ifdef SIGCONT 188059243Sobrien (void) killpg(np->p_jobid, SIGCONT); 188159243Sobrien#endif 188259243Sobrien break; 188359243Sobrien } 188459243Sobrien } 188559243Sobrien while ((np = np->p_friends) != pp); 188659243Sobrien } 188759243Sobrien } 188859243Sobrien#endif /* POSIXJOBS */ 188959243Sobrien 1890167465Smp xexit(SIGHUP); 189159243Sobrien} 189259243Sobrien 189359243Sobrienstatic Char *jobargv[2] = {STRjobs, 0}; 189459243Sobrien 189559243Sobrien/* 189659243Sobrien * Catch an interrupt, e.g. during lexical input. 189759243Sobrien * If we are an interactive shell, we reset the interrupt catch 189859243Sobrien * immediately. In any case we drain the shell output, 189959243Sobrien * and finally go through the normal error mechanism, which 190059243Sobrien * gets a chance to make the shell go away. 190159243Sobrien */ 1902167465Smpint just_signaled; /* bugfix by Michael Bloom (mg@ttidca.TTI.COM) */ 190359243Sobrien 1904167465Smpvoid 1905167465Smppintr(void) 190659243Sobrien{ 190759243Sobrien just_signaled = 1; 190859243Sobrien pintr1(1); 190959243Sobrien} 191059243Sobrien 191159243Sobrienvoid 1912167465Smppintr1(int wantnl) 191359243Sobrien{ 191459243Sobrien if (setintr) { 191559243Sobrien if (pjobs) { 191659243Sobrien pjobs = 0; 191759243Sobrien xputchar('\n'); 191859243Sobrien dojobs(jobargv, NULL); 191959243Sobrien stderror(ERR_NAME | ERR_INTR); 192059243Sobrien } 192159243Sobrien } 192259243Sobrien /* MH - handle interrupted completions specially */ 192359243Sobrien { 192459243Sobrien if (InsideCompletion) 192559243Sobrien stderror(ERR_SILENT); 192659243Sobrien } 192759243Sobrien /* JV - Make sure we shut off inputl */ 192859243Sobrien { 192959243Sobrien (void) Cookedmode(); 193059243Sobrien GettingInput = 0; 1931316957Sdchagin if (evalvec) 1932316957Sdchagin doneinp = 1; 193359243Sobrien } 193459243Sobrien drainoline(); 1935145479Smp#ifdef HAVE_GETPWENT 193659243Sobrien (void) endpwent(); 1937145479Smp#endif 193859243Sobrien 193959243Sobrien /* 194059243Sobrien * If we have an active "onintr" then we search for the label. Note that if 194159243Sobrien * one does "onintr -" then we shan't be interruptible so we needn't worry 194259243Sobrien * about that here. 194359243Sobrien */ 194459243Sobrien if (gointr) { 194559243Sobrien gotolab(gointr); 194659243Sobrien reset(); 194759243Sobrien } 194859243Sobrien else if (intty && wantnl) { 194959243Sobrien if (editing) { 195059243Sobrien /* 195159243Sobrien * If we are editing a multi-line input command, and move to 195259243Sobrien * the beginning of the line, we don't want to trash it when 195359243Sobrien * we hit ^C 195459243Sobrien */ 195559243Sobrien PastBottom(); 195659243Sobrien ClearLines(); 195759243Sobrien ClearDisp(); 195859243Sobrien } 195959243Sobrien else { 196059243Sobrien /* xputchar('\n'); *//* Some like this, others don't */ 196159243Sobrien (void) putraw('\r'); 196259243Sobrien (void) putraw('\n'); 196359243Sobrien } 196459243Sobrien } 196559243Sobrien stderror(ERR_SILENT); 196659243Sobrien} 196759243Sobrien 196859243Sobrien/* 196959243Sobrien * Process is the main driving routine for the shell. 197059243Sobrien * It runs all command processing, except for those within { ... } 197159243Sobrien * in expressions (which is run by a routine evalav in sh.exp.c which 197259243Sobrien * is a stripped down process), and `...` evaluation which is run 197359243Sobrien * also by a subset of this code in sh.glob.c in the routine backeval. 197459243Sobrien * 197559243Sobrien * The code here is a little strange because part of it is interruptible 197659243Sobrien * and hence freeing of structures appears to occur when none is necessary 197759243Sobrien * if this is ignored. 197859243Sobrien * 197959243Sobrien * Note that if catch is not set then we will unwind on any error. 198059243Sobrien * If an end-of-file occurs, we return. 198159243Sobrien */ 198259243Sobrienvoid 1983167465Smpprocess(int catch) 198459243Sobrien{ 198559243Sobrien jmp_buf_t osetexit; 1986231990Smp /* PWP: This might get nuked by longjmp so don't make it a register var */ 1987167465Smp size_t omark; 1988195609Smp volatile int didexitset = 0; 198959243Sobrien 199059243Sobrien getexit(osetexit); 1991167465Smp omark = cleanup_push_mark(); 199259243Sobrien for (;;) { 1993167465Smp struct command *t; 1994167465Smp int hadhist, old_pintr_disabled; 199559243Sobrien 1996195609Smp (void)setexit(); 1997195609Smp if (didexitset == 0) { 1998195609Smp exitset++; 1999195609Smp didexitset++; 2000195609Smp } 200159243Sobrien pendjob(); 200259243Sobrien 200359243Sobrien justpr = enterhist; /* execute if not entering history */ 200459243Sobrien 200559243Sobrien if (haderr) { 200659243Sobrien if (!catch) { 200759243Sobrien /* unwind */ 200859243Sobrien doneinp = 0; 2009167465Smp cleanup_pop_mark(omark); 201059243Sobrien resexit(osetexit); 201159243Sobrien reset(); 201259243Sobrien } 201359243Sobrien haderr = 0; 201459243Sobrien /* 201559243Sobrien * Every error is eventually caught here or the shell dies. It is 201659243Sobrien * at this point that we clean up any left-over open files, by 201759243Sobrien * closing all but a fixed number of pre-defined files. Thus 201859243Sobrien * routines don't have to worry about leaving files open due to 201959243Sobrien * deeper errors... they will get closed here. 202059243Sobrien */ 202159243Sobrien closem(); 202259243Sobrien continue; 202359243Sobrien } 202459243Sobrien if (doneinp) { 202559243Sobrien doneinp = 0; 202659243Sobrien break; 202759243Sobrien } 202859243Sobrien if (chkstop) 202959243Sobrien chkstop--; 203059243Sobrien if (neednote) 203159243Sobrien pnote(); 203259243Sobrien if (intty && prompt && evalvec == 0) { 203359243Sobrien just_signaled = 0; 203459243Sobrien mailchk(); 203559243Sobrien /* 203659243Sobrien * Watch for logins/logouts. Next is scheduled commands stored 203759243Sobrien * previously using "sched." Then execute periodic commands. 203859243Sobrien * Following that, the prompt precmd is run. 203959243Sobrien */ 204059243Sobrien#ifndef HAVENOUTMP 204159243Sobrien watch_login(0); 204259243Sobrien#endif /* !HAVENOUTMP */ 2043167465Smp sched_run(); 204459243Sobrien period_cmd(); 204559243Sobrien precmd(); 204659243Sobrien /* 204759243Sobrien * If we are at the end of the input buffer then we are going to 204859243Sobrien * read fresh stuff. Otherwise, we are rereading input and don't 204959243Sobrien * need or want to prompt. 205059243Sobrien */ 205169408Sache if (fseekp == feobp && aret == TCSH_F_SEEK) 205259243Sobrien printprompt(0, NULL); 205359243Sobrien flush(); 205459243Sobrien setalarm(1); 205559243Sobrien } 205659243Sobrien if (seterr) { 2057167465Smp xfree(seterr); 205859243Sobrien seterr = NULL; 205959243Sobrien } 206059243Sobrien 206159243Sobrien /* 2062167465Smp * Interruptible during interactive reads 2063167465Smp */ 2064167465Smp if (setintr) 2065167465Smp pintr_push_enable(&old_pintr_disabled); 2066316957Sdchagin freelex(¶ml); 2067167465Smp hadhist = lex(¶ml); 2068167465Smp if (setintr) 2069167465Smp cleanup_until(&old_pintr_disabled); 2070167465Smp cleanup_push(¶ml, lex_cleanup); 2071167465Smp 2072167465Smp /* 207359243Sobrien * Echo not only on VERBOSE, but also with history expansion. If there 207459243Sobrien * is a lexical error then we forego history echo. 2075231990Smp * Do not echo if we're only entering history (source -h). 207659243Sobrien */ 2077167465Smp if ((hadhist && !seterr && intty && !tellwhat && !Expand && !whyles) || 2078231990Smp (!enterhist && adrof(STRverbose))) 2079231990Smp { 2080100616Smp int odidfds = didfds; 208159243Sobrien haderr = 1; 2082100616Smp didfds = 0; 208359243Sobrien prlex(¶ml); 2084100616Smp flush(); 208559243Sobrien haderr = 0; 2086100616Smp didfds = odidfds; 208759243Sobrien } 208859243Sobrien (void) alarm(0); /* Autologout OFF */ 2089167465Smp alrmcatch_disabled = 1; 209059243Sobrien 209159243Sobrien /* 209259243Sobrien * Save input text on the history list if reading in old history, or it 209359243Sobrien * is from the terminal at the top level and not in a loop. 209459243Sobrien * 209559243Sobrien * PWP: entry of items in the history list while in a while loop is done 209659243Sobrien * elsewhere... 209759243Sobrien */ 209859243Sobrien if (enterhist || (catch && intty && !whyles && !tellwhat && !arun)) 209959243Sobrien savehist(¶ml, enterhist > 1); 210059243Sobrien 210159243Sobrien if (Expand && seterr) 210259243Sobrien Expand = 0; 210359243Sobrien 210459243Sobrien /* 210559243Sobrien * Print lexical error messages, except when sourcing history lists. 210659243Sobrien */ 210759243Sobrien if (!enterhist && seterr) 210859243Sobrien stderror(ERR_OLD); 210959243Sobrien 211059243Sobrien /* 211159243Sobrien * If had a history command :p modifier then this is as far as we 211259243Sobrien * should go 211359243Sobrien */ 211459243Sobrien if (justpr) 2115167465Smp goto cmd_done; 211659243Sobrien 211759243Sobrien /* 211859243Sobrien * If had a tellwhat from twenex() then do 211959243Sobrien */ 212059243Sobrien if (tellwhat) { 212159243Sobrien (void) tellmewhat(¶ml, NULL); 2122167465Smp goto cmd_done; 212359243Sobrien } 212459243Sobrien 212559243Sobrien alias(¶ml); 212659243Sobrien 212759243Sobrien#ifdef BSDJOBS 212859243Sobrien /* 212959243Sobrien * If we are interactive, try to continue jobs that we have stopped 213059243Sobrien */ 213159243Sobrien if (prompt) 213259243Sobrien continue_jobs(¶ml); 213359243Sobrien#endif /* BSDJOBS */ 213459243Sobrien 213559243Sobrien /* 213659243Sobrien * Check to see if the user typed "rm * .o" or something 213759243Sobrien */ 213859243Sobrien if (prompt) 213959243Sobrien rmstar(¶ml); 214059243Sobrien /* 214159243Sobrien * Parse the words of the input into a parse tree. 214259243Sobrien */ 2143167465Smp t = syntax(paraml.next, ¶ml, 0); 2144231990Smp /* 2145231990Smp * We cannot cleanup push here, because cd /blah; echo foo 2146231990Smp * would rewind t on the chdir error, and free the rest of the command 2147231990Smp */ 2148231990Smp if (seterr) { 2149231990Smp freesyn(t); 215059243Sobrien stderror(ERR_OLD); 2151231990Smp } 215259243Sobrien 215359243Sobrien postcmd(); 215459243Sobrien /* 215559243Sobrien * Execute the parse tree From: Michael Schroeder 215659243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> was execute(t, tpgrp); 215759243Sobrien */ 2158167465Smp execute(t, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 2159231990Smp freesyn(t); 216059243Sobrien 216159243Sobrien /* 216259243Sobrien * Made it! 216359243Sobrien */ 216459243Sobrien#ifdef SIG_WINDOW 2165100616Smp if (windowchg || (catch && intty && !whyles && !tellwhat)) { 2166100616Smp (void) check_window_size(0); /* for window systems */ 2167100616Smp } 216859243Sobrien#endif /* SIG_WINDOW */ 2169167465Smp setcopy(STR_, InputBuf, VAR_READWRITE | VAR_NOGLOB); 2170167465Smp cmd_done: 2171231990Smp if (cleanup_reset()) 2172231990Smp cleanup_until(¶ml); 2173231990Smp else 2174231990Smp haderr = 1; 217559243Sobrien } 2176167465Smp cleanup_pop_mark(omark); 217759243Sobrien resexit(osetexit); 2178195609Smp exitset--; 2179231990Smp handle_pending_signals(); 218059243Sobrien} 218159243Sobrien 218259243Sobrien/*ARGSUSED*/ 218359243Sobrienvoid 2184167465Smpdosource(Char **t, struct command *c) 218559243Sobrien{ 2186145479Smp Char *f; 2187145479Smp int hflg = 0; 2188167465Smp char *file; 218959243Sobrien 219059243Sobrien USE(c); 219159243Sobrien t++; 219259243Sobrien if (*t && eq(*t, STRmh)) { 219359243Sobrien if (*++t == NULL) 219459243Sobrien stderror(ERR_NAME | ERR_HFLAG); 219559243Sobrien hflg++; 219659243Sobrien } 219759243Sobrien else if (*t && eq(*t, STRmm)) { 219859243Sobrien if (*++t == NULL) 219959243Sobrien stderror(ERR_NAME | ERR_MFLAG); 220059243Sobrien hflg = 2; 220159243Sobrien } 220259243Sobrien 220359243Sobrien f = globone(*t++, G_ERROR); 2204167465Smp file = strsave(short2str(f)); 2205167465Smp cleanup_push(file, xfree); 2206167465Smp xfree(f); 2207167465Smp t = glob_all_or_error(t); 2208316957Sdchagin cleanup_push(t, blk_cleanup); 2209167465Smp if ((!srcfile(file, 0, hflg, t)) && (!hflg) && (!bequiet)) 2210167465Smp stderror(ERR_SYSTEM, file, strerror(errno)); 2211167465Smp cleanup_until(file); 221259243Sobrien} 221359243Sobrien 221459243Sobrien/* 221559243Sobrien * Check for mail. 221659243Sobrien * If we are a login shell, then we don't want to tell 221759243Sobrien * about any mail file unless its been modified 221859243Sobrien * after the time we started. 221959243Sobrien * This prevents us from telling the user things he already 222059243Sobrien * knows, since the login program insists on saying 222159243Sobrien * "You have mail." 222259243Sobrien */ 222359243Sobrien 222459243Sobrien/* 222559243Sobrien * The AMS version. 222659243Sobrien * This version checks if the file is a directory, and if so, 222759243Sobrien * tells you the number of files in it, otherwise do the old thang. 222859243Sobrien * The magic "+1" in the time calculation is to compensate for 222959243Sobrien * an AFS bug where directory mtimes are set to 1 second in 223059243Sobrien * the future. 223159243Sobrien */ 223259243Sobrien 223359243Sobrienstatic void 2234167465Smpmailchk(void) 223559243Sobrien{ 2236145479Smp struct varent *v; 2237145479Smp Char **vp; 223859243Sobrien time_t t; 223959243Sobrien int intvl, cnt; 224059243Sobrien struct stat stb; 2241145479Smp int new; 224259243Sobrien 224359243Sobrien v = adrof(STRmail); 2244100616Smp if (v == NULL || v->vec == NULL) 224559243Sobrien return; 224659243Sobrien (void) time(&t); 224759243Sobrien vp = v->vec; 224859243Sobrien cnt = blklen(vp); 224959243Sobrien intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 225059243Sobrien if (intvl < 1) 225159243Sobrien intvl = 1; 225259243Sobrien if (chktim + intvl > t) 225359243Sobrien return; 225459243Sobrien for (; *vp; vp++) { 225559243Sobrien char *filename = short2str(*vp); 225659243Sobrien char *mboxdir = filename; 225759243Sobrien 225859243Sobrien if (stat(filename, &stb) < 0) 225959243Sobrien continue; 226059243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 226159243Sobrien new = stb.st_mtime > time0.tv_sec; 226259243Sobrien#else 226359415Sobrien new = stb.st_mtime > seconds0; 226459243Sobrien#endif 226559243Sobrien if (S_ISDIR(stb.st_mode)) { 226659243Sobrien DIR *mailbox; 226759243Sobrien int mailcount = 0; 2268167465Smp char *tempfilename; 226959243Sobrien struct stat stc; 227059243Sobrien 2271167465Smp tempfilename = xasprintf("%s/new", filename); 227259243Sobrien 227359243Sobrien if (stat(tempfilename, &stc) != -1 && S_ISDIR(stc.st_mode)) { 227459243Sobrien /* 227559243Sobrien * "filename/new" exists and is a directory; you are 227659243Sobrien * using Qmail. 227759243Sobrien */ 227859243Sobrien stb = stc; 227959243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 228059243Sobrien new = stb.st_mtime > time0.tv_sec; 228159243Sobrien#else 228259415Sobrien new = stb.st_mtime > seconds0; 228359243Sobrien#endif 228459243Sobrien mboxdir = tempfilename; 228559243Sobrien } 228659243Sobrien 2287167465Smp if (stb.st_mtime <= chktim + 1 || (loginsh && !new)) { 2288167465Smp xfree(tempfilename); 228959243Sobrien continue; 2290167465Smp } 229159243Sobrien 2292167465Smp mailbox = opendir(mboxdir); 2293167465Smp xfree(tempfilename); 2294167465Smp if (mailbox == NULL) 229559243Sobrien continue; 229659243Sobrien 229759243Sobrien /* skip . and .. */ 2298231990Smp if (!readdir(mailbox) || !readdir(mailbox)) { 2299231990Smp (void)closedir(mailbox); 230059243Sobrien continue; 2301231990Smp } 230259243Sobrien 230359243Sobrien while (readdir(mailbox)) 230459243Sobrien mailcount++; 230559243Sobrien 2306231990Smp (void)closedir(mailbox); 230759243Sobrien if (mailcount == 0) 230859243Sobrien continue; 230959243Sobrien 231059243Sobrien if (cnt == 1) 231159243Sobrien xprintf(CGETS(11, 3, "You have %d mail messages.\n"), 231259243Sobrien mailcount); 231359243Sobrien else 231459243Sobrien xprintf(CGETS(11, 4, "You have %d mail messages in %s.\n"), 231559243Sobrien mailcount, filename); 231659243Sobrien } 231759243Sobrien else { 2318145479Smp char *type; 2319145479Smp 2320231990Smp if (stb.st_size == 0 || stb.st_atime >= stb.st_mtime || 232159243Sobrien (stb.st_atime <= chktim && stb.st_mtime <= chktim) || 232259243Sobrien (loginsh && !new)) 232359243Sobrien continue; 2324145479Smp type = strsave(new ? CGETS(11, 6, "new ") : ""); 2325167465Smp cleanup_push(type, xfree); 232659243Sobrien if (cnt == 1) 2327145479Smp xprintf(CGETS(11, 5, "You have %smail.\n"), type); 232859243Sobrien else 2329145479Smp xprintf(CGETS(11, 7, "You have %smail in %s.\n"), type, filename); 2330167465Smp cleanup_until(type); 233159243Sobrien } 233259243Sobrien } 233359243Sobrien chktim = t; 233459243Sobrien} 233559243Sobrien 233659243Sobrien/* 233759243Sobrien * Extract a home directory from the password file 233859243Sobrien * The argument points to a buffer where the name of the 233959243Sobrien * user whose home directory is sought is currently. 2340167465Smp * We return home directory of the user, or NULL. 234159243Sobrien */ 2342167465SmpChar * 2343167465Smpgethdir(const Char *home) 234459243Sobrien{ 234559243Sobrien Char *h; 234659243Sobrien 234759243Sobrien /* 234859243Sobrien * Is it us? 234959243Sobrien */ 235059243Sobrien if (*home == '\0') { 2351167465Smp if ((h = varval(STRhome)) != STRNULL) 2352167465Smp return Strsave(h); 235359243Sobrien else 2354167465Smp return NULL; 235559243Sobrien } 235659243Sobrien 235759243Sobrien /* 235859243Sobrien * Look in the cache 235959243Sobrien */ 236059243Sobrien if ((h = gettilde(home)) == NULL) 2361167465Smp return NULL; 2362167465Smp else 2363167465Smp return Strsave(h); 236459243Sobrien} 236559243Sobrien 236659243Sobrien/* 236759243Sobrien * Move the initial descriptors to their eventual 236859243Sobrien * resting places, closing all other units. 236959243Sobrien */ 237059243Sobrienvoid 2371167465Smpinitdesc(void) 237259243Sobrien{ 237359243Sobrien#ifdef NLS_BUGS 237459243Sobrien#ifdef NLS_CATALOGS 2375145479Smp nlsclose(); 237659243Sobrien#endif /* NLS_CATALOGS */ 237759243Sobrien#endif /* NLS_BUGS */ 237859243Sobrien 237959243Sobrien 238059243Sobrien didfds = 0; /* 0, 1, 2 aren't set up */ 238159243Sobrien (void) close_on_exec(SHIN = dcopy(0, FSHIN), 1); 238259243Sobrien (void) close_on_exec(SHOUT = dcopy(1, FSHOUT), 1); 238359243Sobrien (void) close_on_exec(SHDIAG = dcopy(2, FSHDIAG), 1); 238459243Sobrien (void) close_on_exec(OLDSTD = dcopy(SHIN, FOLDSTD), 1); 238559243Sobrien#ifndef CLOSE_ON_EXEC 238659243Sobrien didcch = 0; /* Havent closed for child */ 238759243Sobrien#endif /* CLOSE_ON_EXEC */ 2388231990Smp if (SHDIAG >= 0) 2389231990Smp isdiagatty = isatty(SHDIAG); 2390231990Smp else 2391231990Smp isdiagatty = 0; 2392231990Smp if (SHDIAG >= 0) 2393231990Smp isoutatty = isatty(SHOUT); 2394231990Smp else 2395231990Smp isoutatty = 0; 239659243Sobrien#ifdef NLS_BUGS 239759243Sobrien#ifdef NLS_CATALOGS 239859243Sobrien nlsinit(); 239959243Sobrien#endif /* NLS_CATALOGS */ 240059243Sobrien#endif /* NLS_BUGS */ 240159243Sobrien} 240259243Sobrien 240359243Sobrien 240459243Sobrienvoid 240559243Sobrien#ifdef PROF 2406167465Smpdone(int i) 240759243Sobrien#else 2408167465Smpxexit(int i) 240959243Sobrien#endif 241059243Sobrien{ 241159243Sobrien#ifdef TESLA 241259243Sobrien if (loginsh && do_logout) { 241359243Sobrien /* this is to send hangup signal to the develcon */ 241459243Sobrien /* we toggle DTR. clear dtr - sleep 1 - set dtr */ 241559243Sobrien /* ioctl will return ENOTTY for pty's but we ignore it */ 241659243Sobrien /* exitstat will run after disconnect */ 241759243Sobrien /* we sleep for 2 seconds to let things happen in */ 241859243Sobrien /* .logout and rechist() */ 241959243Sobrien#ifdef TIOCCDTR 242059243Sobrien (void) sleep(2); 242159243Sobrien (void) ioctl(FSHTTY, TIOCCDTR, NULL); 242259243Sobrien (void) sleep(1); 242359243Sobrien (void) ioctl(FSHTTY, TIOCSDTR, NULL); 242459243Sobrien#endif /* TIOCCDTR */ 242559243Sobrien } 242659243Sobrien#endif /* TESLA */ 242759243Sobrien 242859243Sobrien { 242959243Sobrien struct process *pp, *np; 2430231990Smp pid_t mypid = getpid(); 243159243Sobrien /* Kill all processes marked for hup'ing */ 243259243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 243359243Sobrien np = pp; 2434231990Smp do 2435231990Smp if ((np->p_flags & PHUP) && np->p_jobid != shpgrp && 2436231990Smp np->p_parentid == mypid) { 243759243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 243859243Sobrien /* In case the job was suspended... */ 243959243Sobrien#ifdef SIGCONT 244059243Sobrien (void) killpg(np->p_jobid, SIGCONT); 244159243Sobrien#endif 244259243Sobrien break; 244359243Sobrien } 244459243Sobrien } 244559243Sobrien while ((np = np->p_friends) != pp); 244659243Sobrien } 244759243Sobrien } 244859243Sobrien untty(); 244959243Sobrien#ifdef NLS_CATALOGS 245059243Sobrien /* 245159243Sobrien * We need to call catclose, because SVR4 leaves symlinks behind otherwise 245259243Sobrien * in the catalog directories. We cannot close on a vforked() child, 245359243Sobrien * because messages will stop working on the parent too. 245459243Sobrien */ 245559243Sobrien if (child == 0) 2456145479Smp nlsclose(); 245759243Sobrien#endif /* NLS_CATALOGS */ 245869408Sache#ifdef WINNT_NATIVE 245959243Sobrien nt_cleanup(); 246069408Sache#endif /* WINNT_NATIVE */ 246159243Sobrien _exit(i); 246259243Sobrien} 246359243Sobrien 246459243Sobrien#ifndef _PATH_DEFPATH 246559243Sobrienstatic Char ** 2466167465Smpdefaultpath(void) 246759243Sobrien{ 246859243Sobrien char *ptr; 246959243Sobrien Char **blk, **blkp; 247059243Sobrien struct stat stb; 247159243Sobrien 2472167465Smp blkp = blk = xmalloc(sizeof(Char *) * 10); 247359243Sobrien 247459243Sobrien#ifndef NODOT 247559243Sobrien# ifndef DOTLAST 247659243Sobrien *blkp++ = Strsave(STRdot); 247759243Sobrien# endif 247859243Sobrien#endif 247959243Sobrien 248059243Sobrien#define DIRAPPEND(a) \ 248159243Sobrien if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \ 248259243Sobrien *blkp++ = SAVE(ptr) 248359243Sobrien 248459243Sobrien#ifdef _PATH_LOCAL 248559243Sobrien DIRAPPEND(_PATH_LOCAL); 248659243Sobrien#endif 248759243Sobrien 248859243Sobrien#ifdef _PATH_USRUCB 248959243Sobrien DIRAPPEND(_PATH_USRUCB); 249059243Sobrien#endif 249159243Sobrien 249259243Sobrien#ifdef _PATH_USRBSD 249359243Sobrien DIRAPPEND(_PATH_USRBSD); 249459243Sobrien#endif 249559243Sobrien 249659243Sobrien#ifdef _PATH_BIN 249759243Sobrien DIRAPPEND(_PATH_BIN); 249859243Sobrien#endif 249959243Sobrien 250059243Sobrien#ifdef _PATH_USRBIN 250159243Sobrien DIRAPPEND(_PATH_USRBIN); 250259243Sobrien#endif 250359243Sobrien 250459243Sobrien#undef DIRAPPEND 250559243Sobrien 250659243Sobrien#ifndef NODOT 250759243Sobrien# ifdef DOTLAST 250859243Sobrien *blkp++ = Strsave(STRdot); 250959243Sobrien# endif 251059243Sobrien#endif 251159243Sobrien *blkp = NULL; 251259243Sobrien return (blk); 251359243Sobrien} 251459243Sobrien#endif 251559243Sobrien 251659243Sobrienstatic void 2517167465Smprecord(void) 251859243Sobrien{ 251959243Sobrien if (!fast) { 252059243Sobrien recdirs(NULL, adrof(STRsavedirs) != NULL); 252159243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 252259243Sobrien } 2523231990Smp displayHistStats("Exiting"); /* no-op unless DEBUG_HIST */ 252459243Sobrien} 2525195609Smp 2526195609Smp/* 2527195609Smp * Grab the tty repeatedly, and give up if we are not in the correct 2528195609Smp * tty process group. 2529195609Smp */ 2530195609Smpint 2531195609Smpgrabpgrp(int fd, pid_t desired) 2532195609Smp{ 2533195609Smp struct sigaction old; 2534195609Smp pid_t pgrp; 2535195609Smp size_t i; 2536195609Smp 2537195609Smp for (i = 0; i < 100; i++) { 2538195609Smp if ((pgrp = tcgetpgrp(fd)) == -1) 2539195609Smp return -1; 2540195609Smp if (pgrp == desired) 2541195609Smp return 0; 2542195609Smp (void)sigaction(SIGTTIN, NULL, &old); 2543195609Smp (void)signal(SIGTTIN, SIG_DFL); 2544195609Smp (void)kill(0, SIGTTIN); 2545195609Smp (void)sigaction(SIGTTIN, &old, NULL); 2546195609Smp } 2547195609Smp errno = EPERM; 2548195609Smp return -1; 2549195609Smp} 2550