1316958Sdchagin/* $Header: /p/tcsh/cvsroot/tcsh/sh.c,v 3.189 2016/09/12 16:33:54 christos Exp $ */ 259243Sobrien/* 359243Sobrien * sh.c: Main shell routines 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#define EXTERN /* Intern */ 3459243Sobrien#include "sh.h" 3559243Sobrien 3659243Sobrien#ifndef lint 3759243Sobrienchar copyright[] = 3859243Sobrien"@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 3959243Sobrien All rights reserved.\n"; 4059243Sobrien#endif /* not lint */ 4159243Sobrien 42316958SdchaginRCSID("$tcsh: sh.c,v 3.189 2016/09/12 16:33:54 christos Exp $") 4359243Sobrien 4459243Sobrien#include "tc.h" 4559243Sobrien#include "ed.h" 4659243Sobrien#include "tw.h" 4759243Sobrien 48145479Smpextern int MapsAreInited; 49145479Smpextern int NLSMapsAreInited; 5059243Sobrien 5159243Sobrien/* 5259243Sobrien * C Shell 5359243Sobrien * 5459243Sobrien * Bill Joy, UC Berkeley, California, USA 5559243Sobrien * October 1978, May 1980 5659243Sobrien * 5759243Sobrien * Jim Kulp, IIASA, Laxenburg, Austria 5859243Sobrien * April 1980 5959243Sobrien * 6059243Sobrien * Filename recognition added: 6159243Sobrien * Ken Greer, Ind. Consultant, Palo Alto CA 6259243Sobrien * October 1983. 6359243Sobrien * 6459243Sobrien * Karl Kleinpaste, Computer Consoles, Inc. 6559243Sobrien * Added precmd, periodic/tperiod, prompt changes, 6659243Sobrien * directory stack hack, and login watch. 6759243Sobrien * Sometime March 1983 - Feb 1984. 6859243Sobrien * 6959243Sobrien * Added scheduled commands, including the "sched" command, 7059243Sobrien * plus the call to sched_run near the precmd et al 7159243Sobrien * routines. 7259243Sobrien * Upgraded scheduled events for running events while 7359243Sobrien * sitting idle at command input. 7459243Sobrien * 7559243Sobrien * Paul Placeway, Ohio State 7659243Sobrien * added stuff for running with twenex/inputl 9 Oct 1984. 7759243Sobrien * 7859243Sobrien * ported to Apple Unix (TM) (OREO) 26 -- 29 Jun 1987 7959243Sobrien */ 8059243Sobrien 81316958Sdchaginjmp_buf_t reslab IZERO_STRUCT; 82316958Sdchaginstruct wordent paraml IZERO_STRUCT; 8359243Sobrien 8459243Sobrienstatic const char tcshstr[] = "tcsh"; 8559243Sobrien 86167465Smpstruct sigaction parintr; /* Parents interrupt catch */ 87167465Smpstruct sigaction parterm; /* Parents terminate catch */ 8859243Sobrien 8959243Sobrien#ifdef TESLA 9059243Sobrienint do_logout = 0; 9159243Sobrien#endif /* TESLA */ 9259243Sobrien 9359243Sobrien 94145479Smpint use_fork = 0; /* use fork() instead of vfork()? */ 9559243Sobrien 9659243Sobrien/* 9759243Sobrien * Magic pointer values. Used to specify other invalid conditions aside 9859243Sobrien * from null. 9959243Sobrien */ 10059243Sobrienstatic Char INVCHAR; 10159243SobrienChar *INVPTR = &INVCHAR; 10259243SobrienChar **INVPPTR = &INVPTR; 10359243Sobrien 104167465Smpstatic int fast = 0; 105145479Smpstatic int mflag = 0; 106145479Smpstatic int prompt = 1; 107145479Smpint enterhist = 0; 108145479Smpint tellwhat = 0; 10959243Sobrientime_t t_period; 11059243SobrienChar *ffile = NULL; 111145479Smpint dolzero = 0; 11259243Sobrienint insource = 0; 11369408Sacheint exitset = 0; 11459243Sobrienstatic time_t chktim; /* Time mail last checked */ 11559243Sobrienchar *progname; 11659243Sobrienint tcsh; 11759243Sobrien 11859243Sobrien/* 11959243Sobrien * This preserves the input state of the shell. It is used by 12059243Sobrien * st_save and st_restore to manupulate shell state. 12159243Sobrien */ 12259243Sobrienstruct saved_state { 12359243Sobrien int insource; 124100616Smp int OLDSTD; 12559243Sobrien int SHIN; 126100616Smp int SHOUT; 127100616Smp int SHDIAG; 12859243Sobrien int intty; 12959243Sobrien struct whyle *whyles; 13059243Sobrien Char *gointr; 13159243Sobrien Char *arginp; 13259243Sobrien Char *evalp; 13359243Sobrien Char **evalvec; 13459243Sobrien Char *alvecp; 13559243Sobrien Char **alvec; 13659243Sobrien int onelflg; 137145479Smp int enterhist; 13859243Sobrien Char **argv; 139167465Smp Char **av; 14059243Sobrien Char HIST; 141145479Smp int cantell; 14259243Sobrien struct Bin B; 143195609Smp int justpr; 14459243Sobrien}; 14559243Sobrien 146167465Smpstatic int srccat (Char *, Char *); 14783098Smp#ifndef WINNT_NATIVE 148167465Smpstatic int srcfile (const char *, int, int, Char **); 14983098Smp#else 150167465Smpint srcfile (const char *, int, int, Char **); 15183098Smp#endif /*WINNT_NATIVE*/ 152167465Smpstatic void srcunit (int, int, int, Char **); 153167465Smpstatic void mailchk (void); 15459243Sobrien#ifndef _PATH_DEFPATH 155167465Smpstatic Char **defaultpath (void); 15659243Sobrien#endif 157167465Smpstatic void record (void); 158167465Smpstatic void st_save (struct saved_state *, int, int, 159167465Smp Char **, Char **); 160167465Smpstatic void st_restore (void *); 16159243Sobrien 162167465Smp int main (int, char **); 16359243Sobrien 164231990Smp#ifndef LOCALEDIR 165231990Smp#define LOCALEDIR "/usr/share/locale" 166231990Smp#endif 167231990Smp 168231990Smp#ifdef NLS_CATALOGS 169231990Smpstatic void 170231990Smpadd_localedir_to_nlspath(const char *path) 171231990Smp{ 172231990Smp static const char msgs_LOC[] = "/%L/LC_MESSAGES/%N.cat"; 173231990Smp static const char msgs_lang[] = "/%l/LC_MESSAGES/%N.cat"; 174231990Smp char *old; 175231990Smp char *new, *new_p; 176231990Smp size_t len; 177231990Smp int add_LOC = 1; 178231990Smp int add_lang = 1; 179231990Smp char trypath[MAXPATHLEN]; 180231990Smp struct stat st; 181231990Smp 182231990Smp if (path == NULL) 183231990Smp return; 184231990Smp 185231990Smp (void) xsnprintf(trypath, sizeof(trypath), "%s/en/LC_MESSAGES/tcsh.cat", 186231990Smp path); 187231990Smp if (stat(trypath, &st) == -1) 188231990Smp return; 189231990Smp 190231990Smp if ((old = getenv("NLSPATH")) != NULL) 191231990Smp len = strlen(old) + 1; /* don't forget the colon. */ 192231990Smp else 193231990Smp len = 0; 194231990Smp 195231990Smp len += 2 * strlen(path) + 196231990Smp sizeof(msgs_LOC) + sizeof(msgs_lang); /* includes the extra colon */ 197231990Smp 198231990Smp new = new_p = xcalloc(len, 1); 199231990Smp 200231990Smp if (old != NULL) { 201231990Smp size_t pathlen = strlen(path); 202231990Smp char *old_p; 203231990Smp 204231990Smp (void) xsnprintf(new_p, len, "%s", old); 205231990Smp new_p += strlen(new_p); 206231990Smp len -= new_p - new; 207231990Smp 208231990Smp /* Check if the paths we try to add are already present in NLSPATH. 209231990Smp If so, note it by setting the appropriate flag to 0. */ 210231990Smp for (old_p = old; old_p; old_p = strchr(old_p, ':'), 211231990Smp old_p = old_p ? old_p + 1 : NULL) { 212231990Smp if (strncmp(old_p, path, pathlen) != 0) 213231990Smp continue; 214231990Smp if (strncmp(old_p + pathlen, msgs_LOC, sizeof(msgs_LOC) - 1) == 0) 215231990Smp add_LOC = 0; 216231990Smp else if (strncmp(old_p + pathlen, msgs_lang, 217231990Smp sizeof(msgs_lang) - 1) == 0) 218231990Smp add_lang = 0; 219231990Smp } 220231990Smp } 221231990Smp 222231990Smp /* Add the message catalog paths not already present to NLSPATH. */ 223231990Smp if (add_LOC || add_lang) 224231990Smp (void) xsnprintf(new_p, len, "%s%s%s%s%s%s", 225231990Smp old ? ":" : "", 226231990Smp add_LOC ? path : "", add_LOC ? msgs_LOC : "", 227231990Smp add_LOC && add_lang ? ":" : "", 228231990Smp add_lang ? path : "", add_lang ? msgs_lang : ""); 229231990Smp 230231990Smp tsetenv(STRNLSPATH, str2short(new)); 231231990Smp free(new); 232231990Smp} 233231990Smp#endif 234231990Smp 23559243Sobrienint 236167465Smpmain(int argc, char **argv) 23759243Sobrien{ 238167465Smp int batch = 0; 239167465Smp volatile int nexececho = 0; 240167465Smp int nofile = 0; 241167465Smp volatile int nverbose = 0; 242167465Smp volatile int rdirs = 0; 243167465Smp int quitit = 0; 244145479Smp Char *cp; 24559243Sobrien#ifdef AUTOLOGOUT 246145479Smp Char *cp2; 24759243Sobrien#endif 248145479Smp char *tcp, *ttyn; 249167465Smp int f, reenter; 250145479Smp char **tempv; 251316958Sdchagin const char *targinp = NULL; 252131962Smp int osetintr; 253167465Smp struct sigaction oparintr; 25459243Sobrien 25569408Sache#ifdef WINNT_NATIVE 25659243Sobrien nt_init(); 25769408Sache#endif /* WINNT_NATIVE */ 258316958Sdchagin 259316958Sdchagin (void)memset(&reslab, 0, sizeof(reslab)); 26059243Sobrien#if defined(NLS_CATALOGS) && defined(LC_MESSAGES) 26159243Sobrien (void) setlocale(LC_MESSAGES, ""); 26259243Sobrien#endif /* NLS_CATALOGS && LC_MESSAGES */ 26359243Sobrien 26459243Sobrien#ifdef NLS 26559243Sobrien# ifdef LC_CTYPE 26659243Sobrien (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 26759243Sobrien# endif /* LC_CTYPE */ 26859243Sobrien#endif /* NLS */ 26959243Sobrien 270231990Smp STR_environ = blk2short(environ); 271231990Smp environ = short2blk(STR_environ); /* So that we can free it */ 272231990Smp 273231990Smp#ifdef NLS_CATALOGS 274231990Smp add_localedir_to_nlspath(LOCALEDIR); 275231990Smp#endif 276231990Smp 27759243Sobrien nlsinit(); 278316958Sdchagin initlex(¶ml); 27959243Sobrien 28059243Sobrien#ifdef MALLOC_TRACE 281167465Smp mal_setstatsfile(fdopen(dmove(xopen("/tmp/tcsh.trace", 282145479Smp O_WRONLY|O_CREAT|O_LARGEFILE, 0666), 25), "w")); 283145479Smp mal_trace(1); 28459243Sobrien#endif /* MALLOC_TRACE */ 28559243Sobrien 28659243Sobrien#if !(defined(BSDTIMES) || defined(_SEQUENT_)) && defined(POSIX) 28759243Sobrien# ifdef _SC_CLK_TCK 28859243Sobrien clk_tck = (clock_t) sysconf(_SC_CLK_TCK); 28959243Sobrien# else /* ! _SC_CLK_TCK */ 29059243Sobrien# ifdef CLK_TCK 29159243Sobrien clk_tck = CLK_TCK; 29259243Sobrien# else /* !CLK_TCK */ 29359243Sobrien clk_tck = HZ; 29459243Sobrien# endif /* CLK_TCK */ 29559243Sobrien# endif /* _SC_CLK_TCK */ 29659243Sobrien#endif /* !BSDTIMES && POSIX */ 29759243Sobrien 29859243Sobrien settimes(); /* Immed. estab. timing base */ 29959243Sobrien#ifdef TESLA 30059243Sobrien do_logout = 0; 30159243Sobrien#endif /* TESLA */ 30259243Sobrien 30359243Sobrien /* 30459243Sobrien * Make sure we have 0, 1, 2 open 30559243Sobrien * Otherwise `` jobs will not work... (From knaff@poly.polytechnique.fr) 30659243Sobrien */ 30759243Sobrien { 30859243Sobrien do 309167465Smp if ((f = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE)) == -1 && 310167465Smp (f = xopen("/", O_RDONLY|O_LARGEFILE)) == -1) 31159243Sobrien exit(1); 31259243Sobrien while (f < 3); 313167465Smp xclose(f); 31459243Sobrien } 31559243Sobrien 31659243Sobrien osinit(); /* Os dependent initialization */ 31759243Sobrien 31859243Sobrien 31959243Sobrien { 32059243Sobrien char *t; 32159243Sobrien 32259243Sobrien t = strrchr(argv[0], '/'); 32369408Sache#ifdef WINNT_NATIVE 32459243Sobrien { 32559243Sobrien char *s = strrchr(argv[0], '\\'); 32659243Sobrien if (s) 32759243Sobrien t = s; 32859243Sobrien } 32969408Sache#endif /* WINNT_NATIVE */ 33059243Sobrien t = t ? t + 1 : argv[0]; 33159243Sobrien if (*t == '-') t++; 33259243Sobrien progname = strsave((t && *t) ? t : tcshstr); /* never want a null */ 333231990Smp tcsh = strncmp(progname, tcshstr, sizeof(tcshstr) - 1) == 0; 33459243Sobrien } 33559243Sobrien 33659243Sobrien /* 33759243Sobrien * Initialize non constant strings 33859243Sobrien */ 33959243Sobrien#ifdef _PATH_BSHELL 34059243Sobrien STR_BSHELL = SAVE(_PATH_BSHELL); 34159243Sobrien#endif 34259243Sobrien#ifdef _PATH_TCSHELL 34359243Sobrien STR_SHELLPATH = SAVE(_PATH_TCSHELL); 34459243Sobrien#else 34559243Sobrien# ifdef _PATH_CSHELL 34659243Sobrien STR_SHELLPATH = SAVE(_PATH_CSHELL); 34759243Sobrien# endif 34859243Sobrien#endif 34959243Sobrien STR_WORD_CHARS = SAVE(WORD_CHARS); 350316958Sdchagin STR_WORD_CHARS_VI = SAVE(WORD_CHARS_VI); 35159243Sobrien 35259243Sobrien HIST = '!'; 35359243Sobrien HISTSUB = '^'; 354231990Smp PRCH = tcsh ? '>' : '%'; /* to replace %# in $prompt for normal users */ 355231990Smp PRCHROOT = '#'; /* likewise for root */ 35659243Sobrien word_chars = STR_WORD_CHARS; 35759243Sobrien bslash_quote = 0; /* PWP: do tcsh-style backslash quoting? */ 358231990Smp anyerror = 1; /* for compatibility */ 359231990Smp setcopy(STRanyerror, STRNULL, VAR_READWRITE); 36059243Sobrien 36159243Sobrien /* Default history size to 100 */ 362167465Smp setcopy(STRhistory, str2short("100"), VAR_READWRITE); 363316958Sdchagin sethistory(100); 36459243Sobrien 36559243Sobrien tempv = argv; 36659243Sobrien ffile = SAVE(tempv[0]); 36759243Sobrien dolzero = 0; 36859243Sobrien if (eq(ffile, STRaout)) /* A.out's are quittable */ 36959243Sobrien quitit = 1; 37059243Sobrien uid = getuid(); 37159243Sobrien gid = getgid(); 37259243Sobrien euid = geteuid(); 37359243Sobrien egid = getegid(); 37459243Sobrien /* 37559243Sobrien * We are a login shell if: 1. we were invoked as -<something> with 37659243Sobrien * optional arguments 2. or we were invoked only with the -l flag 37759243Sobrien */ 37859243Sobrien loginsh = (**tempv == '-') || (argc == 2 && 37959243Sobrien tempv[1][0] == '-' && tempv[1][1] == 'l' && 38059243Sobrien tempv[1][2] == '\0'); 38159243Sobrien#ifdef _VMS_POSIX 38259243Sobrien /* No better way to find if we are a login shell */ 38359243Sobrien if (!loginsh) { 38459243Sobrien loginsh = (argc == 1 && getppid() == 1); 38559243Sobrien **tempv = '-'; /* Avoid giving VMS an acidic stomach */ 38659243Sobrien } 38759243Sobrien#endif /* _VMS_POSIX */ 38859243Sobrien 38959243Sobrien if (loginsh && **tempv != '-') { 390167465Smp char *argv0; 391167465Smp 39259243Sobrien /* 39359243Sobrien * Mangle the argv space 39459243Sobrien */ 39559243Sobrien tempv[1][0] = '\0'; 39659243Sobrien tempv[1][1] = '\0'; 39759243Sobrien tempv[1] = NULL; 398167465Smp argv0 = strspl("-", *tempv); 399167465Smp *tempv = argv0; 40059243Sobrien argc--; 40159243Sobrien } 40259243Sobrien if (loginsh) { 40359243Sobrien (void) time(&chktim); 404167465Smp setNS(STRloginsh); 40559243Sobrien } 40659243Sobrien 40759243Sobrien NoNLSRebind = getenv("NOREBIND") != NULL; 40859243Sobrien#ifdef NLS 40959243Sobrien# ifdef SETLOCALEBUG 41059243Sobrien dont_free = 1; 41159243Sobrien# endif /* SETLOCALEBUG */ 41259243Sobrien (void) setlocale(LC_ALL, ""); 41359243Sobrien# ifdef LC_COLLATE 41459243Sobrien (void) setlocale(LC_COLLATE, ""); 41559243Sobrien# endif 41659243Sobrien# ifdef SETLOCALEBUG 41759243Sobrien dont_free = 0; 41859243Sobrien# endif /* SETLOCALEBUG */ 41959243Sobrien# ifdef STRCOLLBUG 42059243Sobrien fix_strcoll_bug(); 42159243Sobrien# endif /* STRCOLLBUG */ 42259243Sobrien 423231990Smp /* 424231990Smp * On solaris ISO8859-1 contains no printable characters in the upper half 425231990Smp * so we need to test only for MB_CUR_MAX == 1, otherwise for multi-byte 426231990Smp * locales we are always AsciiOnly == 0. 427231990Smp */ 428231990Smp if (MB_CUR_MAX == 1) { 42959243Sobrien int k; 43059243Sobrien 431231990Smp for (k = 0200; k <= 0377 && !isprint(CTL_ESC(k)); k++) 43259243Sobrien continue; 433231990Smp AsciiOnly = k > 0377; 434231990Smp } else 435231990Smp AsciiOnly = 0; 43659243Sobrien#else 43759243Sobrien AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL; 43859243Sobrien#endif /* NLS */ 43959243Sobrien if (MapsAreInited && !NLSMapsAreInited) 44059243Sobrien ed_InitNLSMaps(); 44159243Sobrien ResetArrowKeys(); 44259243Sobrien 44359243Sobrien /* 44459243Sobrien * Initialize for periodic command intervals. Also, initialize the dummy 44559243Sobrien * tty list for login-watch. 44659243Sobrien */ 44759243Sobrien (void) time(&t_period); 44859243Sobrien#ifndef HAVENOUTMP 44959243Sobrien initwatch(); 45059243Sobrien#endif /* !HAVENOUTMP */ 45159243Sobrien 45259243Sobrien#if defined(alliant) 45359243Sobrien /* 45459243Sobrien * From: Jim Pace <jdp@research.att.com> 45559243Sobrien * tcsh does not work properly on the alliants through an rlogin session. 45659243Sobrien * The shell generally hangs. Also, reference to the controlling terminal 45759243Sobrien * does not work ( ie: echo foo > /dev/tty ). 45859243Sobrien * 45959243Sobrien * A security feature was added to rlogind affecting FX/80's Concentrix 46059243Sobrien * from revision 5.5.xx upwards (through 5.7 where this fix was implemented) 46159243Sobrien * This security change also affects the FX/2800 series. 46259243Sobrien * The security change to rlogind requires the process group of an rlogin 46359243Sobrien * session become disassociated with the tty in rlogind. 46459243Sobrien * 46559243Sobrien * The changes needed are: 46659243Sobrien * 1. set the process group 46759243Sobrien * 2. reenable the control terminal 46859243Sobrien */ 46959243Sobrien if (loginsh && isatty(SHIN)) { 470167465Smp ttyn = ttyname(SHIN); 471167465Smp xclose(SHIN); 472167465Smp SHIN = xopen(ttyn, O_RDWR|O_LARGEFILE); 47359243Sobrien shpgrp = getpid(); 47459243Sobrien (void) ioctl (SHIN, TIOCSPGRP, (ioctl_t) &shpgrp); 47559243Sobrien (void) setpgid(0, shpgrp); 47659243Sobrien } 47759243Sobrien#endif /* alliant */ 47859243Sobrien 47959243Sobrien /* 48059243Sobrien * Move the descriptors to safe places. The variable didfds is 0 while we 48159243Sobrien * have only FSH* to work with. When didfds is true, we have 0,1,2 and 48259243Sobrien * prefer to use these. 48359243Sobrien */ 48459243Sobrien initdesc(); 48559243Sobrien 486316958Sdchagin cdtohome = 1; 487316958Sdchagin setv(STRcdtohome, SAVE(""), VAR_READWRITE); 488316958Sdchagin 48959243Sobrien /* 49059243Sobrien * Get and set the tty now 49159243Sobrien */ 49259243Sobrien if ((ttyn = ttyname(SHIN)) != NULL) { 49359243Sobrien /* 49459243Sobrien * Could use rindex to get rid of other possible path components, but 49559243Sobrien * hpux preserves the subdirectory /pty/ when storing the tty name in 49659243Sobrien * utmp, so we keep it too. 49759243Sobrien */ 49859243Sobrien if (strncmp(ttyn, "/dev/", 5) == 0) 499167465Smp setv(STRtty, cp = SAVE(ttyn + 5), VAR_READWRITE); 50059243Sobrien else 501167465Smp setv(STRtty, cp = SAVE(ttyn), VAR_READWRITE); 50259243Sobrien } 50359243Sobrien else 504167465Smp setv(STRtty, cp = SAVE(""), VAR_READWRITE); 505316958Sdchagin 50659243Sobrien /* 50759243Sobrien * Initialize the shell variables. ARGV and PROMPT are initialized later. 50859243Sobrien * STATUS is also munged in several places. CHILD is munged when 50959243Sobrien * forking/waiting 51059243Sobrien */ 51159243Sobrien 51259243Sobrien /* 51359243Sobrien * 7-10-87 Paul Placeway autologout should be set ONLY on login shells and 51459243Sobrien * on shells running as root. Out of these, autologout should NOT be set 51559243Sobrien * for any psudo-terminals (this catches most window systems) and not for 51659243Sobrien * any terminal running X windows. 51759243Sobrien * 51859243Sobrien * At Ohio State, we have had problems with a user having his X session 51959243Sobrien * drop out from under him (on a Sun) because the shell in his master 52059243Sobrien * xterm timed out and exited. 52159243Sobrien * 52259243Sobrien * Really, this should be done with a program external to the shell, that 52359243Sobrien * watches for no activity (and NO running programs, such as dump) on a 52459243Sobrien * terminal for a long peroid of time, and then SIGHUPS the shell on that 52559243Sobrien * terminal. 52659243Sobrien * 52759243Sobrien * bugfix by Rich Salz <rsalz@PINEAPPLE.BBN.COM>: For root rsh things 52859243Sobrien * allways first check to see if loginsh or really root, then do things 52959243Sobrien * with ttyname() 53059243Sobrien * 53159243Sobrien * Also by Jean-Francois Lamy <lamy%ai.toronto.edu@RELAY.CS.NET>: check the 53259243Sobrien * value of cp before using it! ("root can rsh too") 53359243Sobrien * 53459243Sobrien * PWP: keep the nested ifs; the order of the tests matters and a good 53559243Sobrien * (smart) C compiler might re-arange things wrong. 53659243Sobrien */ 53759243Sobrien#ifdef AUTOLOGOUT 53859243Sobrien# ifdef convex 539167465Smp if (uid == 0) 54059243Sobrien /* root always has a 15 minute autologout */ 541167465Smp setcopy(STRautologout, STRrootdefautologout, VAR_READWRITE); 54259243Sobrien else 54359243Sobrien if (loginsh) 54459243Sobrien /* users get autologout set to 0 */ 545167465Smp setcopy(STRautologout, STR0, VAR_READWRITE); 54659243Sobrien# else /* convex */ 54759243Sobrien if (loginsh || (uid == 0)) { 54859243Sobrien if (*cp) { 54959243Sobrien /* only for login shells or root and we must have a tty */ 550231990Smp if (((cp2 = Strrchr(cp, (Char) '/')) != NULL) && 551231990Smp (Strncmp(cp, STRptssl, 3) != 0)) { 552172665Smp cp2 = cp2 + 1; 55359243Sobrien } 55459243Sobrien else 55559243Sobrien cp2 = cp; 55659243Sobrien if (!(((Strncmp(cp2, STRtty, 3) == 0) && Isalpha(cp2[3])) || 557184072Sru Strstr(cp, STRptssl) != NULL)) { 55859243Sobrien if (getenv("DISPLAY") == NULL) { 55959243Sobrien /* NOT on X window shells */ 560167465Smp setcopy(STRautologout, STRdefautologout, VAR_READWRITE); 56159243Sobrien } 56259243Sobrien } 56359243Sobrien } 56459243Sobrien } 56559243Sobrien# endif /* convex */ 56659243Sobrien#endif /* AUTOLOGOUT */ 56759243Sobrien 568167465Smp sigset_interrupting(SIGALRM, queue_alrmcatch); 56959243Sobrien 570167465Smp setcopy(STRstatus, STR0, VAR_READWRITE); 57159243Sobrien 57259243Sobrien /* 573100616Smp * get and set machine specific environment variables 57459243Sobrien */ 57559243Sobrien getmachine(); 57659243Sobrien 57759243Sobrien 57859243Sobrien /* 57959243Sobrien * Publish the selected echo style 58059243Sobrien */ 581100616Smp#if ECHO_STYLE != BSD_ECHO 582100616Smp if (tcsh) { 583100616Smp# if ECHO_STYLE == NONE_ECHO 584167465Smp setcopy(STRecho_style, STRnone, VAR_READWRITE); 585100616Smp# endif /* ECHO_STYLE == NONE_ECHO */ 586100616Smp# if ECHO_STYLE == SYSV_ECHO 587167465Smp setcopy(STRecho_style, STRsysv, VAR_READWRITE); 588100616Smp# endif /* ECHO_STYLE == SYSV_ECHO */ 589100616Smp# if ECHO_STYLE == BOTH_ECHO 590167465Smp setcopy(STRecho_style, STRboth, VAR_READWRITE); 591100616Smp# endif /* ECHO_STYLE == BOTH_ECHO */ 592100616Smp } else 593100616Smp#endif /* ECHO_STYLE != BSD_ECHO */ 594167465Smp setcopy(STRecho_style, STRbsd, VAR_READWRITE); 59559243Sobrien 59659243Sobrien /* 59759243Sobrien * increment the shell level. 59859243Sobrien */ 59959243Sobrien shlvl(1); 60059243Sobrien 601231990Smp#ifdef __ANDROID__ 602316958Sdchagin /* On Android, $HOME either isn't set or set to /data, a R/O location. 603316958Sdchagin Check for the environment variable EXTERNAL_STORAGE, which contains 604316958Sdchagin the mount point of the external storage (SD card, mostly). If 605316958Sdchagin EXTERNAL_STORAGE isn't set fall back to "/sdcard". Eventually 606316958Sdchagin override $HOME so the environment is on the same page. */ 607316958Sdchagin if (((tcp = getenv("HOME")) != NULL && strcmp (tcp, "/data") != 0) 608316958Sdchagin || (tcp = getenv("EXTERNAL_STORAGE")) != NULL) { 609231990Smp cp = quote(SAVE(tcp)); 610316958Sdchagin } else 611231990Smp cp = quote(SAVE("/sdcard")); 612316958Sdchagin tsetenv(STRKHOME, cp); 613231990Smp#else 614316958Sdchagin if ((tcp = getenv("HOME")) != NULL) 615316958Sdchagin cp = quote(SAVE(tcp)); 616316958Sdchagin else 61759243Sobrien cp = NULL; 618231990Smp#endif 61973393Skris 62059243Sobrien if (cp == NULL) 62159243Sobrien fast = 1; /* No home -> can't read scripts */ 62259243Sobrien else 623167465Smp setv(STRhome, cp, VAR_READWRITE); 62473393Skris 62559243Sobrien dinit(cp); /* dinit thinks that HOME == cwd in a login 62659243Sobrien * shell */ 62759243Sobrien /* 62859243Sobrien * Grab other useful things from the environment. Should we grab 62959243Sobrien * everything?? 63059243Sobrien */ 63159243Sobrien { 63259243Sobrien char *cln, *cus, *cgr; 63359243Sobrien struct passwd *pw; 63459243Sobrien struct group *gr; 63559243Sobrien 63659243Sobrien 63759243Sobrien#ifdef apollo 63859243Sobrien int oid = getoid(); 63959243Sobrien 640167465Smp setv(STRoid, Itoa(oid, 0, 0), VAR_READWRITE); 64159243Sobrien#endif /* apollo */ 64259243Sobrien 643231990Smp setv(STReuid, Itoa(euid, 0, 0), VAR_READWRITE); 644231990Smp if ((pw = xgetpwuid(euid)) == NULL) 645231990Smp setcopy(STReuser, STRunknown, VAR_READWRITE); 646231990Smp else 647231990Smp setcopy(STReuser, str2short(pw->pw_name), VAR_READWRITE); 648231990Smp 649167465Smp setv(STRuid, Itoa(uid, 0, 0), VAR_READWRITE); 65059243Sobrien 651167465Smp setv(STRgid, Itoa(gid, 0, 0), VAR_READWRITE); 65259243Sobrien 65359243Sobrien cln = getenv("LOGNAME"); 65459243Sobrien cus = getenv("USER"); 65559243Sobrien if (cus != NULL) 656167465Smp setv(STRuser, quote(SAVE(cus)), VAR_READWRITE); 65759243Sobrien else if (cln != NULL) 658167465Smp setv(STRuser, quote(SAVE(cln)), VAR_READWRITE); 659167465Smp else if ((pw = xgetpwuid(uid)) == NULL) 660231990Smp setcopy(STRuser, STRunknown, VAR_READWRITE); 66159243Sobrien else 662167465Smp setcopy(STRuser, str2short(pw->pw_name), VAR_READWRITE); 66359243Sobrien if (cln == NULL) 66459243Sobrien tsetenv(STRLOGNAME, varval(STRuser)); 66559243Sobrien if (cus == NULL) 66659243Sobrien tsetenv(STRKUSER, varval(STRuser)); 66759243Sobrien 66859243Sobrien cgr = getenv("GROUP"); 66959243Sobrien if (cgr != NULL) 670167465Smp setv(STRgroup, quote(SAVE(cgr)), VAR_READWRITE); 671167465Smp else if ((gr = xgetgrgid(gid)) == NULL) 672231990Smp setcopy(STRgroup, STRunknown, VAR_READWRITE); 67359243Sobrien else 674167465Smp setcopy(STRgroup, str2short(gr->gr_name), VAR_READWRITE); 67559243Sobrien if (cgr == NULL) 67659243Sobrien tsetenv(STRKGROUP, varval(STRgroup)); 67759243Sobrien } 67859243Sobrien 67959243Sobrien /* 68059243Sobrien * HOST may be wrong, since rexd transports the entire environment on sun 68159243Sobrien * 3.x Just set it again 68259243Sobrien */ 68359243Sobrien { 68459243Sobrien char cbuff[MAXHOSTNAMELEN]; 68559243Sobrien 68659243Sobrien if (gethostname(cbuff, sizeof(cbuff)) >= 0) { 68759243Sobrien cbuff[sizeof(cbuff) - 1] = '\0'; /* just in case */ 68859243Sobrien tsetenv(STRHOST, str2short(cbuff)); 68959243Sobrien } 69059243Sobrien else 691231990Smp tsetenv(STRHOST, STRunknown); 69259243Sobrien } 69359243Sobrien 69459243Sobrien 69559243Sobrien#ifdef REMOTEHOST 69659243Sobrien /* 69759243Sobrien * Try to determine the remote host we were logged in from. 69859243Sobrien */ 69959243Sobrien remotehost(); 70059243Sobrien#endif /* REMOTEHOST */ 70159243Sobrien 70259243Sobrien#ifdef apollo 70359243Sobrien if ((tcp = getenv("SYSTYPE")) == NULL) 70459243Sobrien tcp = "bsd4.3"; 70559243Sobrien tsetenv(STRSYSTYPE, quote(str2short(tcp))); 70659243Sobrien#endif /* apollo */ 70759243Sobrien 70859243Sobrien /* 70959243Sobrien * set editing on by default, unless running under Emacs as an inferior 71059243Sobrien * shell. 71159243Sobrien * We try to do this intelligently. If $TERM is available, then it 71259243Sobrien * should determine if we should edit or not. $TERM is preserved 71359243Sobrien * across rlogin sessions, so we will not get confused if we rlogin 71459243Sobrien * under an emacs shell. Another advantage is that if we run an 71559243Sobrien * xterm under an emacs shell, then the $TERM will be set to 71659243Sobrien * xterm, so we are going to want to edit. Unfortunately emacs 71759243Sobrien * does not restore all the tty modes, so xterm is not very well 71859243Sobrien * set up. But this is not the shell's fault. 71959243Sobrien * Also don't edit if $TERM == wm, for when we're running under an ATK app. 72059243Sobrien * Finally, emacs compiled under terminfo, sets the terminal to dumb, 72159243Sobrien * so disable editing for that too. 72259243Sobrien * 72359243Sobrien * Unfortunately, in some cases the initial $TERM setting is "unknown", 72459243Sobrien * "dumb", or "network" which is then changed in the user's startup files. 72559243Sobrien * We fix this by setting noediting here if $TERM is unknown/dumb and 72659243Sobrien * if noediting is set, we switch on editing if $TERM is changed. 72759243Sobrien */ 72859243Sobrien if ((tcp = getenv("TERM")) != NULL) { 729167465Smp setv(STRterm, quote(SAVE(tcp)), VAR_READWRITE); 73059243Sobrien noediting = strcmp(tcp, "unknown") == 0 || strcmp(tcp, "dumb") == 0 || 73159243Sobrien strcmp(tcp, "network") == 0; 73259243Sobrien editing = strcmp(tcp, "emacs") != 0 && strcmp(tcp, "wm") != 0 && 73359243Sobrien !noediting; 73459243Sobrien } 73559243Sobrien else { 73659243Sobrien noediting = 0; 73759243Sobrien editing = ((tcp = getenv("EMACS")) == NULL || strcmp(tcp, "t") != 0); 73859243Sobrien } 73959243Sobrien 74059243Sobrien /* 74159243Sobrien * The 'edit' variable is either set or unset. It doesn't 74259243Sobrien * need a value. Making it 'emacs' might be confusing. 74359243Sobrien */ 74459243Sobrien if (editing) 745167465Smp setNS(STRedit); 74659243Sobrien 74759243Sobrien 74859243Sobrien /* 74959243Sobrien * still more mutability: make the complete routine automatically add the 75059243Sobrien * suffix of file names... 75159243Sobrien */ 752167465Smp setNS(STRaddsuffix); 75359243Sobrien 75459243Sobrien /* 755145479Smp * Compatibility with tcsh >= 6.12 by default 756145479Smp */ 757167465Smp setNS(STRcsubstnonl); 758145479Smp 759145479Smp /* 76083098Smp * Random default kill ring size 76183098Smp */ 762167465Smp setcopy(STRkillring, str2short("30"), VAR_READWRITE); 76383098Smp 76483098Smp /* 76559243Sobrien * Re-initialize path if set in environment 76659243Sobrien */ 76759243Sobrien if ((tcp = getenv("PATH")) == NULL) 76859243Sobrien#ifdef _PATH_DEFPATH 76959243Sobrien importpath(str2short(_PATH_DEFPATH)); 77059243Sobrien#else /* !_PATH_DEFPATH */ 77159243Sobrien setq(STRpath, defaultpath(), &shvhed, VAR_READWRITE); 77259243Sobrien#endif /* _PATH_DEFPATH */ 77359243Sobrien else 77459243Sobrien /* Importpath() allocates memory for the path, and the 77559243Sobrien * returned pointer from SAVE() was discarded, so 77659243Sobrien * this was a memory leak.. (sg) 77759243Sobrien * 77859243Sobrien * importpath(SAVE(tcp)); 77959243Sobrien */ 78059243Sobrien importpath(str2short(tcp)); 78159243Sobrien 78259243Sobrien 78359243Sobrien { 78459243Sobrien /* If the SHELL environment variable ends with "tcsh", set 78559243Sobrien * STRshell to the same path. This is to facilitate using 78659243Sobrien * the executable in environments where the compiled-in 78759243Sobrien * default isn't appropriate (sg). 78859243Sobrien */ 78959243Sobrien 790167465Smp size_t sh_len = 0; 79159243Sobrien 79259243Sobrien if ((tcp = getenv("SHELL")) != NULL) { 79359243Sobrien sh_len = strlen(tcp); 79459243Sobrien if ((sh_len >= 5 && strcmp(tcp + (sh_len - 5), "/tcsh") == 0) || 79559243Sobrien (!tcsh && sh_len >= 4 && strcmp(tcp + (sh_len - 4), "/csh") == 0)) 796167465Smp setv(STRshell, quote(SAVE(tcp)), VAR_READWRITE); 79759243Sobrien else 79859243Sobrien sh_len = 0; 79959243Sobrien } 80059243Sobrien if (sh_len == 0) 801167465Smp setcopy(STRshell, STR_SHELLPATH, VAR_READWRITE); 80259243Sobrien } 80359243Sobrien 804167465Smp#ifdef _OSD_POSIX /* BS2000 needs this variable set to "SHELL" */ 805167465Smp if ((tcp = getenv("PROGRAM_ENVIRONMENT")) == NULL) 806167465Smp tcp = "SHELL"; 807167465Smp tsetenv(STRPROGRAM_ENVIRONMENT, quote(str2short(tcp))); 808167465Smp#endif /* _OSD_POSIX */ 809167465Smp 81059243Sobrien#ifdef COLOR_LS_F 81159243Sobrien if ((tcp = getenv("LS_COLORS")) != NULL) 81259243Sobrien parseLS_COLORS(str2short(tcp)); 813316958Sdchagin if ((tcp = getenv("LSCOLORS")) != NULL) 814316958Sdchagin parseLSCOLORS(str2short(tcp)); 81559243Sobrien#endif /* COLOR_LS_F */ 81659243Sobrien 817316958Sdchagin mainpid = getpid(); 818316958Sdchagin doldol = putn((tcsh_number_t)mainpid); /* For $$ */ 81969408Sache#ifdef WINNT_NATIVE 82059243Sobrien { 821167465Smp char *tmp; 822167465Smp Char *tmp2; 823167465Smp if ((tmp = getenv("TMP")) != NULL) { 824167465Smp tmp = xasprintf("%s/%s", tmp, "sh"); 825167465Smp tmp2 = SAVE(tmp); 826231990Smp xfree(tmp); 827231990Smp } 828167465Smp else { 829167465Smp tmp2 = SAVE(""); 830167465Smp } 831167465Smp shtemp = Strspl(tmp2, doldol); /* For << */ 832167465Smp xfree(tmp2); 833167465Smp } 83469408Sache#else /* !WINNT_NATIVE */ 835231990Smp#ifdef HAVE_MKSTEMP 836231990Smp { 837316958Sdchagin const char *tmpdir = getenv ("TMPDIR"); 838231990Smp if (!tmpdir) 839231990Smp tmpdir = "/tmp"; 840231990Smp shtemp = Strspl(SAVE(tmpdir), SAVE("/sh" TMP_TEMPLATE)); /* For << */ 841231990Smp } 842231990Smp#else /* !HAVE_MKSTEMP */ 84359243Sobrien shtemp = Strspl(STRtmpsh, doldol); /* For << */ 844231990Smp#endif /* HAVE_MKSTEMP */ 84569408Sache#endif /* WINNT_NATIVE */ 84659243Sobrien 84759243Sobrien /* 84859243Sobrien * Record the interrupt states from the parent process. If the parent is 84959243Sobrien * non-interruptible our hand must be forced or we (and our children) won't 85059243Sobrien * be either. Our children inherit termination from our parent. We catch it 85159243Sobrien * only if we are the login shell. 85259243Sobrien */ 853167465Smp sigaction(SIGINT, NULL, &parintr); 854167465Smp sigaction(SIGTERM, NULL, &parterm); 85559243Sobrien 85659243Sobrien 85759243Sobrien#ifdef TCF 85859243Sobrien /* Enable process migration on ourselves and our progeny */ 85959243Sobrien (void) signal(SIGMIGRATE, SIG_DFL); 86059243Sobrien#endif /* TCF */ 86159243Sobrien 86259243Sobrien /* 86369408Sache * dspkanji/dspmbyte autosetting 86469408Sache */ 86569408Sache /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 86669408Sache#if defined(DSPMBYTE) 86769408Sache#if defined(NLS) && defined(LC_CTYPE) 868231990Smp if (((tcp = setlocale(LC_CTYPE, NULL)) != NULL || (tcp = getenv("LANG")) != NULL) && !adrof(CHECK_MBYTEVAR)) 86969408Sache#else 870231990Smp if ((tcp = getenv("LANG")) != NULL && !adrof(CHECK_MBYTEVAR)) 87169408Sache#endif 872231990Smp { 87369408Sache autoset_dspmbyte(str2short(tcp)); 87469408Sache } 87569408Sache#if defined(WINNT_NATIVE) 87669408Sache else if (!adrof(CHECK_MBYTEVAR)) 87769408Sache nt_autoset_dspmbyte(); 87869408Sache#endif /* WINNT_NATIVE */ 87969408Sache#endif 880231990Smp#if defined(AUTOSET_KANJI) 881231990Smp# if defined(NLS) && defined(LC_CTYPE) 882231990Smp if (setlocale(LC_CTYPE, NULL) != NULL || getenv("LANG") != NULL) 883231990Smp# else 884231990Smp if (getenv("LANG") != NULL) 885231990Smp# endif 886231990Smp autoset_kanji(); 887231990Smp#endif /* AUTOSET_KANJI */ 888100616Smp fix_version(); /* publish the shell version */ 889100616Smp 890100616Smp if (argc > 1 && strcmp(argv[1], "--version") == 0) { 891100616Smp xprintf("%S\n", varval(STRversion)); 892100616Smp xexit(0); 893100616Smp } 894145479Smp if (argc > 1 && strcmp(argv[1], "--help") == 0) { 895145479Smp xprintf("%S\n\n", varval(STRversion)); 896195609Smp xprintf("%s", CGETS(11, 8, HELP_STRING)); 897145479Smp xexit(0); 898145479Smp } 89969408Sache /* 90059243Sobrien * Process the arguments. 90159243Sobrien * 90259243Sobrien * Note that processing of -v/-x is actually delayed till after script 90359243Sobrien * processing. 90459243Sobrien * 90559243Sobrien * We set the first character of our name to be '-' if we are a shell 90659243Sobrien * running interruptible commands. Many programs which examine ps'es 90759243Sobrien * use this to filter such shells out. 90859243Sobrien */ 90959243Sobrien argc--, tempv++; 91059243Sobrien while (argc > 0 && (tcp = tempv[0])[0] == '-' && 91159243Sobrien *++tcp != '\0' && !batch) { 91259243Sobrien do 91359243Sobrien switch (*tcp++) { 91459243Sobrien 91559243Sobrien case 0: /* - Interruptible, no prompt */ 91659243Sobrien prompt = 0; 91759243Sobrien setintr = 1; 91859243Sobrien nofile = 1; 91959243Sobrien break; 92059243Sobrien 92159243Sobrien case 'b': /* -b Next arg is input file */ 92259243Sobrien batch = 1; 92359243Sobrien break; 92459243Sobrien 92559243Sobrien case 'c': /* -c Command input from arg */ 92659243Sobrien if (argc == 1) 92759243Sobrien xexit(0); 92859243Sobrien argc--, tempv++; 92959243Sobrien#ifdef M_XENIX 93059243Sobrien /* Xenix Vi bug: 93159243Sobrien it relies on a 7 bit environment (/bin/sh), so it 93259243Sobrien pass ascii arguments with the 8th bit set */ 93359243Sobrien if (!strcmp(argv[0], "sh")) 93459243Sobrien { 93559243Sobrien char *p; 93659243Sobrien 93759243Sobrien for (p = tempv[0]; *p; ++p) 93859243Sobrien *p &= ASCII; 93959243Sobrien } 94059243Sobrien#endif 941316958Sdchagin targinp = tempv[0]; 94259243Sobrien prompt = 0; 94359243Sobrien nofile = 1; 94459243Sobrien break; 94559243Sobrien case 'd': /* -d Load directory stack from file */ 94659243Sobrien rdirs = 1; 94759243Sobrien break; 94859243Sobrien 94959243Sobrien#ifdef apollo 95059243Sobrien case 'D': /* -D Define environment variable */ 95159243Sobrien { 952145479Smp Char *dp; 95359243Sobrien 95459243Sobrien cp = str2short(tcp); 95559243Sobrien if (dp = Strchr(cp, '=')) { 95659243Sobrien *dp++ = '\0'; 95759243Sobrien tsetenv(cp, dp); 95859243Sobrien } 95959243Sobrien else 96059243Sobrien tsetenv(cp, STRNULL); 96159243Sobrien } 96259243Sobrien *tcp = '\0'; /* done with this argument */ 96359243Sobrien break; 96459243Sobrien#endif /* apollo */ 96559243Sobrien 96659243Sobrien case 'e': /* -e Exit on any error */ 96759243Sobrien exiterr = 1; 96859243Sobrien break; 96959243Sobrien 97059243Sobrien case 'f': /* -f Fast start */ 97159243Sobrien fast = 1; 97259243Sobrien break; 97359243Sobrien 97459243Sobrien case 'i': /* -i Interactive, even if !intty */ 97559243Sobrien intact = 1; 97659243Sobrien nofile = 1; 97759243Sobrien break; 97859243Sobrien 97959243Sobrien case 'm': /* -m read .cshrc (from su) */ 98059243Sobrien mflag = 1; 98159243Sobrien break; 98259243Sobrien 98359243Sobrien case 'n': /* -n Don't execute */ 98459243Sobrien noexec = 1; 98559243Sobrien break; 98659243Sobrien 98759243Sobrien case 'q': /* -q (Undoc'd) ... die on quit */ 98859243Sobrien quitit = 1; 98959243Sobrien break; 99059243Sobrien 99159243Sobrien case 's': /* -s Read from std input */ 99259243Sobrien nofile = 1; 99359243Sobrien break; 99459243Sobrien 99559243Sobrien case 't': /* -t Read one line from input */ 99659243Sobrien onelflg = 2; 99759243Sobrien prompt = 0; 99859243Sobrien nofile = 1; 99959243Sobrien break; 100059243Sobrien 100159243Sobrien case 'v': /* -v Echo hist expanded input */ 100259243Sobrien nverbose = 1; /* ... later */ 100359243Sobrien break; 100459243Sobrien 100559243Sobrien case 'x': /* -x Echo just before execution */ 100659243Sobrien nexececho = 1; /* ... later */ 100759243Sobrien break; 100859243Sobrien 100959243Sobrien case 'V': /* -V Echo hist expanded input */ 101059243Sobrien setNS(STRverbose); /* NOW! */ 101159243Sobrien break; 101259243Sobrien 101359243Sobrien case 'X': /* -X Echo just before execution */ 101459243Sobrien setNS(STRecho); /* NOW! */ 101559243Sobrien break; 101659243Sobrien 1017167465Smp case 'F': 101859243Sobrien /* 101959243Sobrien * This will cause children to be created using fork instead of 102059243Sobrien * vfork. 102159243Sobrien */ 102259243Sobrien use_fork = 1; 102359243Sobrien break; 102459243Sobrien 102559243Sobrien case ' ': 102659243Sobrien case '\t': 1027231990Smp case '\r': 1028231990Smp case '\n': 102959243Sobrien /* 103059243Sobrien * for O/S's that don't do the argument parsing right in 103159243Sobrien * "#!/foo -f " scripts 103259243Sobrien */ 103359243Sobrien break; 103459243Sobrien 103559243Sobrien default: /* Unknown command option */ 103659243Sobrien exiterr = 1; 103759243Sobrien stderror(ERR_TCSHUSAGE, tcp-1, progname); 103859243Sobrien break; 103959243Sobrien 104059243Sobrien } while (*tcp); 104159243Sobrien tempv++, argc--; 104259243Sobrien } 104359243Sobrien 104459243Sobrien if (quitit) /* With all due haste, for debugging */ 104559243Sobrien (void) signal(SIGQUIT, SIG_DFL); 104659243Sobrien 104759243Sobrien /* 104859243Sobrien * Unless prevented by -, -c, -i, -s, or -t, if there are remaining 104959243Sobrien * arguments the first of them is the name of a shell file from which to 105059243Sobrien * read commands. 105159243Sobrien */ 105259243Sobrien if (nofile == 0 && argc > 0) { 1053167465Smp nofile = xopen(tempv[0], O_RDONLY|O_LARGEFILE); 105459243Sobrien if (nofile < 0) { 105559243Sobrien child = 1; /* So this ... */ 105659243Sobrien /* ... doesn't return */ 105759243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 105859243Sobrien } 1059167465Smp xfree(ffile); 106059243Sobrien dolzero = 1; 106159243Sobrien ffile = SAVE(tempv[0]); 106259243Sobrien /* 106359243Sobrien * Replace FSHIN. Handle /dev/std{in,out,err} specially 106459243Sobrien * since once they are closed we cannot open them again. 106559243Sobrien * In that case we use our own saved descriptors 106659243Sobrien */ 106759243Sobrien if ((SHIN = dmove(nofile, FSHIN)) < 0) 106859243Sobrien switch(nofile) { 106959243Sobrien case 0: 107059243Sobrien SHIN = FSHIN; 107159243Sobrien break; 107259243Sobrien case 1: 107359243Sobrien SHIN = FSHOUT; 107459243Sobrien break; 107559243Sobrien case 2: 107659243Sobrien SHIN = FSHDIAG; 107759243Sobrien break; 107859243Sobrien default: 107959243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 108059243Sobrien break; 108159243Sobrien } 108259243Sobrien (void) close_on_exec(SHIN, 1); 108359243Sobrien prompt = 0; 108459243Sobrien /* argc not used any more */ tempv++; 108559243Sobrien } 108659243Sobrien 1087100616Smp /* 1088100616Smp * Call to closem() used to be part of initdesc(). Now called below where 1089100616Smp * the script name argument has become stdin. Kernel may have used a file 1090100616Smp * descriptor to hold the name of the script (setuid case) and this name 1091100616Smp * mustn't be lost by closing the fd too soon. 1092100616Smp */ 1093100616Smp closem(); 109459243Sobrien 109559243Sobrien /* 109659243Sobrien * Consider input a tty if it really is or we are interactive. but not for 109759243Sobrien * editing (christos) 109859243Sobrien */ 109959243Sobrien if (!(intty = isatty(SHIN))) { 110059243Sobrien if (adrof(STRedit)) 110159243Sobrien unsetv(STRedit); 110259243Sobrien editing = 0; 110359243Sobrien } 110459243Sobrien intty |= intact; 110559243Sobrien#ifndef convex 110659243Sobrien if (intty || (intact && isatty(SHOUT))) { 110759243Sobrien if (!batch && (uid != euid || gid != egid)) { 110859243Sobrien errno = EACCES; 110959243Sobrien child = 1; /* So this ... */ 111059243Sobrien /* ... doesn't return */ 111159243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 111259243Sobrien } 111359243Sobrien } 111459243Sobrien#endif /* convex */ 111559243Sobrien isoutatty = isatty(SHOUT); 111659243Sobrien isdiagatty = isatty(SHDIAG); 111759243Sobrien /* 111859243Sobrien * Decide whether we should play with signals or not. If we are explicitly 111959243Sobrien * told (via -i, or -) or we are a login shell (arg0 starts with -) or the 112059243Sobrien * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 112159243Sobrien * Note that in only the login shell is it likely that parent may have set 112259243Sobrien * signals to be ignored 112359243Sobrien */ 112459243Sobrien if (loginsh || intact || (intty && isatty(SHOUT))) 112559243Sobrien setintr = 1; 112659243Sobrien settell(); 112759243Sobrien /* 112859243Sobrien * Save the remaining arguments in argv. 112959243Sobrien */ 113059243Sobrien setq(STRargv, blk2short(tempv), &shvhed, VAR_READWRITE); 113159243Sobrien 113259243Sobrien /* 113359243Sobrien * Set up the prompt. 113459243Sobrien */ 113559243Sobrien if (prompt) { 1136231990Smp setcopy(STRprompt, STRdefprompt, VAR_READWRITE); 113759243Sobrien /* that's a meta-questionmark */ 1138167465Smp setcopy(STRprompt2, STRmquestion, VAR_READWRITE); 1139167465Smp setcopy(STRprompt3, STRKCORRECT, VAR_READWRITE); 114059243Sobrien } 114159243Sobrien 114259243Sobrien /* 114359243Sobrien * If we are an interactive shell, then start fiddling with the signals; 114459243Sobrien * this is a tricky game. 114559243Sobrien */ 114659243Sobrien shpgrp = mygetpgrp(); 114759243Sobrien opgrp = tpgrp = -1; 114859243Sobrien if (setintr) { 1149167465Smp struct sigaction osig; 1150167465Smp 115159243Sobrien **argv = '-'; 115259243Sobrien if (!quitit) /* Wary! */ 115359243Sobrien (void) signal(SIGQUIT, SIG_IGN); 1154167465Smp pintr_disabled = 1; 1155167465Smp sigset_interrupting(SIGINT, queue_pintr); 115659243Sobrien (void) signal(SIGTERM, SIG_IGN); 115759243Sobrien 115859243Sobrien /* 115959243Sobrien * No reason I can see not to save history on all these events.. 116059243Sobrien * Most usual occurrence is in a window system, where we're not a login 116159243Sobrien * shell, but might as well be... (sg) 116259243Sobrien * But there might be races when lots of shells exit together... 116359243Sobrien * [this is also incompatible]. 116459243Sobrien * We have to be mre careful here. If the parent wants to 116559243Sobrien * ignore the signals then we leave them untouched... 116659243Sobrien * We also only setup the handlers for shells that are trully 116759243Sobrien * interactive. 116859243Sobrien */ 1169167465Smp sigaction(SIGHUP, NULL, &osig); 1170167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1171167465Smp /* exit processing on HUP */ 1172167465Smp sigset_interrupting(SIGHUP, queue_phup); 117359243Sobrien#ifdef SIGXCPU 1174167465Smp sigaction(SIGXCPU, NULL, &osig); 1175167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1176167465Smp /* exit processing on XCPU */ 1177167465Smp sigset_interrupting(SIGXCPU, queue_phup); 117859243Sobrien#endif 117959243Sobrien#ifdef SIGXFSZ 1180167465Smp sigaction(SIGXFSZ, NULL, &osig); 1181167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1182167465Smp /* exit processing on XFSZ */ 1183167465Smp sigset_interrupting(SIGXFSZ, queue_phup); 118459243Sobrien#endif 118559243Sobrien 1186316958Sdchagin if (quitit == 0 && targinp == 0) { 118759243Sobrien#ifdef SIGTSTP 118859243Sobrien (void) signal(SIGTSTP, SIG_IGN); 118959243Sobrien#endif 119059243Sobrien#ifdef SIGTTIN 119159243Sobrien (void) signal(SIGTTIN, SIG_IGN); 119259243Sobrien#endif 119359243Sobrien#ifdef SIGTTOU 119459243Sobrien (void) signal(SIGTTOU, SIG_IGN); 119559243Sobrien#endif 119659243Sobrien /* 119759243Sobrien * Wait till in foreground, in case someone stupidly runs csh & 119859243Sobrien * dont want to try to grab away the tty. 119959243Sobrien */ 120059243Sobrien if (isatty(FSHDIAG)) 120159243Sobrien f = FSHDIAG; 120259243Sobrien else if (isatty(FSHOUT)) 120359243Sobrien f = FSHOUT; 120459243Sobrien else if (isatty(OLDSTD)) 120559243Sobrien f = OLDSTD; 120659243Sobrien else 120759243Sobrien f = -1; 120859243Sobrien 120959243Sobrien#ifdef NeXT 121059243Sobrien /* NeXT 2.0 /usr/etc/rlogind, does not set our process group! */ 1211316958Sdchagin if (f != -1 && shpgrp == 0) { 121259243Sobrien shpgrp = getpid(); 121359243Sobrien (void) setpgid(0, shpgrp); 121459243Sobrien (void) tcsetpgrp(f, shpgrp); 121559243Sobrien } 121659243Sobrien#endif /* NeXT */ 121759243Sobrien#ifdef BSDJOBS /* if we have tty job control */ 1218316958Sdchagin if (f != -1 && grabpgrp(f, shpgrp) != -1) { 121959243Sobrien /* 122059243Sobrien * Thanks to Matt Day for the POSIX references, and to 122159243Sobrien * Paul Close for the SGI clarification. 122259243Sobrien */ 122359243Sobrien if (setdisc(f) != -1) { 122459243Sobrien opgrp = shpgrp; 122559243Sobrien shpgrp = getpid(); 122659243Sobrien tpgrp = shpgrp; 122759243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 122859243Sobrien /* 122959243Sobrien * On hpux 7.03 this fails with EPERM. This happens on 123059243Sobrien * the 800 when opgrp != shpgrp at this point. (we were 123159243Sobrien * forked from a non job control shell) 123259243Sobrien * POSIX 7.2.4, says we failed because the process 123359243Sobrien * group specified did not belong to a process 123459243Sobrien * in the same session with the tty. So we set our 123559243Sobrien * process group and try again. 123659243Sobrien */ 123759243Sobrien if (setpgid(0, shpgrp) == -1) { 123859243Sobrien xprintf("setpgid:"); 123959243Sobrien goto notty; 124059243Sobrien } 124159243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 124259243Sobrien xprintf("tcsetpgrp:"); 124359243Sobrien goto notty; 124459243Sobrien } 124559243Sobrien } 124659243Sobrien /* 124759243Sobrien * We check the process group now. If it is the same, then 124859243Sobrien * we don't need to set it again. On hpux 7.0 on the 300's 124959243Sobrien * if we set it again it fails with EPERM. This is the 125059243Sobrien * correct behavior according to POSIX 4.3.3 if the process 125159243Sobrien * was a session leader . 125259243Sobrien */ 125359243Sobrien else if (shpgrp != mygetpgrp()) { 125459243Sobrien if(setpgid(0, shpgrp) == -1) { 125559243Sobrien xprintf("setpgid:"); 125659243Sobrien goto notty; 125759243Sobrien } 125859243Sobrien } 125959243Sobrien#ifdef IRIS4D 126059243Sobrien /* 126159243Sobrien * But on irix 3.3 we need to set it again, even if it is 126259243Sobrien * the same. We do that to tell the system that we 126359243Sobrien * need BSD process group compatibility. 126459243Sobrien */ 126559243Sobrien else 126659243Sobrien (void) setpgid(0, shpgrp); 126759243Sobrien#endif 126859243Sobrien (void) close_on_exec(dcopy(f, FSHTTY), 1); 126959243Sobrien } 127059243Sobrien else 127159243Sobrien tpgrp = -1; 127259243Sobrien } 127359243Sobrien if (tpgrp == -1) { 127459243Sobrien notty: 1275167465Smp xprintf(CGETS(11, 1, "Warning: no access to tty (%s).\n"), 1276195609Smp strerror(errno)); 1277195609Smp xprintf("%s", 1278195609Smp CGETS(11, 2, "Thus no job control in this shell.\n")); 127959243Sobrien /* 128059243Sobrien * Fix from:Sakari Jalovaara <sja@sirius.hut.fi> if we don't 128159243Sobrien * have access to tty, disable editing too 128259243Sobrien */ 128359243Sobrien if (adrof(STRedit)) 128459243Sobrien unsetv(STRedit); 128559243Sobrien editing = 0; 128659243Sobrien } 128759243Sobrien#else /* BSDJOBS */ /* don't have job control, so frotz it */ 128859243Sobrien tpgrp = -1; 128959243Sobrien#endif /* BSDJOBS */ 129059243Sobrien } 129159243Sobrien } 1292167465Smp if (setintr == 0 && parintr.sa_handler == SIG_DFL) 129359243Sobrien setintr = 1; 129459243Sobrien 129559243Sobrien/* 129659243Sobrien * SVR4 doesn't send a SIGCHLD when a child is stopped or continued if the 129759243Sobrien * handler is installed with signal(2) or sigset(2). sigaction(2) must 129859243Sobrien * be used instead. 129959243Sobrien * 130059243Sobrien * David Dawes (dawes@physics.su.oz.au) Sept 1991 130159243Sobrien */ 1302167465Smp sigset_interrupting(SIGCHLD, queue_pchild); 130359243Sobrien 1304316958Sdchagin if (intty && !targinp) 130559243Sobrien (void) ed_Setup(editing);/* Get the tty state, and set defaults */ 130659243Sobrien /* Only alter the tty state if editing */ 130759243Sobrien 130859243Sobrien /* 130959243Sobrien * Set an exit here in case of an interrupt or error reading the shell 131059243Sobrien * start-up scripts. 131159243Sobrien */ 1312131962Smp osetintr = setintr; 1313131962Smp oparintr = parintr; 1314167465Smp (void)cleanup_push_mark(); /* There is no outer handler */ 1315167465Smp if (setexit() != 0) /* PWP */ 1316167465Smp reenter = 1; 1317167465Smp else 1318167465Smp reenter = 0; 131969408Sache exitset++; 132059243Sobrien haderr = 0; /* In case second time through */ 132159243Sobrien if (!fast && reenter == 0) { 132259243Sobrien /* Will have varval(STRhome) here because set fast if don't */ 132359243Sobrien { 1324167465Smp pintr_disabled++; 1325167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1326167465Smp setintr = 0;/*FIXRESET:cleanup*/ 1327167465Smp /* onintr in /etc/ files has no effect */ 1328167465Smp parintr.sa_handler = SIG_IGN;/*FIXRESET: cleanup*/ 132959243Sobrien#ifdef LOGINFIRST 133059243Sobrien#ifdef _PATH_DOTLOGIN 133159243Sobrien if (loginsh) 1332167465Smp (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 133359243Sobrien#endif 133459243Sobrien#endif 133559243Sobrien 133659243Sobrien#ifdef _PATH_DOTCSHRC 133759243Sobrien (void) srcfile(_PATH_DOTCSHRC, 0, 0, NULL); 133859243Sobrien#endif 1339316958Sdchagin if (!targinp && !onelflg && !havhash) 134059243Sobrien dohash(NULL,NULL); 134159243Sobrien#ifndef LOGINFIRST 134259243Sobrien#ifdef _PATH_DOTLOGIN 134359243Sobrien if (loginsh) 134459243Sobrien (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 134559243Sobrien#endif 134659243Sobrien#endif 1347167465Smp cleanup_until(&pintr_disabled); 134859243Sobrien setintr = osetintr; 134959243Sobrien parintr = oparintr; 135059243Sobrien } 135159243Sobrien#ifdef LOGINFIRST 135259243Sobrien if (loginsh) 135359243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 135459243Sobrien#endif 135559243Sobrien /* upward compat. */ 135659243Sobrien if (!srccat(varval(STRhome), STRsldottcshrc)) 135759243Sobrien (void) srccat(varval(STRhome), STRsldotcshrc); 135859243Sobrien 1359316958Sdchagin if (!targinp && !onelflg && !havhash) 136059243Sobrien dohash(NULL,NULL); 136159243Sobrien 136259243Sobrien /* 136359243Sobrien * Source history before .login so that it is available in .login 136459243Sobrien */ 136559243Sobrien loadhist(NULL, 0); 136659243Sobrien#ifndef LOGINFIRST 136759243Sobrien if (loginsh) 136859243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 136959243Sobrien#endif 1370167465Smp if (loginsh || rdirs) 137159243Sobrien loaddirs(NULL); 137259243Sobrien } 1373131962Smp /* Reset interrupt flag */ 1374131962Smp setintr = osetintr; 1375131962Smp parintr = oparintr; 1376167465Smp exitset--; 1377131962Smp 137859243Sobrien /* Initing AFTER .cshrc is the Right Way */ 1379316958Sdchagin if (intty && !targinp) { /* PWP setup stuff */ 138059243Sobrien ed_Init(); /* init the new line editor */ 138159243Sobrien#ifdef SIG_WINDOW 138259243Sobrien check_window_size(1); /* mung environment */ 138359243Sobrien#endif /* SIG_WINDOW */ 138459243Sobrien } 138559243Sobrien 138659243Sobrien /* 138759243Sobrien * Now are ready for the -v and -x flags 138859243Sobrien */ 138959243Sobrien if (nverbose) 139059243Sobrien setNS(STRverbose); 139159243Sobrien if (nexececho) 139259243Sobrien setNS(STRecho); 139359243Sobrien 1394316958Sdchagin 1395316958Sdchagin if (targinp) { 1396316958Sdchagin arginp = SAVE(targinp); 1397316958Sdchagin /* 1398316958Sdchagin * we put the command into a variable 1399316958Sdchagin */ 1400316958Sdchagin if (arginp != NULL) 1401316958Sdchagin setv(STRcommand, quote(Strsave(arginp)), VAR_READWRITE); 1402316958Sdchagin 1403316958Sdchagin /* 1404316958Sdchagin * * Give an error on -c arguments that end in * backslash to 1405316958Sdchagin * ensure that you don't make * nonportable csh scripts. 1406316958Sdchagin */ 1407316958Sdchagin { 1408316958Sdchagin int count; 1409316958Sdchagin 1410316958Sdchagin cp = Strend(arginp); 1411316958Sdchagin count = 0; 1412316958Sdchagin while (cp > arginp && *--cp == '\\') 1413316958Sdchagin ++count; 1414316958Sdchagin if ((count & 1) != 0) { 1415316958Sdchagin exiterr = 1; 1416316958Sdchagin stderror(ERR_ARGC); 1417316958Sdchagin } 1418316958Sdchagin } 1419316958Sdchagin } 142059243Sobrien /* 142159243Sobrien * All the rest of the world is inside this call. The argument to process 142259243Sobrien * indicates whether it should catch "error unwinds". Thus if we are a 142359243Sobrien * interactive shell our call here will never return by being blown past on 142459243Sobrien * an error. 142559243Sobrien */ 142659243Sobrien process(setintr); 142759243Sobrien 142859243Sobrien /* 142959243Sobrien * Mop-up. 143059243Sobrien */ 1431197812Srdivacky /* Take care of these (especially HUP) here instead of inside flush. */ 1432197812Srdivacky handle_pending_signals(); 143359243Sobrien if (intty) { 143459243Sobrien if (loginsh) { 143559243Sobrien xprintf("logout\n"); 1436167465Smp xclose(SHIN); 143759243Sobrien child = 1; 143859243Sobrien#ifdef TESLA 143959243Sobrien do_logout = 1; 144059243Sobrien#endif /* TESLA */ 144159243Sobrien goodbye(NULL, NULL); 144259243Sobrien } 144359243Sobrien else { 144459243Sobrien xprintf("exit\n"); 144559243Sobrien } 144659243Sobrien } 144759243Sobrien record(); 144859243Sobrien exitstat(); 144959243Sobrien return (0); 145059243Sobrien} 145159243Sobrien 145259243Sobrienvoid 1453167465Smpuntty(void) 145459243Sobrien{ 145559243Sobrien#ifdef BSDJOBS 145659243Sobrien if (tpgrp > 0 && opgrp != shpgrp) { 145759243Sobrien (void) setpgid(0, opgrp); 145859243Sobrien (void) tcsetpgrp(FSHTTY, opgrp); 145959243Sobrien (void) resetdisc(FSHTTY); 146059243Sobrien } 146159243Sobrien#endif /* BSDJOBS */ 146259243Sobrien} 146359243Sobrien 146459243Sobrienvoid 1465167465Smpimportpath(Char *cp) 146659243Sobrien{ 1467167465Smp size_t i = 0; 1468145479Smp Char *dp; 1469145479Smp Char **pv; 147059243Sobrien int c; 147159243Sobrien 147259243Sobrien for (dp = cp; *dp; dp++) 147359243Sobrien if (*dp == PATHSEP) 147459243Sobrien i++; 147559243Sobrien /* 147659243Sobrien * i+2 where i is the number of colons in the path. There are i+1 147759243Sobrien * directories in the path plus we need room for a zero terminator. 147859243Sobrien */ 1479167465Smp pv = xcalloc(i + 2, sizeof(Char *)); 148059243Sobrien dp = cp; 148159243Sobrien i = 0; 148259243Sobrien if (*dp) 148359243Sobrien for (;;) { 148459243Sobrien if ((c = *dp) == PATHSEP || c == 0) { 148559243Sobrien *dp = 0; 148659243Sobrien pv[i++] = Strsave(*cp ? cp : STRdot); 148759243Sobrien if (c) { 148859243Sobrien cp = dp + 1; 148959243Sobrien *dp = PATHSEP; 149059243Sobrien } 149159243Sobrien else 149259243Sobrien break; 149359243Sobrien } 149469408Sache#ifdef WINNT_NATIVE 149559243Sobrien else if (*dp == '\\') 149659243Sobrien *dp = '/'; 149769408Sache#endif /* WINNT_NATIVE */ 149859243Sobrien dp++; 149959243Sobrien } 150059243Sobrien pv[i] = 0; 1501167465Smp cleanup_push(pv, blk_cleanup); 150259243Sobrien setq(STRpath, pv, &shvhed, VAR_READWRITE); 1503167465Smp cleanup_ignore(pv); 1504167465Smp cleanup_until(pv); 150559243Sobrien} 150659243Sobrien 150759243Sobrien/* 150859243Sobrien * Source to the file which is the catenation of the argument names. 150959243Sobrien */ 151059243Sobrienstatic int 1511167465Smpsrccat(Char *cp, Char *dp) 151259243Sobrien{ 151359243Sobrien if (cp[0] == '/' && cp[1] == '\0') 151459243Sobrien return srcfile(short2str(dp), (mflag ? 0 : 1), 0, NULL); 151559243Sobrien else { 1516145479Smp Char *ep; 151759243Sobrien char *ptr; 151859243Sobrien int rv; 151959243Sobrien 152069408Sache#ifdef WINNT_NATIVE 1521167465Smp ep = Strend(cp); 1522167465Smp if (ep != cp && ep[-1] == '/' && dp[0] == '/') /* silly win95 */ 152359243Sobrien dp++; 152469408Sache#endif /* WINNT_NATIVE */ 152559243Sobrien 152659243Sobrien ep = Strspl(cp, dp); 1527167465Smp cleanup_push(ep, xfree); 152859243Sobrien ptr = short2str(ep); 152959243Sobrien 153059243Sobrien rv = srcfile(ptr, (mflag ? 0 : 1), 0, NULL); 1531167465Smp cleanup_until(ep); 153259243Sobrien return rv; 153359243Sobrien } 153459243Sobrien} 153559243Sobrien 153659243Sobrien/* 153759243Sobrien * Source to a file putting the file descriptor in a safe place (> 2). 153859243Sobrien */ 153983098Smp#ifndef WINNT_NATIVE 154059243Sobrienstatic int 154183098Smp#else 154283098Smpint 154383098Smp#endif /*WINNT_NATIVE*/ 1544167465Smpsrcfile(const char *f, int onlyown, int flag, Char **av) 154559243Sobrien{ 1546145479Smp int unit; 154759243Sobrien 1548167465Smp if ((unit = xopen(f, O_RDONLY|O_LARGEFILE)) == -1) 154959243Sobrien return 0; 1550167465Smp cleanup_push(&unit, open_cleanup); 155159243Sobrien unit = dmove(unit, -1); 1552167465Smp cleanup_ignore(&unit); 1553167465Smp cleanup_until(&unit); 155459243Sobrien 155559243Sobrien (void) close_on_exec(unit, 1); 155659243Sobrien srcunit(unit, onlyown, flag, av); 155759243Sobrien return 1; 155859243Sobrien} 155959243Sobrien 156059243Sobrien 156159243Sobrien/* 156259243Sobrien * Save the shell state, and establish new argument vector, and new input 156359243Sobrien * fd. 156459243Sobrien */ 156559243Sobrienstatic void 1566167465Smpst_save(struct saved_state *st, int unit, int hflg, Char **al, Char **av) 156759243Sobrien{ 156859243Sobrien st->insource = insource; 156959243Sobrien st->SHIN = SHIN; 1570100616Smp /* Want to preserve the meaning of "source file >output". 1571100616Smp * Save old descriptors, move new 0,1,2 to safe places and assign 1572100616Smp * them to SH* and let process() redo 0,1,2 from them. 1573100616Smp * 1574100616Smp * The macro returns true if d1 and d2 are good and they point to 1575100616Smp * different things. If you don't avoid saving duplicate 1576100616Smp * descriptors, you really limit the depth of "source" recursion 1577100616Smp * you can do because of all the open file descriptors. -IAN! 1578100616Smp */ 1579100616Smp#define NEED_SAVE_FD(d1,d2) \ 1580100616Smp (fstat(d1, &s1) != -1 && fstat(d2, &s2) != -1 \ 1581100616Smp && (s1.st_ino != s2.st_ino || s1.st_dev != s2.st_dev) ) 1582100616Smp 1583100616Smp st->OLDSTD = st->SHOUT = st->SHDIAG = -1;/* test later to restore these */ 1584100616Smp if (didfds) { 1585100616Smp struct stat s1, s2; 1586145479Smp if (NEED_SAVE_FD(0,OLDSTD)) { 1587145479Smp st->OLDSTD = OLDSTD; 1588145479Smp OLDSTD = dmove(0, -1); 1589145479Smp (void)close_on_exec(OLDSTD, 1); 1590145479Smp } 1591145479Smp if (NEED_SAVE_FD(1,SHOUT)) { 1592145479Smp st->SHOUT = SHOUT; 1593145479Smp SHOUT = dmove(1, -1); 1594145479Smp (void)close_on_exec(SHOUT, 1); 1595145479Smp } 1596145479Smp if (NEED_SAVE_FD(2,SHDIAG)) { 1597145479Smp st->SHDIAG = SHDIAG; 1598145479Smp SHDIAG = dmove(2, -1); 1599145479Smp (void)close_on_exec(SHDIAG, 1); 1600145479Smp } 1601100616Smp donefds(); 1602100616Smp } 1603100616Smp 160459243Sobrien st->intty = intty; 160559243Sobrien st->whyles = whyles; 160659243Sobrien st->gointr = gointr; 160759243Sobrien st->arginp = arginp; 160859243Sobrien st->evalp = evalp; 160959243Sobrien st->evalvec = evalvec; 161059243Sobrien st->alvecp = alvecp; 161159243Sobrien st->alvec = alvec; 161259243Sobrien st->onelflg = onelflg; 161359243Sobrien st->enterhist = enterhist; 1614195609Smp st->justpr = justpr; 161559243Sobrien if (hflg) 161659243Sobrien st->HIST = HIST; 161759243Sobrien else 161859243Sobrien st->HIST = '\0'; 161959243Sobrien st->cantell = cantell; 162059243Sobrien cpybin(st->B, B); 162159243Sobrien 162259243Sobrien /* 162359243Sobrien * we can now pass arguments to source. 162459243Sobrien * For compatibility we do that only if arguments were really 162559243Sobrien * passed, otherwise we keep the old, global $argv like before. 162659243Sobrien */ 162759243Sobrien if (av != NULL && *av != NULL) { 162859243Sobrien struct varent *vp; 1629100616Smp if ((vp = adrof(STRargv)) != NULL && vp->vec != NULL) 163059243Sobrien st->argv = saveblk(vp->vec); 163159243Sobrien else 163259243Sobrien st->argv = NULL; 163359243Sobrien setq(STRargv, saveblk(av), &shvhed, VAR_READWRITE); 163459243Sobrien } 163559243Sobrien else 163659243Sobrien st->argv = NULL; 1637167465Smp st->av = av; 163859243Sobrien 163959243Sobrien SHIN = unit; /* Do this first */ 164059243Sobrien 164159243Sobrien /* Establish new input arena */ 164259243Sobrien { 164359243Sobrien fbuf = NULL; 164459243Sobrien fseekp = feobp = fblocks = 0; 164559243Sobrien settell(); 164659243Sobrien } 164759243Sobrien 164859243Sobrien arginp = 0; 164959243Sobrien onelflg = 0; 165059243Sobrien intty = isatty(SHIN); 165159243Sobrien whyles = 0; 165259243Sobrien gointr = 0; 165359243Sobrien evalvec = 0; 165459243Sobrien evalp = 0; 165559243Sobrien alvec = al; 165659243Sobrien alvecp = 0; 165759243Sobrien enterhist = hflg; 165859243Sobrien if (enterhist) 165959243Sobrien HIST = '\0'; 166059243Sobrien insource = 1; 166159243Sobrien} 166259243Sobrien 166359243Sobrien 166459243Sobrien/* 166559243Sobrien * Restore the shell to a saved state 166659243Sobrien */ 166759243Sobrienstatic void 1668167465Smpst_restore(void *xst) 1669167465Smp{ 167059243Sobrien struct saved_state *st; 1671167465Smp 1672167465Smp st = xst; 167359243Sobrien if (st->SHIN == -1) 167459243Sobrien return; 167559243Sobrien 167659243Sobrien /* Reset input arena */ 167759243Sobrien { 1678145479Smp int i; 1679145479Smp Char** nfbuf = fbuf; 1680145479Smp int nfblocks = fblocks; 168159243Sobrien 168259243Sobrien fblocks = 0; 168359243Sobrien fbuf = NULL; 168459243Sobrien for (i = 0; i < nfblocks; i++) 1685167465Smp xfree(nfbuf[i]); 1686167465Smp xfree(nfbuf); 168759243Sobrien } 168859243Sobrien cpybin(B, st->B); 168959243Sobrien 1690167465Smp xclose(SHIN); 169159243Sobrien 169259243Sobrien insource = st->insource; 169359243Sobrien SHIN = st->SHIN; 1694100616Smp if (st->OLDSTD != -1) 1695167465Smp xclose(OLDSTD), OLDSTD = st->OLDSTD; 1696100616Smp if (st->SHOUT != -1) 1697167465Smp xclose(SHOUT), SHOUT = st->SHOUT; 1698100616Smp if (st->SHDIAG != -1) 1699167465Smp xclose(SHDIAG), SHDIAG = st->SHDIAG; 170059243Sobrien arginp = st->arginp; 170159243Sobrien onelflg = st->onelflg; 170259243Sobrien evalp = st->evalp; 170359243Sobrien evalvec = st->evalvec; 170459243Sobrien alvecp = st->alvecp; 170559243Sobrien alvec = st->alvec; 170659243Sobrien intty = st->intty; 170759243Sobrien whyles = st->whyles; 170859243Sobrien gointr = st->gointr; 170959243Sobrien if (st->HIST != '\0') 171059243Sobrien HIST = st->HIST; 171159243Sobrien enterhist = st->enterhist; 171259243Sobrien cantell = st->cantell; 1713195609Smp justpr = st->justpr; 171459243Sobrien 171559243Sobrien if (st->argv != NULL) 171659243Sobrien setq(STRargv, st->argv, &shvhed, VAR_READWRITE); 1717167465Smp else if (st->av != NULL && *st->av != NULL && adrof(STRargv) != NULL) 171859243Sobrien unsetv(STRargv); 171959243Sobrien} 172059243Sobrien 172159243Sobrien/* 172259243Sobrien * Source to a unit. If onlyown it must be our file or our group or 172359243Sobrien * we don't chance it. This occurs on ".cshrc"s and the like. 172459243Sobrien */ 172559243Sobrienstatic void 1726167465Smpsrcunit(int unit, int onlyown, int hflg, Char **av) 172759243Sobrien{ 172859243Sobrien struct saved_state st; 1729167465Smp 173059243Sobrien st.SHIN = -1; /* st_restore checks this */ 173159243Sobrien 173259243Sobrien if (unit < 0) 173359243Sobrien return; 173459243Sobrien 173559243Sobrien if (onlyown) { 173659243Sobrien struct stat stb; 173759243Sobrien 173859243Sobrien if (fstat(unit, &stb) < 0) { 1739167465Smp xclose(unit); 174059243Sobrien return; 174159243Sobrien } 174259243Sobrien } 174359243Sobrien 1744167465Smp /* Does nothing before st_save() because st.SHIN == -1 */ 1745167465Smp cleanup_push(&st, st_restore); 1746167465Smp if (setintr) { 1747167465Smp pintr_disabled++; 1748167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1749167465Smp } 175059243Sobrien 175159243Sobrien /* Save the current state and move us to a new state */ 175259243Sobrien st_save(&st, unit, hflg, NULL, av); 175359243Sobrien 175459243Sobrien /* 175559243Sobrien * Now if we are allowing commands to be interrupted, we let ourselves be 175659243Sobrien * interrupted. 175759243Sobrien */ 1758167465Smp if (setintr) { 1759167465Smp cleanup_until(&pintr_disabled); 1760167465Smp pintr_disabled++; 1761167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 176259243Sobrien } 176359243Sobrien 1764167465Smp process(0); /* 0 -> blow away on errors */ 176559243Sobrien 176659243Sobrien /* Restore the old state */ 1767167465Smp cleanup_until(&st); 176859243Sobrien} 176959243Sobrien 177059243Sobrien 177159243Sobrien/*ARGSUSED*/ 177259243Sobrienvoid 1773167465Smpgoodbye(Char **v, struct command *c) 177459243Sobrien{ 1775145479Smp USE(v); 177659243Sobrien USE(c); 177759243Sobrien record(); 177859243Sobrien 177959243Sobrien if (loginsh) { 1780167465Smp size_t omark; 1781167465Smp sigset_t set; 1782167465Smp 1783195609Smp sigemptyset(&set); 1784167465Smp signal(SIGQUIT, SIG_IGN); 1785167465Smp sigaddset(&set, SIGQUIT); 1786167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 1787167465Smp signal(SIGINT, SIG_IGN); 1788167465Smp sigaddset(&set, SIGINT); 1789167465Smp signal(SIGTERM, SIG_IGN); 1790167465Smp sigaddset(&set, SIGTERM); 1791167465Smp signal(SIGHUP, SIG_IGN); 1792167465Smp sigaddset(&set, SIGHUP); 1793167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 1794167465Smp phup_disabled = 1; 179559243Sobrien setintr = 0; /* No interrupts after "logout" */ 179659243Sobrien /* Trap errors inside .logout */ 1797167465Smp omark = cleanup_push_mark(); 1798167465Smp if (setexit() == 0) { 1799167465Smp if (!(adrof(STRlogout))) 1800167465Smp setcopy(STRlogout, STRnormal, VAR_READWRITE); 180159243Sobrien#ifdef _PATH_DOTLOGOUT 1802167465Smp (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 180359243Sobrien#endif 1804167465Smp if (adrof(STRhome)) 1805167465Smp (void) srccat(varval(STRhome), STRsldtlogout); 180659243Sobrien#ifdef TESLA 1807167465Smp do_logout = 1; 180859243Sobrien#endif /* TESLA */ 1809167465Smp } 1810167465Smp cleanup_pop_mark(omark); 181159243Sobrien } 181259243Sobrien exitstat(); 181359243Sobrien} 181459243Sobrien 181559243Sobrienvoid 1816167465Smpexitstat(void) 181759243Sobrien{ 181859243Sobrien#ifdef PROF 1819231990Smp _mcleanup(); 182059243Sobrien#endif 182159243Sobrien /* 182259243Sobrien * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit 182359243Sobrien * directly because we poke child here. Otherwise we might continue 182459243Sobrien * unwarrantedly (sic). 182559243Sobrien */ 182659243Sobrien child = 1; 182759243Sobrien 182859243Sobrien xexit(getn(varval(STRstatus))); 182959243Sobrien} 183059243Sobrien 183159243Sobrien/* 183259243Sobrien * in the event of a HUP we want to save the history 183359243Sobrien */ 1834167465Smpvoid 1835167465Smpphup(void) 183659243Sobrien{ 183759243Sobrien if (loginsh) { 1838167465Smp setcopy(STRlogout, STRhangup, VAR_READWRITE); 183959243Sobrien#ifdef _PATH_DOTLOGOUT 184059243Sobrien (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 184159243Sobrien#endif 184259243Sobrien if (adrof(STRhome)) 184359243Sobrien (void) srccat(varval(STRhome), STRsldtlogout); 184459243Sobrien } 184559243Sobrien 184659243Sobrien record(); 184759243Sobrien 184859243Sobrien#ifdef POSIXJOBS 184959243Sobrien /* 185059243Sobrien * We kill the last foreground process group. It then becomes 185159243Sobrien * responsible to propagate the SIGHUP to its progeny. 185259243Sobrien */ 185359243Sobrien { 185459243Sobrien struct process *pp, *np; 185559243Sobrien 185659243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 185759243Sobrien np = pp; 185859243Sobrien /* 185959243Sobrien * Find if this job is in the foreground. It could be that 186059243Sobrien * the process leader has exited and the foreground flag 186159243Sobrien * is cleared for it. 186259243Sobrien */ 186359243Sobrien do 186459243Sobrien /* 186559243Sobrien * If a process is in the foreground we try to kill 186659243Sobrien * it's process group. If we succeed, then the 186759243Sobrien * whole job is gone. Otherwise we keep going... 186859243Sobrien * But avoid sending HUP to the shell again. 186959243Sobrien */ 187059243Sobrien if (((np->p_flags & PFOREGND) != 0) && np->p_jobid != shpgrp) { 187159243Sobrien np->p_flags &= ~PHUP; 187259243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 187359243Sobrien /* In case the job was suspended... */ 187459243Sobrien#ifdef SIGCONT 187559243Sobrien (void) killpg(np->p_jobid, SIGCONT); 187659243Sobrien#endif 187759243Sobrien break; 187859243Sobrien } 187959243Sobrien } 188059243Sobrien while ((np = np->p_friends) != pp); 188159243Sobrien } 188259243Sobrien } 188359243Sobrien#endif /* POSIXJOBS */ 188459243Sobrien 1885167465Smp xexit(SIGHUP); 188659243Sobrien} 188759243Sobrien 188859243Sobrienstatic Char *jobargv[2] = {STRjobs, 0}; 188959243Sobrien 189059243Sobrien/* 189159243Sobrien * Catch an interrupt, e.g. during lexical input. 189259243Sobrien * If we are an interactive shell, we reset the interrupt catch 189359243Sobrien * immediately. In any case we drain the shell output, 189459243Sobrien * and finally go through the normal error mechanism, which 189559243Sobrien * gets a chance to make the shell go away. 189659243Sobrien */ 1897167465Smpint just_signaled; /* bugfix by Michael Bloom (mg@ttidca.TTI.COM) */ 189859243Sobrien 1899167465Smpvoid 1900167465Smppintr(void) 190159243Sobrien{ 190259243Sobrien just_signaled = 1; 190359243Sobrien pintr1(1); 190459243Sobrien} 190559243Sobrien 190659243Sobrienvoid 1907167465Smppintr1(int wantnl) 190859243Sobrien{ 190959243Sobrien if (setintr) { 191059243Sobrien if (pjobs) { 191159243Sobrien pjobs = 0; 191259243Sobrien xputchar('\n'); 191359243Sobrien dojobs(jobargv, NULL); 191459243Sobrien stderror(ERR_NAME | ERR_INTR); 191559243Sobrien } 191659243Sobrien } 191759243Sobrien /* MH - handle interrupted completions specially */ 191859243Sobrien { 191959243Sobrien if (InsideCompletion) 192059243Sobrien stderror(ERR_SILENT); 192159243Sobrien } 192259243Sobrien /* JV - Make sure we shut off inputl */ 192359243Sobrien { 192459243Sobrien (void) Cookedmode(); 192559243Sobrien GettingInput = 0; 1926316958Sdchagin if (evalvec) 1927316958Sdchagin doneinp = 1; 192859243Sobrien } 192959243Sobrien drainoline(); 1930145479Smp#ifdef HAVE_GETPWENT 193159243Sobrien (void) endpwent(); 1932145479Smp#endif 193359243Sobrien 193459243Sobrien /* 193559243Sobrien * If we have an active "onintr" then we search for the label. Note that if 193659243Sobrien * one does "onintr -" then we shan't be interruptible so we needn't worry 193759243Sobrien * about that here. 193859243Sobrien */ 193959243Sobrien if (gointr) { 194059243Sobrien gotolab(gointr); 194159243Sobrien reset(); 194259243Sobrien } 194359243Sobrien else if (intty && wantnl) { 194459243Sobrien if (editing) { 194559243Sobrien /* 194659243Sobrien * If we are editing a multi-line input command, and move to 194759243Sobrien * the beginning of the line, we don't want to trash it when 194859243Sobrien * we hit ^C 194959243Sobrien */ 195059243Sobrien PastBottom(); 195159243Sobrien ClearLines(); 195259243Sobrien ClearDisp(); 195359243Sobrien } 195459243Sobrien else { 195559243Sobrien /* xputchar('\n'); *//* Some like this, others don't */ 195659243Sobrien (void) putraw('\r'); 195759243Sobrien (void) putraw('\n'); 195859243Sobrien } 195959243Sobrien } 196059243Sobrien stderror(ERR_SILENT); 196159243Sobrien} 196259243Sobrien 196359243Sobrien/* 196459243Sobrien * Process is the main driving routine for the shell. 196559243Sobrien * It runs all command processing, except for those within { ... } 196659243Sobrien * in expressions (which is run by a routine evalav in sh.exp.c which 196759243Sobrien * is a stripped down process), and `...` evaluation which is run 196859243Sobrien * also by a subset of this code in sh.glob.c in the routine backeval. 196959243Sobrien * 197059243Sobrien * The code here is a little strange because part of it is interruptible 197159243Sobrien * and hence freeing of structures appears to occur when none is necessary 197259243Sobrien * if this is ignored. 197359243Sobrien * 197459243Sobrien * Note that if catch is not set then we will unwind on any error. 197559243Sobrien * If an end-of-file occurs, we return. 197659243Sobrien */ 197759243Sobrienvoid 1978167465Smpprocess(int catch) 197959243Sobrien{ 198059243Sobrien jmp_buf_t osetexit; 1981231990Smp /* PWP: This might get nuked by longjmp so don't make it a register var */ 1982167465Smp size_t omark; 1983195609Smp volatile int didexitset = 0; 198459243Sobrien 198559243Sobrien getexit(osetexit); 1986167465Smp omark = cleanup_push_mark(); 198759243Sobrien for (;;) { 1988167465Smp struct command *t; 1989167465Smp int hadhist, old_pintr_disabled; 199059243Sobrien 1991195609Smp (void)setexit(); 1992195609Smp if (didexitset == 0) { 1993195609Smp exitset++; 1994195609Smp didexitset++; 1995195609Smp } 199659243Sobrien pendjob(); 199759243Sobrien 199859243Sobrien justpr = enterhist; /* execute if not entering history */ 199959243Sobrien 200059243Sobrien if (haderr) { 200159243Sobrien if (!catch) { 200259243Sobrien /* unwind */ 200359243Sobrien doneinp = 0; 2004167465Smp cleanup_pop_mark(omark); 200559243Sobrien resexit(osetexit); 200659243Sobrien reset(); 200759243Sobrien } 200859243Sobrien haderr = 0; 200959243Sobrien /* 201059243Sobrien * Every error is eventually caught here or the shell dies. It is 201159243Sobrien * at this point that we clean up any left-over open files, by 201259243Sobrien * closing all but a fixed number of pre-defined files. Thus 201359243Sobrien * routines don't have to worry about leaving files open due to 201459243Sobrien * deeper errors... they will get closed here. 201559243Sobrien */ 201659243Sobrien closem(); 201759243Sobrien continue; 201859243Sobrien } 201959243Sobrien if (doneinp) { 202059243Sobrien doneinp = 0; 202159243Sobrien break; 202259243Sobrien } 202359243Sobrien if (chkstop) 202459243Sobrien chkstop--; 202559243Sobrien if (neednote) 202659243Sobrien pnote(); 202759243Sobrien if (intty && prompt && evalvec == 0) { 202859243Sobrien just_signaled = 0; 202959243Sobrien mailchk(); 203059243Sobrien /* 203159243Sobrien * Watch for logins/logouts. Next is scheduled commands stored 203259243Sobrien * previously using "sched." Then execute periodic commands. 203359243Sobrien * Following that, the prompt precmd is run. 203459243Sobrien */ 203559243Sobrien#ifndef HAVENOUTMP 203659243Sobrien watch_login(0); 203759243Sobrien#endif /* !HAVENOUTMP */ 2038167465Smp sched_run(); 203959243Sobrien period_cmd(); 204059243Sobrien precmd(); 204159243Sobrien /* 204259243Sobrien * If we are at the end of the input buffer then we are going to 204359243Sobrien * read fresh stuff. Otherwise, we are rereading input and don't 204459243Sobrien * need or want to prompt. 204559243Sobrien */ 204669408Sache if (fseekp == feobp && aret == TCSH_F_SEEK) 204759243Sobrien printprompt(0, NULL); 204859243Sobrien flush(); 204959243Sobrien setalarm(1); 205059243Sobrien } 205159243Sobrien if (seterr) { 2052167465Smp xfree(seterr); 205359243Sobrien seterr = NULL; 205459243Sobrien } 205559243Sobrien 205659243Sobrien /* 2057167465Smp * Interruptible during interactive reads 2058167465Smp */ 2059167465Smp if (setintr) 2060167465Smp pintr_push_enable(&old_pintr_disabled); 2061316958Sdchagin freelex(¶ml); 2062167465Smp hadhist = lex(¶ml); 2063167465Smp if (setintr) 2064167465Smp cleanup_until(&old_pintr_disabled); 2065167465Smp cleanup_push(¶ml, lex_cleanup); 2066167465Smp 2067167465Smp /* 206859243Sobrien * Echo not only on VERBOSE, but also with history expansion. If there 206959243Sobrien * is a lexical error then we forego history echo. 2070231990Smp * Do not echo if we're only entering history (source -h). 207159243Sobrien */ 2072167465Smp if ((hadhist && !seterr && intty && !tellwhat && !Expand && !whyles) || 2073231990Smp (!enterhist && adrof(STRverbose))) 2074231990Smp { 2075100616Smp int odidfds = didfds; 207659243Sobrien haderr = 1; 2077100616Smp didfds = 0; 207859243Sobrien prlex(¶ml); 2079100616Smp flush(); 208059243Sobrien haderr = 0; 2081100616Smp didfds = odidfds; 208259243Sobrien } 208359243Sobrien (void) alarm(0); /* Autologout OFF */ 2084167465Smp alrmcatch_disabled = 1; 208559243Sobrien 208659243Sobrien /* 208759243Sobrien * Save input text on the history list if reading in old history, or it 208859243Sobrien * is from the terminal at the top level and not in a loop. 208959243Sobrien * 209059243Sobrien * PWP: entry of items in the history list while in a while loop is done 209159243Sobrien * elsewhere... 209259243Sobrien */ 209359243Sobrien if (enterhist || (catch && intty && !whyles && !tellwhat && !arun)) 209459243Sobrien savehist(¶ml, enterhist > 1); 209559243Sobrien 209659243Sobrien if (Expand && seterr) 209759243Sobrien Expand = 0; 209859243Sobrien 209959243Sobrien /* 210059243Sobrien * Print lexical error messages, except when sourcing history lists. 210159243Sobrien */ 210259243Sobrien if (!enterhist && seterr) 210359243Sobrien stderror(ERR_OLD); 210459243Sobrien 210559243Sobrien /* 210659243Sobrien * If had a history command :p modifier then this is as far as we 210759243Sobrien * should go 210859243Sobrien */ 210959243Sobrien if (justpr) 2110167465Smp goto cmd_done; 211159243Sobrien 211259243Sobrien /* 211359243Sobrien * If had a tellwhat from twenex() then do 211459243Sobrien */ 211559243Sobrien if (tellwhat) { 211659243Sobrien (void) tellmewhat(¶ml, NULL); 2117167465Smp goto cmd_done; 211859243Sobrien } 211959243Sobrien 212059243Sobrien alias(¶ml); 212159243Sobrien 212259243Sobrien#ifdef BSDJOBS 212359243Sobrien /* 212459243Sobrien * If we are interactive, try to continue jobs that we have stopped 212559243Sobrien */ 212659243Sobrien if (prompt) 212759243Sobrien continue_jobs(¶ml); 212859243Sobrien#endif /* BSDJOBS */ 212959243Sobrien 213059243Sobrien /* 213159243Sobrien * Check to see if the user typed "rm * .o" or something 213259243Sobrien */ 213359243Sobrien if (prompt) 213459243Sobrien rmstar(¶ml); 213559243Sobrien /* 213659243Sobrien * Parse the words of the input into a parse tree. 213759243Sobrien */ 2138167465Smp t = syntax(paraml.next, ¶ml, 0); 2139231990Smp /* 2140231990Smp * We cannot cleanup push here, because cd /blah; echo foo 2141231990Smp * would rewind t on the chdir error, and free the rest of the command 2142231990Smp */ 2143231990Smp if (seterr) { 2144231990Smp freesyn(t); 214559243Sobrien stderror(ERR_OLD); 2146231990Smp } 214759243Sobrien 214859243Sobrien postcmd(); 214959243Sobrien /* 215059243Sobrien * Execute the parse tree From: Michael Schroeder 215159243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> was execute(t, tpgrp); 215259243Sobrien */ 2153167465Smp execute(t, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 2154231990Smp freesyn(t); 215559243Sobrien 215659243Sobrien /* 215759243Sobrien * Made it! 215859243Sobrien */ 215959243Sobrien#ifdef SIG_WINDOW 2160100616Smp if (windowchg || (catch && intty && !whyles && !tellwhat)) { 2161100616Smp (void) check_window_size(0); /* for window systems */ 2162100616Smp } 216359243Sobrien#endif /* SIG_WINDOW */ 2164167465Smp setcopy(STR_, InputBuf, VAR_READWRITE | VAR_NOGLOB); 2165167465Smp cmd_done: 2166231990Smp if (cleanup_reset()) 2167231990Smp cleanup_until(¶ml); 2168231990Smp else 2169231990Smp haderr = 1; 217059243Sobrien } 2171167465Smp cleanup_pop_mark(omark); 217259243Sobrien resexit(osetexit); 2173195609Smp exitset--; 2174231990Smp handle_pending_signals(); 217559243Sobrien} 217659243Sobrien 217759243Sobrien/*ARGSUSED*/ 217859243Sobrienvoid 2179167465Smpdosource(Char **t, struct command *c) 218059243Sobrien{ 2181145479Smp Char *f; 2182145479Smp int hflg = 0; 2183167465Smp char *file; 218459243Sobrien 218559243Sobrien USE(c); 218659243Sobrien t++; 218759243Sobrien if (*t && eq(*t, STRmh)) { 218859243Sobrien if (*++t == NULL) 218959243Sobrien stderror(ERR_NAME | ERR_HFLAG); 219059243Sobrien hflg++; 219159243Sobrien } 219259243Sobrien else if (*t && eq(*t, STRmm)) { 219359243Sobrien if (*++t == NULL) 219459243Sobrien stderror(ERR_NAME | ERR_MFLAG); 219559243Sobrien hflg = 2; 219659243Sobrien } 219759243Sobrien 219859243Sobrien f = globone(*t++, G_ERROR); 2199167465Smp file = strsave(short2str(f)); 2200167465Smp cleanup_push(file, xfree); 2201167465Smp xfree(f); 2202167465Smp t = glob_all_or_error(t); 2203316958Sdchagin cleanup_push(t, blk_cleanup); 2204167465Smp if ((!srcfile(file, 0, hflg, t)) && (!hflg) && (!bequiet)) 2205167465Smp stderror(ERR_SYSTEM, file, strerror(errno)); 2206167465Smp cleanup_until(file); 220759243Sobrien} 220859243Sobrien 220959243Sobrien/* 221059243Sobrien * Check for mail. 221159243Sobrien * If we are a login shell, then we don't want to tell 221259243Sobrien * about any mail file unless its been modified 221359243Sobrien * after the time we started. 221459243Sobrien * This prevents us from telling the user things he already 221559243Sobrien * knows, since the login program insists on saying 221659243Sobrien * "You have mail." 221759243Sobrien */ 221859243Sobrien 221959243Sobrien/* 222059243Sobrien * The AMS version. 222159243Sobrien * This version checks if the file is a directory, and if so, 222259243Sobrien * tells you the number of files in it, otherwise do the old thang. 222359243Sobrien * The magic "+1" in the time calculation is to compensate for 222459243Sobrien * an AFS bug where directory mtimes are set to 1 second in 222559243Sobrien * the future. 222659243Sobrien */ 222759243Sobrien 222859243Sobrienstatic void 2229167465Smpmailchk(void) 223059243Sobrien{ 2231145479Smp struct varent *v; 2232145479Smp Char **vp; 223359243Sobrien time_t t; 223459243Sobrien int intvl, cnt; 223559243Sobrien struct stat stb; 2236145479Smp int new; 223759243Sobrien 223859243Sobrien v = adrof(STRmail); 2239100616Smp if (v == NULL || v->vec == NULL) 224059243Sobrien return; 224159243Sobrien (void) time(&t); 224259243Sobrien vp = v->vec; 224359243Sobrien cnt = blklen(vp); 224459243Sobrien intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 224559243Sobrien if (intvl < 1) 224659243Sobrien intvl = 1; 224759243Sobrien if (chktim + intvl > t) 224859243Sobrien return; 224959243Sobrien for (; *vp; vp++) { 225059243Sobrien char *filename = short2str(*vp); 225159243Sobrien char *mboxdir = filename; 225259243Sobrien 225359243Sobrien if (stat(filename, &stb) < 0) 225459243Sobrien continue; 225559243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 225659243Sobrien new = stb.st_mtime > time0.tv_sec; 225759243Sobrien#else 225859415Sobrien new = stb.st_mtime > seconds0; 225959243Sobrien#endif 226059243Sobrien if (S_ISDIR(stb.st_mode)) { 226159243Sobrien DIR *mailbox; 226259243Sobrien int mailcount = 0; 2263167465Smp char *tempfilename; 226459243Sobrien struct stat stc; 226559243Sobrien 2266167465Smp tempfilename = xasprintf("%s/new", filename); 226759243Sobrien 226859243Sobrien if (stat(tempfilename, &stc) != -1 && S_ISDIR(stc.st_mode)) { 226959243Sobrien /* 227059243Sobrien * "filename/new" exists and is a directory; you are 227159243Sobrien * using Qmail. 227259243Sobrien */ 227359243Sobrien stb = stc; 227459243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 227559243Sobrien new = stb.st_mtime > time0.tv_sec; 227659243Sobrien#else 227759415Sobrien new = stb.st_mtime > seconds0; 227859243Sobrien#endif 227959243Sobrien mboxdir = tempfilename; 228059243Sobrien } 228159243Sobrien 2282167465Smp if (stb.st_mtime <= chktim + 1 || (loginsh && !new)) { 2283167465Smp xfree(tempfilename); 228459243Sobrien continue; 2285167465Smp } 228659243Sobrien 2287167465Smp mailbox = opendir(mboxdir); 2288167465Smp xfree(tempfilename); 2289167465Smp if (mailbox == NULL) 229059243Sobrien continue; 229159243Sobrien 229259243Sobrien /* skip . and .. */ 2293231990Smp if (!readdir(mailbox) || !readdir(mailbox)) { 2294231990Smp (void)closedir(mailbox); 229559243Sobrien continue; 2296231990Smp } 229759243Sobrien 229859243Sobrien while (readdir(mailbox)) 229959243Sobrien mailcount++; 230059243Sobrien 2301231990Smp (void)closedir(mailbox); 230259243Sobrien if (mailcount == 0) 230359243Sobrien continue; 230459243Sobrien 230559243Sobrien if (cnt == 1) 230659243Sobrien xprintf(CGETS(11, 3, "You have %d mail messages.\n"), 230759243Sobrien mailcount); 230859243Sobrien else 230959243Sobrien xprintf(CGETS(11, 4, "You have %d mail messages in %s.\n"), 231059243Sobrien mailcount, filename); 231159243Sobrien } 231259243Sobrien else { 2313145479Smp char *type; 2314145479Smp 2315231990Smp if (stb.st_size == 0 || stb.st_atime >= stb.st_mtime || 231659243Sobrien (stb.st_atime <= chktim && stb.st_mtime <= chktim) || 231759243Sobrien (loginsh && !new)) 231859243Sobrien continue; 2319145479Smp type = strsave(new ? CGETS(11, 6, "new ") : ""); 2320167465Smp cleanup_push(type, xfree); 232159243Sobrien if (cnt == 1) 2322145479Smp xprintf(CGETS(11, 5, "You have %smail.\n"), type); 232359243Sobrien else 2324145479Smp xprintf(CGETS(11, 7, "You have %smail in %s.\n"), type, filename); 2325167465Smp cleanup_until(type); 232659243Sobrien } 232759243Sobrien } 232859243Sobrien chktim = t; 232959243Sobrien} 233059243Sobrien 233159243Sobrien/* 233259243Sobrien * Extract a home directory from the password file 233359243Sobrien * The argument points to a buffer where the name of the 233459243Sobrien * user whose home directory is sought is currently. 2335167465Smp * We return home directory of the user, or NULL. 233659243Sobrien */ 2337167465SmpChar * 2338167465Smpgethdir(const Char *home) 233959243Sobrien{ 234059243Sobrien Char *h; 234159243Sobrien 234259243Sobrien /* 234359243Sobrien * Is it us? 234459243Sobrien */ 234559243Sobrien if (*home == '\0') { 2346167465Smp if ((h = varval(STRhome)) != STRNULL) 2347167465Smp return Strsave(h); 234859243Sobrien else 2349167465Smp return NULL; 235059243Sobrien } 235159243Sobrien 235259243Sobrien /* 235359243Sobrien * Look in the cache 235459243Sobrien */ 235559243Sobrien if ((h = gettilde(home)) == NULL) 2356167465Smp return NULL; 2357167465Smp else 2358167465Smp return Strsave(h); 235959243Sobrien} 236059243Sobrien 236159243Sobrien/* 236259243Sobrien * Move the initial descriptors to their eventual 236359243Sobrien * resting places, closing all other units. 236459243Sobrien */ 236559243Sobrienvoid 2366167465Smpinitdesc(void) 236759243Sobrien{ 236859243Sobrien#ifdef NLS_BUGS 236959243Sobrien#ifdef NLS_CATALOGS 2370145479Smp nlsclose(); 237159243Sobrien#endif /* NLS_CATALOGS */ 237259243Sobrien#endif /* NLS_BUGS */ 237359243Sobrien 237459243Sobrien 237559243Sobrien didfds = 0; /* 0, 1, 2 aren't set up */ 237659243Sobrien (void) close_on_exec(SHIN = dcopy(0, FSHIN), 1); 237759243Sobrien (void) close_on_exec(SHOUT = dcopy(1, FSHOUT), 1); 237859243Sobrien (void) close_on_exec(SHDIAG = dcopy(2, FSHDIAG), 1); 237959243Sobrien (void) close_on_exec(OLDSTD = dcopy(SHIN, FOLDSTD), 1); 238059243Sobrien#ifndef CLOSE_ON_EXEC 238159243Sobrien didcch = 0; /* Havent closed for child */ 238259243Sobrien#endif /* CLOSE_ON_EXEC */ 2383231990Smp if (SHDIAG >= 0) 2384231990Smp isdiagatty = isatty(SHDIAG); 2385231990Smp else 2386231990Smp isdiagatty = 0; 2387231990Smp if (SHDIAG >= 0) 2388231990Smp isoutatty = isatty(SHOUT); 2389231990Smp else 2390231990Smp isoutatty = 0; 239159243Sobrien#ifdef NLS_BUGS 239259243Sobrien#ifdef NLS_CATALOGS 239359243Sobrien nlsinit(); 239459243Sobrien#endif /* NLS_CATALOGS */ 239559243Sobrien#endif /* NLS_BUGS */ 239659243Sobrien} 239759243Sobrien 239859243Sobrien 239959243Sobrienvoid 240059243Sobrien#ifdef PROF 2401167465Smpdone(int i) 240259243Sobrien#else 2403167465Smpxexit(int i) 240459243Sobrien#endif 240559243Sobrien{ 240659243Sobrien#ifdef TESLA 240759243Sobrien if (loginsh && do_logout) { 240859243Sobrien /* this is to send hangup signal to the develcon */ 240959243Sobrien /* we toggle DTR. clear dtr - sleep 1 - set dtr */ 241059243Sobrien /* ioctl will return ENOTTY for pty's but we ignore it */ 241159243Sobrien /* exitstat will run after disconnect */ 241259243Sobrien /* we sleep for 2 seconds to let things happen in */ 241359243Sobrien /* .logout and rechist() */ 241459243Sobrien#ifdef TIOCCDTR 241559243Sobrien (void) sleep(2); 241659243Sobrien (void) ioctl(FSHTTY, TIOCCDTR, NULL); 241759243Sobrien (void) sleep(1); 241859243Sobrien (void) ioctl(FSHTTY, TIOCSDTR, NULL); 241959243Sobrien#endif /* TIOCCDTR */ 242059243Sobrien } 242159243Sobrien#endif /* TESLA */ 242259243Sobrien 242359243Sobrien { 242459243Sobrien struct process *pp, *np; 2425231990Smp pid_t mypid = getpid(); 242659243Sobrien /* Kill all processes marked for hup'ing */ 242759243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 242859243Sobrien np = pp; 2429231990Smp do 2430231990Smp if ((np->p_flags & PHUP) && np->p_jobid != shpgrp && 2431231990Smp np->p_parentid == mypid) { 243259243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 243359243Sobrien /* In case the job was suspended... */ 243459243Sobrien#ifdef SIGCONT 243559243Sobrien (void) killpg(np->p_jobid, SIGCONT); 243659243Sobrien#endif 243759243Sobrien break; 243859243Sobrien } 243959243Sobrien } 244059243Sobrien while ((np = np->p_friends) != pp); 244159243Sobrien } 244259243Sobrien } 244359243Sobrien untty(); 244459243Sobrien#ifdef NLS_CATALOGS 244559243Sobrien /* 244659243Sobrien * We need to call catclose, because SVR4 leaves symlinks behind otherwise 244759243Sobrien * in the catalog directories. We cannot close on a vforked() child, 244859243Sobrien * because messages will stop working on the parent too. 244959243Sobrien */ 245059243Sobrien if (child == 0) 2451145479Smp nlsclose(); 245259243Sobrien#endif /* NLS_CATALOGS */ 245369408Sache#ifdef WINNT_NATIVE 245459243Sobrien nt_cleanup(); 245569408Sache#endif /* WINNT_NATIVE */ 245659243Sobrien _exit(i); 245759243Sobrien} 245859243Sobrien 245959243Sobrien#ifndef _PATH_DEFPATH 246059243Sobrienstatic Char ** 2461167465Smpdefaultpath(void) 246259243Sobrien{ 246359243Sobrien char *ptr; 246459243Sobrien Char **blk, **blkp; 246559243Sobrien struct stat stb; 246659243Sobrien 2467167465Smp blkp = blk = xmalloc(sizeof(Char *) * 10); 246859243Sobrien 246959243Sobrien#ifndef NODOT 247059243Sobrien# ifndef DOTLAST 247159243Sobrien *blkp++ = Strsave(STRdot); 247259243Sobrien# endif 247359243Sobrien#endif 247459243Sobrien 247559243Sobrien#define DIRAPPEND(a) \ 247659243Sobrien if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \ 247759243Sobrien *blkp++ = SAVE(ptr) 247859243Sobrien 247959243Sobrien#ifdef _PATH_LOCAL 248059243Sobrien DIRAPPEND(_PATH_LOCAL); 248159243Sobrien#endif 248259243Sobrien 248359243Sobrien#ifdef _PATH_USRUCB 248459243Sobrien DIRAPPEND(_PATH_USRUCB); 248559243Sobrien#endif 248659243Sobrien 248759243Sobrien#ifdef _PATH_USRBSD 248859243Sobrien DIRAPPEND(_PATH_USRBSD); 248959243Sobrien#endif 249059243Sobrien 249159243Sobrien#ifdef _PATH_BIN 249259243Sobrien DIRAPPEND(_PATH_BIN); 249359243Sobrien#endif 249459243Sobrien 249559243Sobrien#ifdef _PATH_USRBIN 249659243Sobrien DIRAPPEND(_PATH_USRBIN); 249759243Sobrien#endif 249859243Sobrien 249959243Sobrien#undef DIRAPPEND 250059243Sobrien 250159243Sobrien#ifndef NODOT 250259243Sobrien# ifdef DOTLAST 250359243Sobrien *blkp++ = Strsave(STRdot); 250459243Sobrien# endif 250559243Sobrien#endif 250659243Sobrien *blkp = NULL; 250759243Sobrien return (blk); 250859243Sobrien} 250959243Sobrien#endif 251059243Sobrien 251159243Sobrienstatic void 2512167465Smprecord(void) 251359243Sobrien{ 251459243Sobrien if (!fast) { 251559243Sobrien recdirs(NULL, adrof(STRsavedirs) != NULL); 251659243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 251759243Sobrien } 2518231990Smp displayHistStats("Exiting"); /* no-op unless DEBUG_HIST */ 251959243Sobrien} 2520195609Smp 2521195609Smp/* 2522195609Smp * Grab the tty repeatedly, and give up if we are not in the correct 2523195609Smp * tty process group. 2524195609Smp */ 2525195609Smpint 2526195609Smpgrabpgrp(int fd, pid_t desired) 2527195609Smp{ 2528195609Smp struct sigaction old; 2529195609Smp pid_t pgrp; 2530195609Smp size_t i; 2531195609Smp 2532195609Smp for (i = 0; i < 100; i++) { 2533195609Smp if ((pgrp = tcgetpgrp(fd)) == -1) 2534195609Smp return -1; 2535195609Smp if (pgrp == desired) 2536195609Smp return 0; 2537195609Smp (void)sigaction(SIGTTIN, NULL, &old); 2538195609Smp (void)signal(SIGTTIN, SIG_DFL); 2539195609Smp (void)kill(0, SIGTTIN); 2540195609Smp (void)sigaction(SIGTTIN, &old, NULL); 2541195609Smp } 2542195609Smp errno = EPERM; 2543195609Smp return -1; 2544195609Smp} 2545