sh.c revision 197812
1195609Smp/* $Header: /p/tcsh/cvsroot/tcsh/sh.c,v 3.145 2009/06/25 21:15:37 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 42195609SmpRCSID("$tcsh: sh.c,v 3.145 2009/06/25 21:15:37 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 8159243Sobrienjmp_buf_t reslab INIT_ZERO_STRUCT; 8259243Sobrien 8359243Sobrienstatic const char tcshstr[] = "tcsh"; 8459243Sobrien 85167465Smpstruct sigaction parintr; /* Parents interrupt catch */ 86167465Smpstruct sigaction parterm; /* Parents terminate catch */ 8759243Sobrien 8859243Sobrien#ifdef TESLA 8959243Sobrienint do_logout = 0; 9059243Sobrien#endif /* TESLA */ 9159243Sobrien 9259243Sobrien 93145479Smpint use_fork = 0; /* use fork() instead of vfork()? */ 9459243Sobrien 9559243Sobrien/* 9659243Sobrien * Magic pointer values. Used to specify other invalid conditions aside 9759243Sobrien * from null. 9859243Sobrien */ 9959243Sobrienstatic Char INVCHAR; 10059243SobrienChar *INVPTR = &INVCHAR; 10159243SobrienChar **INVPPTR = &INVPTR; 10259243Sobrien 103167465Smpstatic int fast = 0; 104145479Smpstatic int mflag = 0; 105145479Smpstatic int prompt = 1; 106145479Smpint enterhist = 0; 107145479Smpint tellwhat = 0; 10859243Sobrientime_t t_period; 10959243SobrienChar *ffile = NULL; 110145479Smpint dolzero = 0; 11159243Sobrienint insource = 0; 11269408Sacheint exitset = 0; 11359243Sobrienstatic time_t chktim; /* Time mail last checked */ 11459243Sobrienchar *progname; 11559243Sobrienint tcsh; 11659243Sobrien 11759243Sobrien/* 11859243Sobrien * This preserves the input state of the shell. It is used by 11959243Sobrien * st_save and st_restore to manupulate shell state. 12059243Sobrien */ 12159243Sobrienstruct saved_state { 12259243Sobrien int insource; 123100616Smp int OLDSTD; 12459243Sobrien int SHIN; 125100616Smp int SHOUT; 126100616Smp int SHDIAG; 12759243Sobrien int intty; 12859243Sobrien struct whyle *whyles; 12959243Sobrien Char *gointr; 13059243Sobrien Char *arginp; 13159243Sobrien Char *evalp; 13259243Sobrien Char **evalvec; 13359243Sobrien Char *alvecp; 13459243Sobrien Char **alvec; 13559243Sobrien int onelflg; 136145479Smp int enterhist; 13759243Sobrien Char **argv; 138167465Smp Char **av; 13959243Sobrien Char HIST; 140145479Smp int cantell; 14159243Sobrien struct Bin B; 142195609Smp int justpr; 14359243Sobrien}; 14459243Sobrien 145167465Smpstatic int srccat (Char *, Char *); 14683098Smp#ifndef WINNT_NATIVE 147167465Smpstatic int srcfile (const char *, int, int, Char **); 14883098Smp#else 149167465Smpint srcfile (const char *, int, int, Char **); 15083098Smp#endif /*WINNT_NATIVE*/ 151167465Smpstatic void srcunit (int, int, int, Char **); 152167465Smpstatic void mailchk (void); 15359243Sobrien#ifndef _PATH_DEFPATH 154167465Smpstatic Char **defaultpath (void); 15559243Sobrien#endif 156167465Smpstatic void record (void); 157167465Smpstatic void st_save (struct saved_state *, int, int, 158167465Smp Char **, Char **); 159167465Smpstatic void st_restore (void *); 16059243Sobrien 161167465Smp int main (int, char **); 16259243Sobrien 16359243Sobrienint 164167465Smpmain(int argc, char **argv) 16559243Sobrien{ 166167465Smp int batch = 0; 167167465Smp volatile int nexececho = 0; 168167465Smp int nofile = 0; 169167465Smp volatile int nverbose = 0; 170167465Smp volatile int rdirs = 0; 171167465Smp int quitit = 0; 172145479Smp Char *cp; 17359243Sobrien#ifdef AUTOLOGOUT 174145479Smp Char *cp2; 17559243Sobrien#endif 176145479Smp char *tcp, *ttyn; 177167465Smp int f, reenter; 178145479Smp char **tempv; 179131962Smp int osetintr; 180167465Smp struct sigaction oparintr; 18159243Sobrien 18269408Sache#ifdef WINNT_NATIVE 18359243Sobrien nt_init(); 18469408Sache#endif /* WINNT_NATIVE */ 18559243Sobrien#if defined(NLS_CATALOGS) && defined(LC_MESSAGES) 18659243Sobrien (void) setlocale(LC_MESSAGES, ""); 18759243Sobrien#endif /* NLS_CATALOGS && LC_MESSAGES */ 18859243Sobrien 18959243Sobrien#ifdef NLS 19059243Sobrien# ifdef LC_CTYPE 19159243Sobrien (void) setlocale(LC_CTYPE, ""); /* for iscntrl */ 19259243Sobrien# endif /* LC_CTYPE */ 19359243Sobrien#endif /* NLS */ 19459243Sobrien 19559243Sobrien nlsinit(); 19659243Sobrien 19759243Sobrien#ifdef MALLOC_TRACE 198167465Smp mal_setstatsfile(fdopen(dmove(xopen("/tmp/tcsh.trace", 199145479Smp O_WRONLY|O_CREAT|O_LARGEFILE, 0666), 25), "w")); 200145479Smp mal_trace(1); 20159243Sobrien#endif /* MALLOC_TRACE */ 20259243Sobrien 20359243Sobrien#if !(defined(BSDTIMES) || defined(_SEQUENT_)) && defined(POSIX) 20459243Sobrien# ifdef _SC_CLK_TCK 20559243Sobrien clk_tck = (clock_t) sysconf(_SC_CLK_TCK); 20659243Sobrien# else /* ! _SC_CLK_TCK */ 20759243Sobrien# ifdef CLK_TCK 20859243Sobrien clk_tck = CLK_TCK; 20959243Sobrien# else /* !CLK_TCK */ 21059243Sobrien clk_tck = HZ; 21159243Sobrien# endif /* CLK_TCK */ 21259243Sobrien# endif /* _SC_CLK_TCK */ 21359243Sobrien#endif /* !BSDTIMES && POSIX */ 21459243Sobrien 21559243Sobrien settimes(); /* Immed. estab. timing base */ 21659243Sobrien#ifdef TESLA 21759243Sobrien do_logout = 0; 21859243Sobrien#endif /* TESLA */ 21959243Sobrien 22059243Sobrien /* 22159243Sobrien * Make sure we have 0, 1, 2 open 22259243Sobrien * Otherwise `` jobs will not work... (From knaff@poly.polytechnique.fr) 22359243Sobrien */ 22459243Sobrien { 22559243Sobrien do 226167465Smp if ((f = xopen(_PATH_DEVNULL, O_RDONLY|O_LARGEFILE)) == -1 && 227167465Smp (f = xopen("/", O_RDONLY|O_LARGEFILE)) == -1) 22859243Sobrien exit(1); 22959243Sobrien while (f < 3); 230167465Smp xclose(f); 23159243Sobrien } 23259243Sobrien 23359243Sobrien osinit(); /* Os dependent initialization */ 23459243Sobrien 23559243Sobrien 23659243Sobrien { 23759243Sobrien char *t; 23859243Sobrien 23959243Sobrien t = strrchr(argv[0], '/'); 24069408Sache#ifdef WINNT_NATIVE 24159243Sobrien { 24259243Sobrien char *s = strrchr(argv[0], '\\'); 24359243Sobrien if (s) 24459243Sobrien t = s; 24559243Sobrien } 24669408Sache#endif /* WINNT_NATIVE */ 24759243Sobrien t = t ? t + 1 : argv[0]; 24859243Sobrien if (*t == '-') t++; 24959243Sobrien progname = strsave((t && *t) ? t : tcshstr); /* never want a null */ 25059243Sobrien tcsh = strcmp(progname, tcshstr) == 0; 25159243Sobrien } 25259243Sobrien 25359243Sobrien /* 25459243Sobrien * Initialize non constant strings 25559243Sobrien */ 25659243Sobrien#ifdef _PATH_BSHELL 25759243Sobrien STR_BSHELL = SAVE(_PATH_BSHELL); 25859243Sobrien#endif 25959243Sobrien#ifdef _PATH_TCSHELL 26059243Sobrien STR_SHELLPATH = SAVE(_PATH_TCSHELL); 26159243Sobrien#else 26259243Sobrien# ifdef _PATH_CSHELL 26359243Sobrien STR_SHELLPATH = SAVE(_PATH_CSHELL); 26459243Sobrien# endif 26559243Sobrien#endif 26659243Sobrien STR_environ = blk2short(environ); 26759243Sobrien environ = short2blk(STR_environ); /* So that we can free it */ 26859243Sobrien STR_WORD_CHARS = SAVE(WORD_CHARS); 26959243Sobrien 27059243Sobrien HIST = '!'; 27159243Sobrien HISTSUB = '^'; 27259243Sobrien PRCH = '>'; 27359243Sobrien PRCHROOT = '#'; 27459243Sobrien word_chars = STR_WORD_CHARS; 27559243Sobrien bslash_quote = 0; /* PWP: do tcsh-style backslash quoting? */ 27659243Sobrien 27759243Sobrien /* Default history size to 100 */ 278167465Smp setcopy(STRhistory, str2short("100"), VAR_READWRITE); 27959243Sobrien 28059243Sobrien tempv = argv; 28159243Sobrien ffile = SAVE(tempv[0]); 28259243Sobrien dolzero = 0; 28359243Sobrien if (eq(ffile, STRaout)) /* A.out's are quittable */ 28459243Sobrien quitit = 1; 28559243Sobrien uid = getuid(); 28659243Sobrien gid = getgid(); 28759243Sobrien euid = geteuid(); 28859243Sobrien egid = getegid(); 28959243Sobrien /* 29059243Sobrien * We are a login shell if: 1. we were invoked as -<something> with 29159243Sobrien * optional arguments 2. or we were invoked only with the -l flag 29259243Sobrien */ 29359243Sobrien loginsh = (**tempv == '-') || (argc == 2 && 29459243Sobrien tempv[1][0] == '-' && tempv[1][1] == 'l' && 29559243Sobrien tempv[1][2] == '\0'); 29659243Sobrien#ifdef _VMS_POSIX 29759243Sobrien /* No better way to find if we are a login shell */ 29859243Sobrien if (!loginsh) { 29959243Sobrien loginsh = (argc == 1 && getppid() == 1); 30059243Sobrien **tempv = '-'; /* Avoid giving VMS an acidic stomach */ 30159243Sobrien } 30259243Sobrien#endif /* _VMS_POSIX */ 30359243Sobrien 30459243Sobrien if (loginsh && **tempv != '-') { 305167465Smp char *argv0; 306167465Smp 30759243Sobrien /* 30859243Sobrien * Mangle the argv space 30959243Sobrien */ 31059243Sobrien tempv[1][0] = '\0'; 31159243Sobrien tempv[1][1] = '\0'; 31259243Sobrien tempv[1] = NULL; 313167465Smp argv0 = strspl("-", *tempv); 314167465Smp *tempv = argv0; 31559243Sobrien argc--; 31659243Sobrien } 31759243Sobrien if (loginsh) { 31859243Sobrien (void) time(&chktim); 319167465Smp setNS(STRloginsh); 32059243Sobrien } 32159243Sobrien 32259243Sobrien AsciiOnly = 1; 32359243Sobrien NoNLSRebind = getenv("NOREBIND") != NULL; 32459243Sobrien#ifdef NLS 32559243Sobrien# ifdef SETLOCALEBUG 32659243Sobrien dont_free = 1; 32759243Sobrien# endif /* SETLOCALEBUG */ 32859243Sobrien (void) setlocale(LC_ALL, ""); 32959243Sobrien# ifdef LC_COLLATE 33059243Sobrien (void) setlocale(LC_COLLATE, ""); 33159243Sobrien# endif 33259243Sobrien# ifdef SETLOCALEBUG 33359243Sobrien dont_free = 0; 33459243Sobrien# endif /* SETLOCALEBUG */ 33559243Sobrien# ifdef STRCOLLBUG 33659243Sobrien fix_strcoll_bug(); 33759243Sobrien# endif /* STRCOLLBUG */ 33859243Sobrien 33959243Sobrien { 34059243Sobrien int k; 34159243Sobrien 342167465Smp for (k = 0200; k <= 0377 && !Isprint(CTL_ESC(k)); k++) 34359243Sobrien continue; 344145479Smp AsciiOnly = MB_CUR_MAX == 1 && k > 0377; 34559243Sobrien } 34659243Sobrien#else 34759243Sobrien AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL; 34859243Sobrien#endif /* NLS */ 34959243Sobrien if (MapsAreInited && !NLSMapsAreInited) 35059243Sobrien ed_InitNLSMaps(); 35159243Sobrien ResetArrowKeys(); 35259243Sobrien 35359243Sobrien /* 35459243Sobrien * Initialize for periodic command intervals. Also, initialize the dummy 35559243Sobrien * tty list for login-watch. 35659243Sobrien */ 35759243Sobrien (void) time(&t_period); 35859243Sobrien#ifndef HAVENOUTMP 35959243Sobrien initwatch(); 36059243Sobrien#endif /* !HAVENOUTMP */ 36159243Sobrien 36259243Sobrien#if defined(alliant) 36359243Sobrien /* 36459243Sobrien * From: Jim Pace <jdp@research.att.com> 36559243Sobrien * tcsh does not work properly on the alliants through an rlogin session. 36659243Sobrien * The shell generally hangs. Also, reference to the controlling terminal 36759243Sobrien * does not work ( ie: echo foo > /dev/tty ). 36859243Sobrien * 36959243Sobrien * A security feature was added to rlogind affecting FX/80's Concentrix 37059243Sobrien * from revision 5.5.xx upwards (through 5.7 where this fix was implemented) 37159243Sobrien * This security change also affects the FX/2800 series. 37259243Sobrien * The security change to rlogind requires the process group of an rlogin 37359243Sobrien * session become disassociated with the tty in rlogind. 37459243Sobrien * 37559243Sobrien * The changes needed are: 37659243Sobrien * 1. set the process group 37759243Sobrien * 2. reenable the control terminal 37859243Sobrien */ 37959243Sobrien if (loginsh && isatty(SHIN)) { 380167465Smp ttyn = ttyname(SHIN); 381167465Smp xclose(SHIN); 382167465Smp SHIN = xopen(ttyn, O_RDWR|O_LARGEFILE); 38359243Sobrien shpgrp = getpid(); 38459243Sobrien (void) ioctl (SHIN, TIOCSPGRP, (ioctl_t) &shpgrp); 38559243Sobrien (void) setpgid(0, shpgrp); 38659243Sobrien } 38759243Sobrien#endif /* alliant */ 38859243Sobrien 38959243Sobrien /* 39059243Sobrien * Move the descriptors to safe places. The variable didfds is 0 while we 39159243Sobrien * have only FSH* to work with. When didfds is true, we have 0,1,2 and 39259243Sobrien * prefer to use these. 39359243Sobrien */ 39459243Sobrien initdesc(); 39559243Sobrien 39659243Sobrien /* 39759243Sobrien * Get and set the tty now 39859243Sobrien */ 39959243Sobrien if ((ttyn = ttyname(SHIN)) != NULL) { 40059243Sobrien /* 40159243Sobrien * Could use rindex to get rid of other possible path components, but 40259243Sobrien * hpux preserves the subdirectory /pty/ when storing the tty name in 40359243Sobrien * utmp, so we keep it too. 40459243Sobrien */ 40559243Sobrien if (strncmp(ttyn, "/dev/", 5) == 0) 406167465Smp setv(STRtty, cp = SAVE(ttyn + 5), VAR_READWRITE); 40759243Sobrien else 408167465Smp setv(STRtty, cp = SAVE(ttyn), VAR_READWRITE); 40959243Sobrien } 41059243Sobrien else 411167465Smp setv(STRtty, cp = SAVE(""), VAR_READWRITE); 41259243Sobrien /* 41359243Sobrien * Initialize the shell variables. ARGV and PROMPT are initialized later. 41459243Sobrien * STATUS is also munged in several places. CHILD is munged when 41559243Sobrien * forking/waiting 41659243Sobrien */ 41759243Sobrien 41859243Sobrien /* 41959243Sobrien * 7-10-87 Paul Placeway autologout should be set ONLY on login shells and 42059243Sobrien * on shells running as root. Out of these, autologout should NOT be set 42159243Sobrien * for any psudo-terminals (this catches most window systems) and not for 42259243Sobrien * any terminal running X windows. 42359243Sobrien * 42459243Sobrien * At Ohio State, we have had problems with a user having his X session 42559243Sobrien * drop out from under him (on a Sun) because the shell in his master 42659243Sobrien * xterm timed out and exited. 42759243Sobrien * 42859243Sobrien * Really, this should be done with a program external to the shell, that 42959243Sobrien * watches for no activity (and NO running programs, such as dump) on a 43059243Sobrien * terminal for a long peroid of time, and then SIGHUPS the shell on that 43159243Sobrien * terminal. 43259243Sobrien * 43359243Sobrien * bugfix by Rich Salz <rsalz@PINEAPPLE.BBN.COM>: For root rsh things 43459243Sobrien * allways first check to see if loginsh or really root, then do things 43559243Sobrien * with ttyname() 43659243Sobrien * 43759243Sobrien * Also by Jean-Francois Lamy <lamy%ai.toronto.edu@RELAY.CS.NET>: check the 43859243Sobrien * value of cp before using it! ("root can rsh too") 43959243Sobrien * 44059243Sobrien * PWP: keep the nested ifs; the order of the tests matters and a good 44159243Sobrien * (smart) C compiler might re-arange things wrong. 44259243Sobrien */ 44359243Sobrien#ifdef AUTOLOGOUT 44459243Sobrien# ifdef convex 445167465Smp if (uid == 0) 44659243Sobrien /* root always has a 15 minute autologout */ 447167465Smp setcopy(STRautologout, STRrootdefautologout, VAR_READWRITE); 44859243Sobrien else 44959243Sobrien if (loginsh) 45059243Sobrien /* users get autologout set to 0 */ 451167465Smp setcopy(STRautologout, STR0, VAR_READWRITE); 45259243Sobrien# else /* convex */ 45359243Sobrien if (loginsh || (uid == 0)) { 45459243Sobrien if (*cp) { 45559243Sobrien /* only for login shells or root and we must have a tty */ 45659243Sobrien if ((cp2 = Strrchr(cp, (Char) '/')) != NULL) { 457172665Smp cp2 = cp2 + 1; 45859243Sobrien } 45959243Sobrien else 46059243Sobrien cp2 = cp; 46159243Sobrien if (!(((Strncmp(cp2, STRtty, 3) == 0) && Isalpha(cp2[3])) || 462184072Sru Strstr(cp, STRptssl) != NULL)) { 46359243Sobrien if (getenv("DISPLAY") == NULL) { 46459243Sobrien /* NOT on X window shells */ 465167465Smp setcopy(STRautologout, STRdefautologout, VAR_READWRITE); 46659243Sobrien } 46759243Sobrien } 46859243Sobrien } 46959243Sobrien } 47059243Sobrien# endif /* convex */ 47159243Sobrien#endif /* AUTOLOGOUT */ 47259243Sobrien 473167465Smp sigset_interrupting(SIGALRM, queue_alrmcatch); 47459243Sobrien 475167465Smp setcopy(STRstatus, STR0, VAR_READWRITE); 47659243Sobrien 47759243Sobrien /* 478100616Smp * get and set machine specific environment variables 47959243Sobrien */ 48059243Sobrien getmachine(); 48159243Sobrien 48259243Sobrien 48359243Sobrien /* 48459243Sobrien * Publish the selected echo style 48559243Sobrien */ 486100616Smp#if ECHO_STYLE != BSD_ECHO 487100616Smp if (tcsh) { 488100616Smp# if ECHO_STYLE == NONE_ECHO 489167465Smp setcopy(STRecho_style, STRnone, VAR_READWRITE); 490100616Smp# endif /* ECHO_STYLE == NONE_ECHO */ 491100616Smp# if ECHO_STYLE == SYSV_ECHO 492167465Smp setcopy(STRecho_style, STRsysv, VAR_READWRITE); 493100616Smp# endif /* ECHO_STYLE == SYSV_ECHO */ 494100616Smp# if ECHO_STYLE == BOTH_ECHO 495167465Smp setcopy(STRecho_style, STRboth, VAR_READWRITE); 496100616Smp# endif /* ECHO_STYLE == BOTH_ECHO */ 497100616Smp } else 498100616Smp#endif /* ECHO_STYLE != BSD_ECHO */ 499167465Smp setcopy(STRecho_style, STRbsd, VAR_READWRITE); 50059243Sobrien 50159243Sobrien /* 50259243Sobrien * increment the shell level. 50359243Sobrien */ 50459243Sobrien shlvl(1); 50559243Sobrien 506167465Smp if ((tcp = getenv("HOME")) != NULL) 507167465Smp cp = quote(SAVE(tcp)); 508167465Smp else 50959243Sobrien cp = NULL; 51073393Skris 51159243Sobrien if (cp == NULL) 51259243Sobrien fast = 1; /* No home -> can't read scripts */ 51359243Sobrien else 514167465Smp setv(STRhome, cp, VAR_READWRITE); 51573393Skris 51659243Sobrien dinit(cp); /* dinit thinks that HOME == cwd in a login 51759243Sobrien * shell */ 51859243Sobrien /* 51959243Sobrien * Grab other useful things from the environment. Should we grab 52059243Sobrien * everything?? 52159243Sobrien */ 52259243Sobrien { 52359243Sobrien char *cln, *cus, *cgr; 52459243Sobrien struct passwd *pw; 52559243Sobrien struct group *gr; 52659243Sobrien 52759243Sobrien 52859243Sobrien#ifdef apollo 52959243Sobrien int oid = getoid(); 53059243Sobrien 531167465Smp setv(STRoid, Itoa(oid, 0, 0), VAR_READWRITE); 53259243Sobrien#endif /* apollo */ 53359243Sobrien 534167465Smp setv(STRuid, Itoa(uid, 0, 0), VAR_READWRITE); 53559243Sobrien 536167465Smp setv(STRgid, Itoa(gid, 0, 0), VAR_READWRITE); 53759243Sobrien 53859243Sobrien cln = getenv("LOGNAME"); 53959243Sobrien cus = getenv("USER"); 54059243Sobrien if (cus != NULL) 541167465Smp setv(STRuser, quote(SAVE(cus)), VAR_READWRITE); 54259243Sobrien else if (cln != NULL) 543167465Smp setv(STRuser, quote(SAVE(cln)), VAR_READWRITE); 544167465Smp else if ((pw = xgetpwuid(uid)) == NULL) 545167465Smp setcopy(STRuser, str2short("unknown"), VAR_READWRITE); 54659243Sobrien else 547167465Smp setcopy(STRuser, str2short(pw->pw_name), VAR_READWRITE); 54859243Sobrien if (cln == NULL) 54959243Sobrien tsetenv(STRLOGNAME, varval(STRuser)); 55059243Sobrien if (cus == NULL) 55159243Sobrien tsetenv(STRKUSER, varval(STRuser)); 55259243Sobrien 55359243Sobrien cgr = getenv("GROUP"); 55459243Sobrien if (cgr != NULL) 555167465Smp setv(STRgroup, quote(SAVE(cgr)), VAR_READWRITE); 556167465Smp else if ((gr = xgetgrgid(gid)) == NULL) 557167465Smp setcopy(STRgroup, str2short("unknown"), VAR_READWRITE); 55859243Sobrien else 559167465Smp setcopy(STRgroup, str2short(gr->gr_name), VAR_READWRITE); 56059243Sobrien if (cgr == NULL) 56159243Sobrien tsetenv(STRKGROUP, varval(STRgroup)); 56259243Sobrien } 56359243Sobrien 56459243Sobrien /* 56559243Sobrien * HOST may be wrong, since rexd transports the entire environment on sun 56659243Sobrien * 3.x Just set it again 56759243Sobrien */ 56859243Sobrien { 56959243Sobrien char cbuff[MAXHOSTNAMELEN]; 57059243Sobrien 57159243Sobrien if (gethostname(cbuff, sizeof(cbuff)) >= 0) { 57259243Sobrien cbuff[sizeof(cbuff) - 1] = '\0'; /* just in case */ 57359243Sobrien tsetenv(STRHOST, str2short(cbuff)); 57459243Sobrien } 57559243Sobrien else 57659243Sobrien tsetenv(STRHOST, str2short("unknown")); 57759243Sobrien } 57859243Sobrien 57959243Sobrien 58059243Sobrien#ifdef REMOTEHOST 58159243Sobrien /* 58259243Sobrien * Try to determine the remote host we were logged in from. 58359243Sobrien */ 58459243Sobrien remotehost(); 58559243Sobrien#endif /* REMOTEHOST */ 58659243Sobrien 58759243Sobrien#ifdef apollo 58859243Sobrien if ((tcp = getenv("SYSTYPE")) == NULL) 58959243Sobrien tcp = "bsd4.3"; 59059243Sobrien tsetenv(STRSYSTYPE, quote(str2short(tcp))); 59159243Sobrien#endif /* apollo */ 59259243Sobrien 59359243Sobrien /* 59459243Sobrien * set editing on by default, unless running under Emacs as an inferior 59559243Sobrien * shell. 59659243Sobrien * We try to do this intelligently. If $TERM is available, then it 59759243Sobrien * should determine if we should edit or not. $TERM is preserved 59859243Sobrien * across rlogin sessions, so we will not get confused if we rlogin 59959243Sobrien * under an emacs shell. Another advantage is that if we run an 60059243Sobrien * xterm under an emacs shell, then the $TERM will be set to 60159243Sobrien * xterm, so we are going to want to edit. Unfortunately emacs 60259243Sobrien * does not restore all the tty modes, so xterm is not very well 60359243Sobrien * set up. But this is not the shell's fault. 60459243Sobrien * Also don't edit if $TERM == wm, for when we're running under an ATK app. 60559243Sobrien * Finally, emacs compiled under terminfo, sets the terminal to dumb, 60659243Sobrien * so disable editing for that too. 60759243Sobrien * 60859243Sobrien * Unfortunately, in some cases the initial $TERM setting is "unknown", 60959243Sobrien * "dumb", or "network" which is then changed in the user's startup files. 61059243Sobrien * We fix this by setting noediting here if $TERM is unknown/dumb and 61159243Sobrien * if noediting is set, we switch on editing if $TERM is changed. 61259243Sobrien */ 61359243Sobrien if ((tcp = getenv("TERM")) != NULL) { 614167465Smp setv(STRterm, quote(SAVE(tcp)), VAR_READWRITE); 61559243Sobrien noediting = strcmp(tcp, "unknown") == 0 || strcmp(tcp, "dumb") == 0 || 61659243Sobrien strcmp(tcp, "network") == 0; 61759243Sobrien editing = strcmp(tcp, "emacs") != 0 && strcmp(tcp, "wm") != 0 && 61859243Sobrien !noediting; 61959243Sobrien } 62059243Sobrien else { 62159243Sobrien noediting = 0; 62259243Sobrien editing = ((tcp = getenv("EMACS")) == NULL || strcmp(tcp, "t") != 0); 62359243Sobrien } 62459243Sobrien 62559243Sobrien /* 62659243Sobrien * The 'edit' variable is either set or unset. It doesn't 62759243Sobrien * need a value. Making it 'emacs' might be confusing. 62859243Sobrien */ 62959243Sobrien if (editing) 630167465Smp setNS(STRedit); 63159243Sobrien 63259243Sobrien 63359243Sobrien /* 63459243Sobrien * still more mutability: make the complete routine automatically add the 63559243Sobrien * suffix of file names... 63659243Sobrien */ 637167465Smp setNS(STRaddsuffix); 63859243Sobrien 63959243Sobrien /* 640145479Smp * Compatibility with tcsh >= 6.12 by default 641145479Smp */ 642167465Smp setNS(STRcsubstnonl); 643145479Smp 644145479Smp /* 64583098Smp * Random default kill ring size 64683098Smp */ 647167465Smp setcopy(STRkillring, str2short("30"), VAR_READWRITE); 64883098Smp 64983098Smp /* 65059243Sobrien * Re-initialize path if set in environment 65159243Sobrien */ 65259243Sobrien if ((tcp = getenv("PATH")) == NULL) 65359243Sobrien#ifdef _PATH_DEFPATH 65459243Sobrien importpath(str2short(_PATH_DEFPATH)); 65559243Sobrien#else /* !_PATH_DEFPATH */ 65659243Sobrien setq(STRpath, defaultpath(), &shvhed, VAR_READWRITE); 65759243Sobrien#endif /* _PATH_DEFPATH */ 65859243Sobrien else 65959243Sobrien /* Importpath() allocates memory for the path, and the 66059243Sobrien * returned pointer from SAVE() was discarded, so 66159243Sobrien * this was a memory leak.. (sg) 66259243Sobrien * 66359243Sobrien * importpath(SAVE(tcp)); 66459243Sobrien */ 66559243Sobrien importpath(str2short(tcp)); 66659243Sobrien 66759243Sobrien 66859243Sobrien { 66959243Sobrien /* If the SHELL environment variable ends with "tcsh", set 67059243Sobrien * STRshell to the same path. This is to facilitate using 67159243Sobrien * the executable in environments where the compiled-in 67259243Sobrien * default isn't appropriate (sg). 67359243Sobrien */ 67459243Sobrien 675167465Smp size_t sh_len = 0; 67659243Sobrien 67759243Sobrien if ((tcp = getenv("SHELL")) != NULL) { 67859243Sobrien sh_len = strlen(tcp); 67959243Sobrien if ((sh_len >= 5 && strcmp(tcp + (sh_len - 5), "/tcsh") == 0) || 68059243Sobrien (!tcsh && sh_len >= 4 && strcmp(tcp + (sh_len - 4), "/csh") == 0)) 681167465Smp setv(STRshell, quote(SAVE(tcp)), VAR_READWRITE); 68259243Sobrien else 68359243Sobrien sh_len = 0; 68459243Sobrien } 68559243Sobrien if (sh_len == 0) 686167465Smp setcopy(STRshell, STR_SHELLPATH, VAR_READWRITE); 68759243Sobrien } 68859243Sobrien 689167465Smp#ifdef _OSD_POSIX /* BS2000 needs this variable set to "SHELL" */ 690167465Smp if ((tcp = getenv("PROGRAM_ENVIRONMENT")) == NULL) 691167465Smp tcp = "SHELL"; 692167465Smp tsetenv(STRPROGRAM_ENVIRONMENT, quote(str2short(tcp))); 693167465Smp#endif /* _OSD_POSIX */ 694167465Smp 69559243Sobrien#ifdef COLOR_LS_F 69659243Sobrien if ((tcp = getenv("LS_COLORS")) != NULL) 69759243Sobrien parseLS_COLORS(str2short(tcp)); 69859243Sobrien#endif /* COLOR_LS_F */ 69959243Sobrien 70059243Sobrien doldol = putn((int) getpid()); /* For $$ */ 70169408Sache#ifdef WINNT_NATIVE 70259243Sobrien { 703167465Smp char *tmp; 704167465Smp Char *tmp2; 705167465Smp if ((tmp = getenv("TMP")) != NULL) { 706167465Smp tmp = xasprintf("%s/%s", tmp, "sh"); 707167465Smp tmp2 = SAVE(tmp); 708167465Smp xfree(tmp); 70959243Sobrien } 710167465Smp else { 711167465Smp tmp2 = SAVE(""); 712167465Smp } 713167465Smp shtemp = Strspl(tmp2, doldol); /* For << */ 714167465Smp xfree(tmp2); 715167465Smp } 71669408Sache#else /* !WINNT_NATIVE */ 71759243Sobrien shtemp = Strspl(STRtmpsh, doldol); /* For << */ 71869408Sache#endif /* WINNT_NATIVE */ 71959243Sobrien 72059243Sobrien /* 72159243Sobrien * Record the interrupt states from the parent process. If the parent is 72259243Sobrien * non-interruptible our hand must be forced or we (and our children) won't 72359243Sobrien * be either. Our children inherit termination from our parent. We catch it 72459243Sobrien * only if we are the login shell. 72559243Sobrien */ 726167465Smp sigaction(SIGINT, NULL, &parintr); 727167465Smp sigaction(SIGTERM, NULL, &parterm); 72859243Sobrien 72959243Sobrien 73059243Sobrien#ifdef TCF 73159243Sobrien /* Enable process migration on ourselves and our progeny */ 73259243Sobrien (void) signal(SIGMIGRATE, SIG_DFL); 73359243Sobrien#endif /* TCF */ 73459243Sobrien 73559243Sobrien /* 73669408Sache * dspkanji/dspmbyte autosetting 73769408Sache */ 73869408Sache /* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ 73969408Sache#if defined(DSPMBYTE) 74069408Sache#if defined(NLS) && defined(LC_CTYPE) 74169408Sache if (((tcp = setlocale(LC_CTYPE, NULL)) != NULL || (tcp = getenv("LANG")) != NULL) && !adrof(CHECK_MBYTEVAR)) { 74269408Sache#else 74369408Sache if ((tcp = getenv("LANG")) != NULL && !adrof(CHECK_MBYTEVAR)) { 74469408Sache#endif 74569408Sache autoset_dspmbyte(str2short(tcp)); 74669408Sache } 74769408Sache#if defined(WINNT_NATIVE) 74869408Sache else if (!adrof(CHECK_MBYTEVAR)) 74969408Sache nt_autoset_dspmbyte(); 75069408Sache#endif /* WINNT_NATIVE */ 75169408Sache#endif 75269408Sache 753100616Smp fix_version(); /* publish the shell version */ 754100616Smp 755100616Smp if (argc > 1 && strcmp(argv[1], "--version") == 0) { 756100616Smp xprintf("%S\n", varval(STRversion)); 757100616Smp xexit(0); 758100616Smp } 759145479Smp if (argc > 1 && strcmp(argv[1], "--help") == 0) { 760145479Smp xprintf("%S\n\n", varval(STRversion)); 761195609Smp xprintf("%s", CGETS(11, 8, HELP_STRING)); 762145479Smp xexit(0); 763145479Smp } 76469408Sache /* 76559243Sobrien * Process the arguments. 76659243Sobrien * 76759243Sobrien * Note that processing of -v/-x is actually delayed till after script 76859243Sobrien * processing. 76959243Sobrien * 77059243Sobrien * We set the first character of our name to be '-' if we are a shell 77159243Sobrien * running interruptible commands. Many programs which examine ps'es 77259243Sobrien * use this to filter such shells out. 77359243Sobrien */ 77459243Sobrien argc--, tempv++; 77559243Sobrien while (argc > 0 && (tcp = tempv[0])[0] == '-' && 77659243Sobrien *++tcp != '\0' && !batch) { 77759243Sobrien do 77859243Sobrien switch (*tcp++) { 77959243Sobrien 78059243Sobrien case 0: /* - Interruptible, no prompt */ 78159243Sobrien prompt = 0; 78259243Sobrien setintr = 1; 78359243Sobrien nofile = 1; 78459243Sobrien break; 78559243Sobrien 78659243Sobrien case 'b': /* -b Next arg is input file */ 78759243Sobrien batch = 1; 78859243Sobrien break; 78959243Sobrien 79059243Sobrien case 'c': /* -c Command input from arg */ 79159243Sobrien if (argc == 1) 79259243Sobrien xexit(0); 79359243Sobrien argc--, tempv++; 79459243Sobrien#ifdef M_XENIX 79559243Sobrien /* Xenix Vi bug: 79659243Sobrien it relies on a 7 bit environment (/bin/sh), so it 79759243Sobrien pass ascii arguments with the 8th bit set */ 79859243Sobrien if (!strcmp(argv[0], "sh")) 79959243Sobrien { 80059243Sobrien char *p; 80159243Sobrien 80259243Sobrien for (p = tempv[0]; *p; ++p) 80359243Sobrien *p &= ASCII; 80459243Sobrien } 80559243Sobrien#endif 80659243Sobrien arginp = SAVE(tempv[0]); 80759243Sobrien 80859243Sobrien /* 80959243Sobrien * we put the command into a variable 81059243Sobrien */ 81159243Sobrien if (arginp != NULL) 812167465Smp setv(STRcommand, quote(Strsave(arginp)), VAR_READWRITE); 81359243Sobrien 81459243Sobrien /* 81559243Sobrien * * Give an error on -c arguments that end in * backslash to 81659243Sobrien * ensure that you don't make * nonportable csh scripts. 81759243Sobrien */ 81859243Sobrien { 819145479Smp int count; 82059243Sobrien 821167465Smp cp = Strend(arginp); 82259243Sobrien count = 0; 82359243Sobrien while (cp > arginp && *--cp == '\\') 82459243Sobrien ++count; 82559243Sobrien if ((count & 1) != 0) { 82659243Sobrien exiterr = 1; 82759243Sobrien stderror(ERR_ARGC); 82859243Sobrien } 82959243Sobrien } 83059243Sobrien prompt = 0; 83159243Sobrien nofile = 1; 83259243Sobrien break; 83359243Sobrien case 'd': /* -d Load directory stack from file */ 83459243Sobrien rdirs = 1; 83559243Sobrien break; 83659243Sobrien 83759243Sobrien#ifdef apollo 83859243Sobrien case 'D': /* -D Define environment variable */ 83959243Sobrien { 840145479Smp Char *dp; 84159243Sobrien 84259243Sobrien cp = str2short(tcp); 84359243Sobrien if (dp = Strchr(cp, '=')) { 84459243Sobrien *dp++ = '\0'; 84559243Sobrien tsetenv(cp, dp); 84659243Sobrien } 84759243Sobrien else 84859243Sobrien tsetenv(cp, STRNULL); 84959243Sobrien } 85059243Sobrien *tcp = '\0'; /* done with this argument */ 85159243Sobrien break; 85259243Sobrien#endif /* apollo */ 85359243Sobrien 85459243Sobrien case 'e': /* -e Exit on any error */ 85559243Sobrien exiterr = 1; 85659243Sobrien break; 85759243Sobrien 85859243Sobrien case 'f': /* -f Fast start */ 85959243Sobrien fast = 1; 86059243Sobrien break; 86159243Sobrien 86259243Sobrien case 'i': /* -i Interactive, even if !intty */ 86359243Sobrien intact = 1; 86459243Sobrien nofile = 1; 86559243Sobrien break; 86659243Sobrien 86759243Sobrien case 'm': /* -m read .cshrc (from su) */ 86859243Sobrien mflag = 1; 86959243Sobrien break; 87059243Sobrien 87159243Sobrien case 'n': /* -n Don't execute */ 87259243Sobrien noexec = 1; 87359243Sobrien break; 87459243Sobrien 87559243Sobrien case 'q': /* -q (Undoc'd) ... die on quit */ 87659243Sobrien quitit = 1; 87759243Sobrien break; 87859243Sobrien 87959243Sobrien case 's': /* -s Read from std input */ 88059243Sobrien nofile = 1; 88159243Sobrien break; 88259243Sobrien 88359243Sobrien case 't': /* -t Read one line from input */ 88459243Sobrien onelflg = 2; 88559243Sobrien prompt = 0; 88659243Sobrien nofile = 1; 88759243Sobrien break; 88859243Sobrien 88959243Sobrien case 'v': /* -v Echo hist expanded input */ 89059243Sobrien nverbose = 1; /* ... later */ 89159243Sobrien break; 89259243Sobrien 89359243Sobrien case 'x': /* -x Echo just before execution */ 89459243Sobrien nexececho = 1; /* ... later */ 89559243Sobrien break; 89659243Sobrien 89759243Sobrien case 'V': /* -V Echo hist expanded input */ 89859243Sobrien setNS(STRverbose); /* NOW! */ 89959243Sobrien break; 90059243Sobrien 90159243Sobrien case 'X': /* -X Echo just before execution */ 90259243Sobrien setNS(STRecho); /* NOW! */ 90359243Sobrien break; 90459243Sobrien 905167465Smp case 'F': 90659243Sobrien /* 90759243Sobrien * This will cause children to be created using fork instead of 90859243Sobrien * vfork. 90959243Sobrien */ 91059243Sobrien use_fork = 1; 91159243Sobrien break; 91259243Sobrien 91359243Sobrien case ' ': 91459243Sobrien case '\t': 91559243Sobrien /* 91659243Sobrien * for O/S's that don't do the argument parsing right in 91759243Sobrien * "#!/foo -f " scripts 91859243Sobrien */ 91959243Sobrien break; 92059243Sobrien 92159243Sobrien default: /* Unknown command option */ 92259243Sobrien exiterr = 1; 92359243Sobrien stderror(ERR_TCSHUSAGE, tcp-1, progname); 92459243Sobrien break; 92559243Sobrien 92659243Sobrien } while (*tcp); 92759243Sobrien tempv++, argc--; 92859243Sobrien } 92959243Sobrien 93059243Sobrien if (quitit) /* With all due haste, for debugging */ 93159243Sobrien (void) signal(SIGQUIT, SIG_DFL); 93259243Sobrien 93359243Sobrien /* 93459243Sobrien * Unless prevented by -, -c, -i, -s, or -t, if there are remaining 93559243Sobrien * arguments the first of them is the name of a shell file from which to 93659243Sobrien * read commands. 93759243Sobrien */ 93859243Sobrien if (nofile == 0 && argc > 0) { 939167465Smp nofile = xopen(tempv[0], O_RDONLY|O_LARGEFILE); 94059243Sobrien if (nofile < 0) { 94159243Sobrien child = 1; /* So this ... */ 94259243Sobrien /* ... doesn't return */ 94359243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 94459243Sobrien } 945167465Smp xfree(ffile); 94659243Sobrien dolzero = 1; 94759243Sobrien ffile = SAVE(tempv[0]); 94859243Sobrien /* 94959243Sobrien * Replace FSHIN. Handle /dev/std{in,out,err} specially 95059243Sobrien * since once they are closed we cannot open them again. 95159243Sobrien * In that case we use our own saved descriptors 95259243Sobrien */ 95359243Sobrien if ((SHIN = dmove(nofile, FSHIN)) < 0) 95459243Sobrien switch(nofile) { 95559243Sobrien case 0: 95659243Sobrien SHIN = FSHIN; 95759243Sobrien break; 95859243Sobrien case 1: 95959243Sobrien SHIN = FSHOUT; 96059243Sobrien break; 96159243Sobrien case 2: 96259243Sobrien SHIN = FSHDIAG; 96359243Sobrien break; 96459243Sobrien default: 96559243Sobrien stderror(ERR_SYSTEM, tempv[0], strerror(errno)); 96659243Sobrien break; 96759243Sobrien } 96859243Sobrien (void) close_on_exec(SHIN, 1); 96959243Sobrien prompt = 0; 97059243Sobrien /* argc not used any more */ tempv++; 97159243Sobrien } 97259243Sobrien 973100616Smp /* 974100616Smp * Call to closem() used to be part of initdesc(). Now called below where 975100616Smp * the script name argument has become stdin. Kernel may have used a file 976100616Smp * descriptor to hold the name of the script (setuid case) and this name 977100616Smp * mustn't be lost by closing the fd too soon. 978100616Smp */ 979100616Smp closem(); 98059243Sobrien 98159243Sobrien /* 98259243Sobrien * Consider input a tty if it really is or we are interactive. but not for 98359243Sobrien * editing (christos) 98459243Sobrien */ 98559243Sobrien if (!(intty = isatty(SHIN))) { 98659243Sobrien if (adrof(STRedit)) 98759243Sobrien unsetv(STRedit); 98859243Sobrien editing = 0; 98959243Sobrien } 99059243Sobrien intty |= intact; 99159243Sobrien#ifndef convex 99259243Sobrien if (intty || (intact && isatty(SHOUT))) { 99359243Sobrien if (!batch && (uid != euid || gid != egid)) { 99459243Sobrien errno = EACCES; 99559243Sobrien child = 1; /* So this ... */ 99659243Sobrien /* ... doesn't return */ 99759243Sobrien stderror(ERR_SYSTEM, progname, strerror(errno)); 99859243Sobrien } 99959243Sobrien } 100059243Sobrien#endif /* convex */ 100159243Sobrien isoutatty = isatty(SHOUT); 100259243Sobrien isdiagatty = isatty(SHDIAG); 100359243Sobrien /* 100459243Sobrien * Decide whether we should play with signals or not. If we are explicitly 100559243Sobrien * told (via -i, or -) or we are a login shell (arg0 starts with -) or the 100659243Sobrien * input and output are both the ttys("csh", or "csh</dev/ttyx>/dev/ttyx") 100759243Sobrien * Note that in only the login shell is it likely that parent may have set 100859243Sobrien * signals to be ignored 100959243Sobrien */ 101059243Sobrien if (loginsh || intact || (intty && isatty(SHOUT))) 101159243Sobrien setintr = 1; 101259243Sobrien settell(); 101359243Sobrien /* 101459243Sobrien * Save the remaining arguments in argv. 101559243Sobrien */ 101659243Sobrien setq(STRargv, blk2short(tempv), &shvhed, VAR_READWRITE); 101759243Sobrien 101859243Sobrien /* 101959243Sobrien * Set up the prompt. 102059243Sobrien */ 102159243Sobrien if (prompt) { 102259243Sobrien if (tcsh) 1023167465Smp setcopy(STRprompt, STRdeftcshprompt, VAR_READWRITE); 102459243Sobrien else 1025167465Smp setcopy(STRprompt, STRdefcshprompt, VAR_READWRITE); 102659243Sobrien /* that's a meta-questionmark */ 1027167465Smp setcopy(STRprompt2, STRmquestion, VAR_READWRITE); 1028167465Smp setcopy(STRprompt3, STRKCORRECT, VAR_READWRITE); 102959243Sobrien } 103059243Sobrien 103159243Sobrien /* 103259243Sobrien * If we are an interactive shell, then start fiddling with the signals; 103359243Sobrien * this is a tricky game. 103459243Sobrien */ 103559243Sobrien shpgrp = mygetpgrp(); 103659243Sobrien opgrp = tpgrp = -1; 103759243Sobrien if (setintr) { 1038167465Smp struct sigaction osig; 1039167465Smp 104059243Sobrien **argv = '-'; 104159243Sobrien if (!quitit) /* Wary! */ 104259243Sobrien (void) signal(SIGQUIT, SIG_IGN); 1043167465Smp pintr_disabled = 1; 1044167465Smp sigset_interrupting(SIGINT, queue_pintr); 104559243Sobrien (void) signal(SIGTERM, SIG_IGN); 104659243Sobrien 104759243Sobrien /* 104859243Sobrien * No reason I can see not to save history on all these events.. 104959243Sobrien * Most usual occurrence is in a window system, where we're not a login 105059243Sobrien * shell, but might as well be... (sg) 105159243Sobrien * But there might be races when lots of shells exit together... 105259243Sobrien * [this is also incompatible]. 105359243Sobrien * We have to be mre careful here. If the parent wants to 105459243Sobrien * ignore the signals then we leave them untouched... 105559243Sobrien * We also only setup the handlers for shells that are trully 105659243Sobrien * interactive. 105759243Sobrien */ 1058167465Smp sigaction(SIGHUP, NULL, &osig); 1059167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1060167465Smp /* exit processing on HUP */ 1061167465Smp sigset_interrupting(SIGHUP, queue_phup); 106259243Sobrien#ifdef SIGXCPU 1063167465Smp sigaction(SIGXCPU, NULL, &osig); 1064167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1065167465Smp /* exit processing on XCPU */ 1066167465Smp sigset_interrupting(SIGXCPU, queue_phup); 106759243Sobrien#endif 106859243Sobrien#ifdef SIGXFSZ 1069167465Smp sigaction(SIGXFSZ, NULL, &osig); 1070167465Smp if (loginsh || osig.sa_handler != SIG_IGN) 1071167465Smp /* exit processing on XFSZ */ 1072167465Smp sigset_interrupting(SIGXFSZ, queue_phup); 107359243Sobrien#endif 107459243Sobrien 107559243Sobrien if (quitit == 0 && arginp == 0) { 107659243Sobrien#ifdef SIGTSTP 107759243Sobrien (void) signal(SIGTSTP, SIG_IGN); 107859243Sobrien#endif 107959243Sobrien#ifdef SIGTTIN 108059243Sobrien (void) signal(SIGTTIN, SIG_IGN); 108159243Sobrien#endif 108259243Sobrien#ifdef SIGTTOU 108359243Sobrien (void) signal(SIGTTOU, SIG_IGN); 108459243Sobrien#endif 108559243Sobrien /* 108659243Sobrien * Wait till in foreground, in case someone stupidly runs csh & 108759243Sobrien * dont want to try to grab away the tty. 108859243Sobrien */ 108959243Sobrien if (isatty(FSHDIAG)) 109059243Sobrien f = FSHDIAG; 109159243Sobrien else if (isatty(FSHOUT)) 109259243Sobrien f = FSHOUT; 109359243Sobrien else if (isatty(OLDSTD)) 109459243Sobrien f = OLDSTD; 109559243Sobrien else 109659243Sobrien f = -1; 109759243Sobrien 109859243Sobrien#ifdef NeXT 109959243Sobrien /* NeXT 2.0 /usr/etc/rlogind, does not set our process group! */ 110059243Sobrien if (shpgrp == 0) { 110159243Sobrien shpgrp = getpid(); 110259243Sobrien (void) setpgid(0, shpgrp); 110359243Sobrien (void) tcsetpgrp(f, shpgrp); 110459243Sobrien } 110559243Sobrien#endif /* NeXT */ 110659243Sobrien#ifdef BSDJOBS /* if we have tty job control */ 1107195609Smp if (grabpgrp(f, shpgrp) != -1) { 110859243Sobrien /* 110959243Sobrien * Thanks to Matt Day for the POSIX references, and to 111059243Sobrien * Paul Close for the SGI clarification. 111159243Sobrien */ 111259243Sobrien if (setdisc(f) != -1) { 111359243Sobrien opgrp = shpgrp; 111459243Sobrien shpgrp = getpid(); 111559243Sobrien tpgrp = shpgrp; 111659243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 111759243Sobrien /* 111859243Sobrien * On hpux 7.03 this fails with EPERM. This happens on 111959243Sobrien * the 800 when opgrp != shpgrp at this point. (we were 112059243Sobrien * forked from a non job control shell) 112159243Sobrien * POSIX 7.2.4, says we failed because the process 112259243Sobrien * group specified did not belong to a process 112359243Sobrien * in the same session with the tty. So we set our 112459243Sobrien * process group and try again. 112559243Sobrien */ 112659243Sobrien if (setpgid(0, shpgrp) == -1) { 112759243Sobrien xprintf("setpgid:"); 112859243Sobrien goto notty; 112959243Sobrien } 113059243Sobrien if (tcsetpgrp(f, shpgrp) == -1) { 113159243Sobrien xprintf("tcsetpgrp:"); 113259243Sobrien goto notty; 113359243Sobrien } 113459243Sobrien } 113559243Sobrien /* 113659243Sobrien * We check the process group now. If it is the same, then 113759243Sobrien * we don't need to set it again. On hpux 7.0 on the 300's 113859243Sobrien * if we set it again it fails with EPERM. This is the 113959243Sobrien * correct behavior according to POSIX 4.3.3 if the process 114059243Sobrien * was a session leader . 114159243Sobrien */ 114259243Sobrien else if (shpgrp != mygetpgrp()) { 114359243Sobrien if(setpgid(0, shpgrp) == -1) { 114459243Sobrien xprintf("setpgid:"); 114559243Sobrien goto notty; 114659243Sobrien } 114759243Sobrien } 114859243Sobrien#ifdef IRIS4D 114959243Sobrien /* 115059243Sobrien * But on irix 3.3 we need to set it again, even if it is 115159243Sobrien * the same. We do that to tell the system that we 115259243Sobrien * need BSD process group compatibility. 115359243Sobrien */ 115459243Sobrien else 115559243Sobrien (void) setpgid(0, shpgrp); 115659243Sobrien#endif 115759243Sobrien (void) close_on_exec(dcopy(f, FSHTTY), 1); 115859243Sobrien } 115959243Sobrien else 116059243Sobrien tpgrp = -1; 116159243Sobrien } 116259243Sobrien if (tpgrp == -1) { 116359243Sobrien notty: 1164167465Smp xprintf(CGETS(11, 1, "Warning: no access to tty (%s).\n"), 1165195609Smp strerror(errno)); 1166195609Smp xprintf("%s", 1167195609Smp CGETS(11, 2, "Thus no job control in this shell.\n")); 116859243Sobrien /* 116959243Sobrien * Fix from:Sakari Jalovaara <sja@sirius.hut.fi> if we don't 117059243Sobrien * have access to tty, disable editing too 117159243Sobrien */ 117259243Sobrien if (adrof(STRedit)) 117359243Sobrien unsetv(STRedit); 117459243Sobrien editing = 0; 117559243Sobrien } 117659243Sobrien#else /* BSDJOBS */ /* don't have job control, so frotz it */ 117759243Sobrien tpgrp = -1; 117859243Sobrien#endif /* BSDJOBS */ 117959243Sobrien } 118059243Sobrien } 1181167465Smp if (setintr == 0 && parintr.sa_handler == SIG_DFL) 118259243Sobrien setintr = 1; 118359243Sobrien 118459243Sobrien/* 118559243Sobrien * SVR4 doesn't send a SIGCHLD when a child is stopped or continued if the 118659243Sobrien * handler is installed with signal(2) or sigset(2). sigaction(2) must 118759243Sobrien * be used instead. 118859243Sobrien * 118959243Sobrien * David Dawes (dawes@physics.su.oz.au) Sept 1991 119059243Sobrien */ 1191167465Smp sigset_interrupting(SIGCHLD, queue_pchild); 119259243Sobrien 119359243Sobrien if (intty && !arginp) 119459243Sobrien (void) ed_Setup(editing);/* Get the tty state, and set defaults */ 119559243Sobrien /* Only alter the tty state if editing */ 119659243Sobrien 119759243Sobrien /* 119859243Sobrien * Set an exit here in case of an interrupt or error reading the shell 119959243Sobrien * start-up scripts. 120059243Sobrien */ 1201131962Smp osetintr = setintr; 1202131962Smp oparintr = parintr; 1203167465Smp (void)cleanup_push_mark(); /* There is no outer handler */ 1204167465Smp if (setexit() != 0) /* PWP */ 1205167465Smp reenter = 1; 1206167465Smp else 1207167465Smp reenter = 0; 120869408Sache exitset++; 120959243Sobrien haderr = 0; /* In case second time through */ 121059243Sobrien if (!fast && reenter == 0) { 121159243Sobrien /* Will have varval(STRhome) here because set fast if don't */ 121259243Sobrien { 1213167465Smp pintr_disabled++; 1214167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1215167465Smp setintr = 0;/*FIXRESET:cleanup*/ 1216167465Smp /* onintr in /etc/ files has no effect */ 1217167465Smp parintr.sa_handler = SIG_IGN;/*FIXRESET: cleanup*/ 121859243Sobrien#ifdef LOGINFIRST 121959243Sobrien#ifdef _PATH_DOTLOGIN 122059243Sobrien if (loginsh) 1221167465Smp (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 122259243Sobrien#endif 122359243Sobrien#endif 122459243Sobrien 122559243Sobrien#ifdef _PATH_DOTCSHRC 122659243Sobrien (void) srcfile(_PATH_DOTCSHRC, 0, 0, NULL); 122759243Sobrien#endif 122859243Sobrien if (!arginp && !onelflg && !havhash) 122959243Sobrien dohash(NULL,NULL); 123059243Sobrien#ifndef LOGINFIRST 123159243Sobrien#ifdef _PATH_DOTLOGIN 123259243Sobrien if (loginsh) 123359243Sobrien (void) srcfile(_PATH_DOTLOGIN, 0, 0, NULL); 123459243Sobrien#endif 123559243Sobrien#endif 1236167465Smp cleanup_until(&pintr_disabled); 123759243Sobrien setintr = osetintr; 123859243Sobrien parintr = oparintr; 123959243Sobrien } 124059243Sobrien#ifdef LOGINFIRST 124159243Sobrien if (loginsh) 124259243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 124359243Sobrien#endif 124459243Sobrien /* upward compat. */ 124559243Sobrien if (!srccat(varval(STRhome), STRsldottcshrc)) 124659243Sobrien (void) srccat(varval(STRhome), STRsldotcshrc); 124759243Sobrien 1248167465Smp if (!arginp && !onelflg && !havhash) 124959243Sobrien dohash(NULL,NULL); 125059243Sobrien 125159243Sobrien /* 125259243Sobrien * Source history before .login so that it is available in .login 125359243Sobrien */ 125459243Sobrien loadhist(NULL, 0); 125559243Sobrien#ifndef LOGINFIRST 125659243Sobrien if (loginsh) 125759243Sobrien (void) srccat(varval(STRhome), STRsldotlogin); 125859243Sobrien#endif 1259167465Smp if (loginsh || rdirs) 126059243Sobrien loaddirs(NULL); 126159243Sobrien } 1262131962Smp /* Reset interrupt flag */ 1263131962Smp setintr = osetintr; 1264131962Smp parintr = oparintr; 1265167465Smp exitset--; 1266131962Smp 126759243Sobrien /* Initing AFTER .cshrc is the Right Way */ 126859243Sobrien if (intty && !arginp) { /* PWP setup stuff */ 126959243Sobrien ed_Init(); /* init the new line editor */ 127059243Sobrien#ifdef SIG_WINDOW 127159243Sobrien check_window_size(1); /* mung environment */ 127259243Sobrien#endif /* SIG_WINDOW */ 127359243Sobrien } 127459243Sobrien 127559243Sobrien /* 127659243Sobrien * Now are ready for the -v and -x flags 127759243Sobrien */ 127859243Sobrien if (nverbose) 127959243Sobrien setNS(STRverbose); 128059243Sobrien if (nexececho) 128159243Sobrien setNS(STRecho); 128259243Sobrien 128359243Sobrien /* 128459243Sobrien * All the rest of the world is inside this call. The argument to process 128559243Sobrien * indicates whether it should catch "error unwinds". Thus if we are a 128659243Sobrien * interactive shell our call here will never return by being blown past on 128759243Sobrien * an error. 128859243Sobrien */ 128959243Sobrien process(setintr); 129059243Sobrien 129159243Sobrien /* 129259243Sobrien * Mop-up. 129359243Sobrien */ 1294197812Srdivacky /* Take care of these (especially HUP) here instead of inside flush. */ 1295197812Srdivacky handle_pending_signals(); 129659243Sobrien if (intty) { 129759243Sobrien if (loginsh) { 129859243Sobrien xprintf("logout\n"); 1299167465Smp xclose(SHIN); 130059243Sobrien child = 1; 130159243Sobrien#ifdef TESLA 130259243Sobrien do_logout = 1; 130359243Sobrien#endif /* TESLA */ 130459243Sobrien goodbye(NULL, NULL); 130559243Sobrien } 130659243Sobrien else { 130759243Sobrien xprintf("exit\n"); 130859243Sobrien } 130959243Sobrien } 131059243Sobrien record(); 131159243Sobrien exitstat(); 131259243Sobrien return (0); 131359243Sobrien} 131459243Sobrien 131559243Sobrienvoid 1316167465Smpuntty(void) 131759243Sobrien{ 131859243Sobrien#ifdef BSDJOBS 131959243Sobrien if (tpgrp > 0 && opgrp != shpgrp) { 132059243Sobrien (void) setpgid(0, opgrp); 132159243Sobrien (void) tcsetpgrp(FSHTTY, opgrp); 132259243Sobrien (void) resetdisc(FSHTTY); 132359243Sobrien } 132459243Sobrien#endif /* BSDJOBS */ 132559243Sobrien} 132659243Sobrien 132759243Sobrienvoid 1328167465Smpimportpath(Char *cp) 132959243Sobrien{ 1330167465Smp size_t i = 0; 1331145479Smp Char *dp; 1332145479Smp Char **pv; 133359243Sobrien int c; 133459243Sobrien 133559243Sobrien for (dp = cp; *dp; dp++) 133659243Sobrien if (*dp == PATHSEP) 133759243Sobrien i++; 133859243Sobrien /* 133959243Sobrien * i+2 where i is the number of colons in the path. There are i+1 134059243Sobrien * directories in the path plus we need room for a zero terminator. 134159243Sobrien */ 1342167465Smp pv = xcalloc(i + 2, sizeof(Char *)); 134359243Sobrien dp = cp; 134459243Sobrien i = 0; 134559243Sobrien if (*dp) 134659243Sobrien for (;;) { 134759243Sobrien if ((c = *dp) == PATHSEP || c == 0) { 134859243Sobrien *dp = 0; 134959243Sobrien pv[i++] = Strsave(*cp ? cp : STRdot); 135059243Sobrien if (c) { 135159243Sobrien cp = dp + 1; 135259243Sobrien *dp = PATHSEP; 135359243Sobrien } 135459243Sobrien else 135559243Sobrien break; 135659243Sobrien } 135769408Sache#ifdef WINNT_NATIVE 135859243Sobrien else if (*dp == '\\') 135959243Sobrien *dp = '/'; 136069408Sache#endif /* WINNT_NATIVE */ 136159243Sobrien dp++; 136259243Sobrien } 136359243Sobrien pv[i] = 0; 1364167465Smp cleanup_push(pv, blk_cleanup); 136559243Sobrien setq(STRpath, pv, &shvhed, VAR_READWRITE); 1366167465Smp cleanup_ignore(pv); 1367167465Smp cleanup_until(pv); 136859243Sobrien} 136959243Sobrien 137059243Sobrien/* 137159243Sobrien * Source to the file which is the catenation of the argument names. 137259243Sobrien */ 137359243Sobrienstatic int 1374167465Smpsrccat(Char *cp, Char *dp) 137559243Sobrien{ 137659243Sobrien if (cp[0] == '/' && cp[1] == '\0') 137759243Sobrien return srcfile(short2str(dp), (mflag ? 0 : 1), 0, NULL); 137859243Sobrien else { 1379145479Smp Char *ep; 138059243Sobrien char *ptr; 138159243Sobrien int rv; 138259243Sobrien 138369408Sache#ifdef WINNT_NATIVE 1384167465Smp ep = Strend(cp); 1385167465Smp if (ep != cp && ep[-1] == '/' && dp[0] == '/') /* silly win95 */ 138659243Sobrien dp++; 138769408Sache#endif /* WINNT_NATIVE */ 138859243Sobrien 138959243Sobrien ep = Strspl(cp, dp); 1390167465Smp cleanup_push(ep, xfree); 139159243Sobrien ptr = short2str(ep); 139259243Sobrien 139359243Sobrien rv = srcfile(ptr, (mflag ? 0 : 1), 0, NULL); 1394167465Smp cleanup_until(ep); 139559243Sobrien return rv; 139659243Sobrien } 139759243Sobrien} 139859243Sobrien 139959243Sobrien/* 140059243Sobrien * Source to a file putting the file descriptor in a safe place (> 2). 140159243Sobrien */ 140283098Smp#ifndef WINNT_NATIVE 140359243Sobrienstatic int 140483098Smp#else 140583098Smpint 140683098Smp#endif /*WINNT_NATIVE*/ 1407167465Smpsrcfile(const char *f, int onlyown, int flag, Char **av) 140859243Sobrien{ 1409145479Smp int unit; 141059243Sobrien 1411167465Smp if ((unit = xopen(f, O_RDONLY|O_LARGEFILE)) == -1) 141259243Sobrien return 0; 1413167465Smp cleanup_push(&unit, open_cleanup); 141459243Sobrien unit = dmove(unit, -1); 1415167465Smp cleanup_ignore(&unit); 1416167465Smp cleanup_until(&unit); 141759243Sobrien 141859243Sobrien (void) close_on_exec(unit, 1); 141959243Sobrien srcunit(unit, onlyown, flag, av); 142059243Sobrien return 1; 142159243Sobrien} 142259243Sobrien 142359243Sobrien 142459243Sobrien/* 142559243Sobrien * Save the shell state, and establish new argument vector, and new input 142659243Sobrien * fd. 142759243Sobrien */ 142859243Sobrienstatic void 1429167465Smpst_save(struct saved_state *st, int unit, int hflg, Char **al, Char **av) 143059243Sobrien{ 143159243Sobrien st->insource = insource; 143259243Sobrien st->SHIN = SHIN; 1433100616Smp /* Want to preserve the meaning of "source file >output". 1434100616Smp * Save old descriptors, move new 0,1,2 to safe places and assign 1435100616Smp * them to SH* and let process() redo 0,1,2 from them. 1436100616Smp * 1437100616Smp * The macro returns true if d1 and d2 are good and they point to 1438100616Smp * different things. If you don't avoid saving duplicate 1439100616Smp * descriptors, you really limit the depth of "source" recursion 1440100616Smp * you can do because of all the open file descriptors. -IAN! 1441100616Smp */ 1442100616Smp#define NEED_SAVE_FD(d1,d2) \ 1443100616Smp (fstat(d1, &s1) != -1 && fstat(d2, &s2) != -1 \ 1444100616Smp && (s1.st_ino != s2.st_ino || s1.st_dev != s2.st_dev) ) 1445100616Smp 1446100616Smp st->OLDSTD = st->SHOUT = st->SHDIAG = -1;/* test later to restore these */ 1447100616Smp if (didfds) { 1448100616Smp struct stat s1, s2; 1449145479Smp if (NEED_SAVE_FD(0,OLDSTD)) { 1450145479Smp st->OLDSTD = OLDSTD; 1451145479Smp OLDSTD = dmove(0, -1); 1452145479Smp (void)close_on_exec(OLDSTD, 1); 1453145479Smp } 1454145479Smp if (NEED_SAVE_FD(1,SHOUT)) { 1455145479Smp st->SHOUT = SHOUT; 1456145479Smp SHOUT = dmove(1, -1); 1457145479Smp (void)close_on_exec(SHOUT, 1); 1458145479Smp } 1459145479Smp if (NEED_SAVE_FD(2,SHDIAG)) { 1460145479Smp st->SHDIAG = SHDIAG; 1461145479Smp SHDIAG = dmove(2, -1); 1462145479Smp (void)close_on_exec(SHDIAG, 1); 1463145479Smp } 1464100616Smp donefds(); 1465100616Smp } 1466100616Smp 146759243Sobrien st->intty = intty; 146859243Sobrien st->whyles = whyles; 146959243Sobrien st->gointr = gointr; 147059243Sobrien st->arginp = arginp; 147159243Sobrien st->evalp = evalp; 147259243Sobrien st->evalvec = evalvec; 147359243Sobrien st->alvecp = alvecp; 147459243Sobrien st->alvec = alvec; 147559243Sobrien st->onelflg = onelflg; 147659243Sobrien st->enterhist = enterhist; 1477195609Smp st->justpr = justpr; 147859243Sobrien if (hflg) 147959243Sobrien st->HIST = HIST; 148059243Sobrien else 148159243Sobrien st->HIST = '\0'; 148259243Sobrien st->cantell = cantell; 148359243Sobrien cpybin(st->B, B); 148459243Sobrien 148559243Sobrien /* 148659243Sobrien * we can now pass arguments to source. 148759243Sobrien * For compatibility we do that only if arguments were really 148859243Sobrien * passed, otherwise we keep the old, global $argv like before. 148959243Sobrien */ 149059243Sobrien if (av != NULL && *av != NULL) { 149159243Sobrien struct varent *vp; 1492100616Smp if ((vp = adrof(STRargv)) != NULL && vp->vec != NULL) 149359243Sobrien st->argv = saveblk(vp->vec); 149459243Sobrien else 149559243Sobrien st->argv = NULL; 149659243Sobrien setq(STRargv, saveblk(av), &shvhed, VAR_READWRITE); 149759243Sobrien } 149859243Sobrien else 149959243Sobrien st->argv = NULL; 1500167465Smp st->av = av; 150159243Sobrien 150259243Sobrien SHIN = unit; /* Do this first */ 150359243Sobrien 150459243Sobrien /* Establish new input arena */ 150559243Sobrien { 150659243Sobrien fbuf = NULL; 150759243Sobrien fseekp = feobp = fblocks = 0; 150859243Sobrien settell(); 150959243Sobrien } 151059243Sobrien 151159243Sobrien arginp = 0; 151259243Sobrien onelflg = 0; 151359243Sobrien intty = isatty(SHIN); 151459243Sobrien whyles = 0; 151559243Sobrien gointr = 0; 151659243Sobrien evalvec = 0; 151759243Sobrien evalp = 0; 151859243Sobrien alvec = al; 151959243Sobrien alvecp = 0; 152059243Sobrien enterhist = hflg; 152159243Sobrien if (enterhist) 152259243Sobrien HIST = '\0'; 152359243Sobrien insource = 1; 152459243Sobrien} 152559243Sobrien 152659243Sobrien 152759243Sobrien/* 152859243Sobrien * Restore the shell to a saved state 152959243Sobrien */ 153059243Sobrienstatic void 1531167465Smpst_restore(void *xst) 1532167465Smp{ 153359243Sobrien struct saved_state *st; 1534167465Smp 1535167465Smp st = xst; 153659243Sobrien if (st->SHIN == -1) 153759243Sobrien return; 153859243Sobrien 153959243Sobrien /* Reset input arena */ 154059243Sobrien { 1541145479Smp int i; 1542145479Smp Char** nfbuf = fbuf; 1543145479Smp int nfblocks = fblocks; 154459243Sobrien 154559243Sobrien fblocks = 0; 154659243Sobrien fbuf = NULL; 154759243Sobrien for (i = 0; i < nfblocks; i++) 1548167465Smp xfree(nfbuf[i]); 1549167465Smp xfree(nfbuf); 155059243Sobrien } 155159243Sobrien cpybin(B, st->B); 155259243Sobrien 1553167465Smp xclose(SHIN); 155459243Sobrien 155559243Sobrien insource = st->insource; 155659243Sobrien SHIN = st->SHIN; 1557100616Smp if (st->OLDSTD != -1) 1558167465Smp xclose(OLDSTD), OLDSTD = st->OLDSTD; 1559100616Smp if (st->SHOUT != -1) 1560167465Smp xclose(SHOUT), SHOUT = st->SHOUT; 1561100616Smp if (st->SHDIAG != -1) 1562167465Smp xclose(SHDIAG), SHDIAG = st->SHDIAG; 156359243Sobrien arginp = st->arginp; 156459243Sobrien onelflg = st->onelflg; 156559243Sobrien evalp = st->evalp; 156659243Sobrien evalvec = st->evalvec; 156759243Sobrien alvecp = st->alvecp; 156859243Sobrien alvec = st->alvec; 156959243Sobrien intty = st->intty; 157059243Sobrien whyles = st->whyles; 157159243Sobrien gointr = st->gointr; 157259243Sobrien if (st->HIST != '\0') 157359243Sobrien HIST = st->HIST; 157459243Sobrien enterhist = st->enterhist; 157559243Sobrien cantell = st->cantell; 1576195609Smp justpr = st->justpr; 157759243Sobrien 157859243Sobrien if (st->argv != NULL) 157959243Sobrien setq(STRargv, st->argv, &shvhed, VAR_READWRITE); 1580167465Smp else if (st->av != NULL && *st->av != NULL && adrof(STRargv) != NULL) 158159243Sobrien unsetv(STRargv); 158259243Sobrien} 158359243Sobrien 158459243Sobrien/* 158559243Sobrien * Source to a unit. If onlyown it must be our file or our group or 158659243Sobrien * we don't chance it. This occurs on ".cshrc"s and the like. 158759243Sobrien */ 158859243Sobrienstatic void 1589167465Smpsrcunit(int unit, int onlyown, int hflg, Char **av) 159059243Sobrien{ 159159243Sobrien struct saved_state st; 1592167465Smp 159359243Sobrien st.SHIN = -1; /* st_restore checks this */ 159459243Sobrien 159559243Sobrien if (unit < 0) 159659243Sobrien return; 159759243Sobrien 159859243Sobrien if (onlyown) { 159959243Sobrien struct stat stb; 160059243Sobrien 160159243Sobrien if (fstat(unit, &stb) < 0) { 1602167465Smp xclose(unit); 160359243Sobrien return; 160459243Sobrien } 160559243Sobrien } 160659243Sobrien 1607167465Smp /* Does nothing before st_save() because st.SHIN == -1 */ 1608167465Smp cleanup_push(&st, st_restore); 1609167465Smp if (setintr) { 1610167465Smp pintr_disabled++; 1611167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 1612167465Smp } 161359243Sobrien 161459243Sobrien /* Save the current state and move us to a new state */ 161559243Sobrien st_save(&st, unit, hflg, NULL, av); 161659243Sobrien 161759243Sobrien /* 161859243Sobrien * Now if we are allowing commands to be interrupted, we let ourselves be 161959243Sobrien * interrupted. 162059243Sobrien */ 1621167465Smp if (setintr) { 1622167465Smp cleanup_until(&pintr_disabled); 1623167465Smp pintr_disabled++; 1624167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 162559243Sobrien } 162659243Sobrien 1627167465Smp process(0); /* 0 -> blow away on errors */ 162859243Sobrien 162959243Sobrien /* Restore the old state */ 1630167465Smp cleanup_until(&st); 163159243Sobrien} 163259243Sobrien 163359243Sobrien 163459243Sobrien/*ARGSUSED*/ 163559243Sobrienvoid 1636167465Smpgoodbye(Char **v, struct command *c) 163759243Sobrien{ 1638145479Smp USE(v); 163959243Sobrien USE(c); 164059243Sobrien record(); 164159243Sobrien 164259243Sobrien if (loginsh) { 1643167465Smp size_t omark; 1644167465Smp sigset_t set; 1645167465Smp 1646195609Smp sigemptyset(&set); 1647167465Smp signal(SIGQUIT, SIG_IGN); 1648167465Smp sigaddset(&set, SIGQUIT); 1649167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 1650167465Smp signal(SIGINT, SIG_IGN); 1651167465Smp sigaddset(&set, SIGINT); 1652167465Smp signal(SIGTERM, SIG_IGN); 1653167465Smp sigaddset(&set, SIGTERM); 1654167465Smp signal(SIGHUP, SIG_IGN); 1655167465Smp sigaddset(&set, SIGHUP); 1656167465Smp sigprocmask(SIG_UNBLOCK, &set, NULL); 1657167465Smp phup_disabled = 1; 165859243Sobrien setintr = 0; /* No interrupts after "logout" */ 165959243Sobrien /* Trap errors inside .logout */ 1660167465Smp omark = cleanup_push_mark(); 1661167465Smp if (setexit() == 0) { 1662167465Smp if (!(adrof(STRlogout))) 1663167465Smp setcopy(STRlogout, STRnormal, VAR_READWRITE); 166459243Sobrien#ifdef _PATH_DOTLOGOUT 1665167465Smp (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 166659243Sobrien#endif 1667167465Smp if (adrof(STRhome)) 1668167465Smp (void) srccat(varval(STRhome), STRsldtlogout); 166959243Sobrien#ifdef TESLA 1670167465Smp do_logout = 1; 167159243Sobrien#endif /* TESLA */ 1672167465Smp } 1673167465Smp cleanup_pop_mark(omark); 167459243Sobrien } 167559243Sobrien exitstat(); 167659243Sobrien} 167759243Sobrien 167859243Sobrienvoid 1679167465Smpexitstat(void) 168059243Sobrien{ 168159243Sobrien#ifdef PROF 168259243Sobrien monitor(0); 168359243Sobrien#endif 168459243Sobrien /* 168559243Sobrien * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit 168659243Sobrien * directly because we poke child here. Otherwise we might continue 168759243Sobrien * unwarrantedly (sic). 168859243Sobrien */ 168959243Sobrien child = 1; 169059243Sobrien 169159243Sobrien xexit(getn(varval(STRstatus))); 169259243Sobrien} 169359243Sobrien 169459243Sobrien/* 169559243Sobrien * in the event of a HUP we want to save the history 169659243Sobrien */ 1697167465Smpvoid 1698167465Smpphup(void) 169959243Sobrien{ 170059243Sobrien if (loginsh) { 1701167465Smp setcopy(STRlogout, STRhangup, VAR_READWRITE); 170259243Sobrien#ifdef _PATH_DOTLOGOUT 170359243Sobrien (void) srcfile(_PATH_DOTLOGOUT, 0, 0, NULL); 170459243Sobrien#endif 170559243Sobrien if (adrof(STRhome)) 170659243Sobrien (void) srccat(varval(STRhome), STRsldtlogout); 170759243Sobrien } 170859243Sobrien 170959243Sobrien record(); 171059243Sobrien 171159243Sobrien#ifdef POSIXJOBS 171259243Sobrien /* 171359243Sobrien * We kill the last foreground process group. It then becomes 171459243Sobrien * responsible to propagate the SIGHUP to its progeny. 171559243Sobrien */ 171659243Sobrien { 171759243Sobrien struct process *pp, *np; 171859243Sobrien 171959243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 172059243Sobrien np = pp; 172159243Sobrien /* 172259243Sobrien * Find if this job is in the foreground. It could be that 172359243Sobrien * the process leader has exited and the foreground flag 172459243Sobrien * is cleared for it. 172559243Sobrien */ 172659243Sobrien do 172759243Sobrien /* 172859243Sobrien * If a process is in the foreground we try to kill 172959243Sobrien * it's process group. If we succeed, then the 173059243Sobrien * whole job is gone. Otherwise we keep going... 173159243Sobrien * But avoid sending HUP to the shell again. 173259243Sobrien */ 173359243Sobrien if (((np->p_flags & PFOREGND) != 0) && np->p_jobid != shpgrp) { 173459243Sobrien np->p_flags &= ~PHUP; 173559243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 173659243Sobrien /* In case the job was suspended... */ 173759243Sobrien#ifdef SIGCONT 173859243Sobrien (void) killpg(np->p_jobid, SIGCONT); 173959243Sobrien#endif 174059243Sobrien break; 174159243Sobrien } 174259243Sobrien } 174359243Sobrien while ((np = np->p_friends) != pp); 174459243Sobrien } 174559243Sobrien } 174659243Sobrien#endif /* POSIXJOBS */ 174759243Sobrien 1748167465Smp xexit(SIGHUP); 174959243Sobrien} 175059243Sobrien 175159243Sobrienstatic Char *jobargv[2] = {STRjobs, 0}; 175259243Sobrien 175359243Sobrien/* 175459243Sobrien * Catch an interrupt, e.g. during lexical input. 175559243Sobrien * If we are an interactive shell, we reset the interrupt catch 175659243Sobrien * immediately. In any case we drain the shell output, 175759243Sobrien * and finally go through the normal error mechanism, which 175859243Sobrien * gets a chance to make the shell go away. 175959243Sobrien */ 1760167465Smpint just_signaled; /* bugfix by Michael Bloom (mg@ttidca.TTI.COM) */ 176159243Sobrien 1762167465Smpvoid 1763167465Smppintr(void) 176459243Sobrien{ 176559243Sobrien just_signaled = 1; 176659243Sobrien pintr1(1); 176759243Sobrien} 176859243Sobrien 176959243Sobrienvoid 1770167465Smppintr1(int wantnl) 177159243Sobrien{ 177259243Sobrien if (setintr) { 177359243Sobrien if (pjobs) { 177459243Sobrien pjobs = 0; 177559243Sobrien xputchar('\n'); 177659243Sobrien dojobs(jobargv, NULL); 177759243Sobrien stderror(ERR_NAME | ERR_INTR); 177859243Sobrien } 177959243Sobrien } 178059243Sobrien /* MH - handle interrupted completions specially */ 178159243Sobrien { 178259243Sobrien if (InsideCompletion) 178359243Sobrien stderror(ERR_SILENT); 178459243Sobrien } 178559243Sobrien /* JV - Make sure we shut off inputl */ 178659243Sobrien { 178759243Sobrien (void) Cookedmode(); 178859243Sobrien GettingInput = 0; 178959243Sobrien } 179059243Sobrien drainoline(); 1791145479Smp#ifdef HAVE_GETPWENT 179259243Sobrien (void) endpwent(); 1793145479Smp#endif 179459243Sobrien 179559243Sobrien /* 179659243Sobrien * If we have an active "onintr" then we search for the label. Note that if 179759243Sobrien * one does "onintr -" then we shan't be interruptible so we needn't worry 179859243Sobrien * about that here. 179959243Sobrien */ 180059243Sobrien if (gointr) { 180159243Sobrien gotolab(gointr); 180259243Sobrien reset(); 180359243Sobrien } 180459243Sobrien else if (intty && wantnl) { 180559243Sobrien if (editing) { 180659243Sobrien /* 180759243Sobrien * If we are editing a multi-line input command, and move to 180859243Sobrien * the beginning of the line, we don't want to trash it when 180959243Sobrien * we hit ^C 181059243Sobrien */ 181159243Sobrien PastBottom(); 181259243Sobrien ClearLines(); 181359243Sobrien ClearDisp(); 181459243Sobrien } 181559243Sobrien else { 181659243Sobrien /* xputchar('\n'); *//* Some like this, others don't */ 181759243Sobrien (void) putraw('\r'); 181859243Sobrien (void) putraw('\n'); 181959243Sobrien } 182059243Sobrien } 182159243Sobrien stderror(ERR_SILENT); 182259243Sobrien} 182359243Sobrien 182459243Sobrien/* 182559243Sobrien * Process is the main driving routine for the shell. 182659243Sobrien * It runs all command processing, except for those within { ... } 182759243Sobrien * in expressions (which is run by a routine evalav in sh.exp.c which 182859243Sobrien * is a stripped down process), and `...` evaluation which is run 182959243Sobrien * also by a subset of this code in sh.glob.c in the routine backeval. 183059243Sobrien * 183159243Sobrien * The code here is a little strange because part of it is interruptible 183259243Sobrien * and hence freeing of structures appears to occur when none is necessary 183359243Sobrien * if this is ignored. 183459243Sobrien * 183559243Sobrien * Note that if catch is not set then we will unwind on any error. 183659243Sobrien * If an end-of-file occurs, we return. 183759243Sobrien */ 183859243Sobrienvoid 1839167465Smpprocess(int catch) 184059243Sobrien{ 184159243Sobrien jmp_buf_t osetexit; 184259243Sobrien /* PWP: This might get nuked my longjmp so don't make it a register var */ 1843167465Smp size_t omark; 1844195609Smp volatile int didexitset = 0; 184559243Sobrien 184659243Sobrien getexit(osetexit); 1847167465Smp omark = cleanup_push_mark(); 184859243Sobrien for (;;) { 1849167465Smp struct command *t; 1850167465Smp int hadhist, old_pintr_disabled; 185159243Sobrien 1852195609Smp (void)setexit(); 1853195609Smp if (didexitset == 0) { 1854195609Smp exitset++; 1855195609Smp didexitset++; 1856195609Smp } 185759243Sobrien pendjob(); 185859243Sobrien 185959243Sobrien justpr = enterhist; /* execute if not entering history */ 186059243Sobrien 186159243Sobrien if (haderr) { 186259243Sobrien if (!catch) { 186359243Sobrien /* unwind */ 186459243Sobrien doneinp = 0; 1865167465Smp cleanup_pop_mark(omark); 186659243Sobrien resexit(osetexit); 186759243Sobrien reset(); 186859243Sobrien } 186959243Sobrien haderr = 0; 187059243Sobrien /* 187159243Sobrien * Every error is eventually caught here or the shell dies. It is 187259243Sobrien * at this point that we clean up any left-over open files, by 187359243Sobrien * closing all but a fixed number of pre-defined files. Thus 187459243Sobrien * routines don't have to worry about leaving files open due to 187559243Sobrien * deeper errors... they will get closed here. 187659243Sobrien */ 187759243Sobrien closem(); 187859243Sobrien continue; 187959243Sobrien } 188059243Sobrien if (doneinp) { 188159243Sobrien doneinp = 0; 188259243Sobrien break; 188359243Sobrien } 188459243Sobrien if (chkstop) 188559243Sobrien chkstop--; 188659243Sobrien if (neednote) 188759243Sobrien pnote(); 188859243Sobrien if (intty && prompt && evalvec == 0) { 188959243Sobrien just_signaled = 0; 189059243Sobrien mailchk(); 189159243Sobrien /* 189259243Sobrien * Watch for logins/logouts. Next is scheduled commands stored 189359243Sobrien * previously using "sched." Then execute periodic commands. 189459243Sobrien * Following that, the prompt precmd is run. 189559243Sobrien */ 189659243Sobrien#ifndef HAVENOUTMP 189759243Sobrien watch_login(0); 189859243Sobrien#endif /* !HAVENOUTMP */ 1899167465Smp sched_run(); 190059243Sobrien period_cmd(); 190159243Sobrien precmd(); 190259243Sobrien /* 190359243Sobrien * If we are at the end of the input buffer then we are going to 190459243Sobrien * read fresh stuff. Otherwise, we are rereading input and don't 190559243Sobrien * need or want to prompt. 190659243Sobrien */ 190769408Sache if (fseekp == feobp && aret == TCSH_F_SEEK) 190859243Sobrien printprompt(0, NULL); 190959243Sobrien flush(); 191059243Sobrien setalarm(1); 191159243Sobrien } 191259243Sobrien if (seterr) { 1913167465Smp xfree(seterr); 191459243Sobrien seterr = NULL; 191559243Sobrien } 191659243Sobrien 191759243Sobrien /* 1918167465Smp * Interruptible during interactive reads 1919167465Smp */ 1920167465Smp if (setintr) 1921167465Smp pintr_push_enable(&old_pintr_disabled); 1922167465Smp hadhist = lex(¶ml); 1923167465Smp if (setintr) 1924167465Smp cleanup_until(&old_pintr_disabled); 1925167465Smp cleanup_push(¶ml, lex_cleanup); 1926167465Smp 1927167465Smp /* 192859243Sobrien * Echo not only on VERBOSE, but also with history expansion. If there 192959243Sobrien * is a lexical error then we forego history echo. 193059243Sobrien */ 1931167465Smp if ((hadhist && !seterr && intty && !tellwhat && !Expand && !whyles) || 1932167465Smp adrof(STRverbose)) { 1933100616Smp int odidfds = didfds; 193459243Sobrien haderr = 1; 1935100616Smp didfds = 0; 193659243Sobrien prlex(¶ml); 1937100616Smp flush(); 193859243Sobrien haderr = 0; 1939100616Smp didfds = odidfds; 194059243Sobrien } 194159243Sobrien (void) alarm(0); /* Autologout OFF */ 1942167465Smp alrmcatch_disabled = 1; 194359243Sobrien 194459243Sobrien /* 194559243Sobrien * Save input text on the history list if reading in old history, or it 194659243Sobrien * is from the terminal at the top level and not in a loop. 194759243Sobrien * 194859243Sobrien * PWP: entry of items in the history list while in a while loop is done 194959243Sobrien * elsewhere... 195059243Sobrien */ 195159243Sobrien if (enterhist || (catch && intty && !whyles && !tellwhat && !arun)) 195259243Sobrien savehist(¶ml, enterhist > 1); 195359243Sobrien 195459243Sobrien if (Expand && seterr) 195559243Sobrien Expand = 0; 195659243Sobrien 195759243Sobrien /* 195859243Sobrien * Print lexical error messages, except when sourcing history lists. 195959243Sobrien */ 196059243Sobrien if (!enterhist && seterr) 196159243Sobrien stderror(ERR_OLD); 196259243Sobrien 196359243Sobrien /* 196459243Sobrien * If had a history command :p modifier then this is as far as we 196559243Sobrien * should go 196659243Sobrien */ 196759243Sobrien if (justpr) 1968167465Smp goto cmd_done; 196959243Sobrien 197059243Sobrien /* 197159243Sobrien * If had a tellwhat from twenex() then do 197259243Sobrien */ 197359243Sobrien if (tellwhat) { 197459243Sobrien (void) tellmewhat(¶ml, NULL); 1975167465Smp goto cmd_done; 197659243Sobrien } 197759243Sobrien 197859243Sobrien alias(¶ml); 197959243Sobrien 198059243Sobrien#ifdef BSDJOBS 198159243Sobrien /* 198259243Sobrien * If we are interactive, try to continue jobs that we have stopped 198359243Sobrien */ 198459243Sobrien if (prompt) 198559243Sobrien continue_jobs(¶ml); 198659243Sobrien#endif /* BSDJOBS */ 198759243Sobrien 198859243Sobrien /* 198959243Sobrien * Check to see if the user typed "rm * .o" or something 199059243Sobrien */ 199159243Sobrien if (prompt) 199259243Sobrien rmstar(¶ml); 199359243Sobrien /* 199459243Sobrien * Parse the words of the input into a parse tree. 199559243Sobrien */ 1996167465Smp t = syntax(paraml.next, ¶ml, 0); 1997167465Smp cleanup_push(t, syntax_cleanup); 199859243Sobrien if (seterr) 199959243Sobrien stderror(ERR_OLD); 200059243Sobrien 200159243Sobrien postcmd(); 200259243Sobrien /* 200359243Sobrien * Execute the parse tree From: Michael Schroeder 200459243Sobrien * <mlschroe@immd4.informatik.uni-erlangen.de> was execute(t, tpgrp); 200559243Sobrien */ 2006167465Smp execute(t, (tpgrp > 0 ? tpgrp : -1), NULL, NULL, TRUE); 200759243Sobrien 200859243Sobrien /* 200959243Sobrien * Made it! 201059243Sobrien */ 201159243Sobrien#ifdef SIG_WINDOW 2012100616Smp if (windowchg || (catch && intty && !whyles && !tellwhat)) { 2013100616Smp (void) check_window_size(0); /* for window systems */ 2014100616Smp } 201559243Sobrien#endif /* SIG_WINDOW */ 2016167465Smp setcopy(STR_, InputBuf, VAR_READWRITE | VAR_NOGLOB); 2017167465Smp cmd_done: 2018167465Smp cleanup_until(¶ml); 201959243Sobrien } 2020167465Smp cleanup_pop_mark(omark); 202159243Sobrien resexit(osetexit); 2022195609Smp exitset--; 202359243Sobrien} 202459243Sobrien 202559243Sobrien/*ARGSUSED*/ 202659243Sobrienvoid 2027167465Smpdosource(Char **t, struct command *c) 202859243Sobrien{ 2029145479Smp Char *f; 2030145479Smp int hflg = 0; 2031167465Smp char *file; 203259243Sobrien 203359243Sobrien USE(c); 203459243Sobrien t++; 203559243Sobrien if (*t && eq(*t, STRmh)) { 203659243Sobrien if (*++t == NULL) 203759243Sobrien stderror(ERR_NAME | ERR_HFLAG); 203859243Sobrien hflg++; 203959243Sobrien } 204059243Sobrien else if (*t && eq(*t, STRmm)) { 204159243Sobrien if (*++t == NULL) 204259243Sobrien stderror(ERR_NAME | ERR_MFLAG); 204359243Sobrien hflg = 2; 204459243Sobrien } 204559243Sobrien 204659243Sobrien f = globone(*t++, G_ERROR); 2047167465Smp file = strsave(short2str(f)); 2048167465Smp cleanup_push(file, xfree); 2049167465Smp xfree(f); 2050167465Smp t = glob_all_or_error(t); 2051167465Smp if ((!srcfile(file, 0, hflg, t)) && (!hflg) && (!bequiet)) 2052167465Smp stderror(ERR_SYSTEM, file, strerror(errno)); 2053167465Smp cleanup_until(file); 205459243Sobrien} 205559243Sobrien 205659243Sobrien/* 205759243Sobrien * Check for mail. 205859243Sobrien * If we are a login shell, then we don't want to tell 205959243Sobrien * about any mail file unless its been modified 206059243Sobrien * after the time we started. 206159243Sobrien * This prevents us from telling the user things he already 206259243Sobrien * knows, since the login program insists on saying 206359243Sobrien * "You have mail." 206459243Sobrien */ 206559243Sobrien 206659243Sobrien/* 206759243Sobrien * The AMS version. 206859243Sobrien * This version checks if the file is a directory, and if so, 206959243Sobrien * tells you the number of files in it, otherwise do the old thang. 207059243Sobrien * The magic "+1" in the time calculation is to compensate for 207159243Sobrien * an AFS bug where directory mtimes are set to 1 second in 207259243Sobrien * the future. 207359243Sobrien */ 207459243Sobrien 207559243Sobrienstatic void 2076167465Smpmailchk(void) 207759243Sobrien{ 2078145479Smp struct varent *v; 2079145479Smp Char **vp; 208059243Sobrien time_t t; 208159243Sobrien int intvl, cnt; 208259243Sobrien struct stat stb; 2083145479Smp int new; 208459243Sobrien 208559243Sobrien v = adrof(STRmail); 2086100616Smp if (v == NULL || v->vec == NULL) 208759243Sobrien return; 208859243Sobrien (void) time(&t); 208959243Sobrien vp = v->vec; 209059243Sobrien cnt = blklen(vp); 209159243Sobrien intvl = (cnt && number(*vp)) ? (--cnt, getn(*vp++)) : MAILINTVL; 209259243Sobrien if (intvl < 1) 209359243Sobrien intvl = 1; 209459243Sobrien if (chktim + intvl > t) 209559243Sobrien return; 209659243Sobrien for (; *vp; vp++) { 209759243Sobrien char *filename = short2str(*vp); 209859243Sobrien char *mboxdir = filename; 209959243Sobrien 210059243Sobrien if (stat(filename, &stb) < 0) 210159243Sobrien continue; 210259243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 210359243Sobrien new = stb.st_mtime > time0.tv_sec; 210459243Sobrien#else 210559415Sobrien new = stb.st_mtime > seconds0; 210659243Sobrien#endif 210759243Sobrien if (S_ISDIR(stb.st_mode)) { 210859243Sobrien DIR *mailbox; 210959243Sobrien int mailcount = 0; 2110167465Smp char *tempfilename; 211159243Sobrien struct stat stc; 211259243Sobrien 2113167465Smp tempfilename = xasprintf("%s/new", filename); 211459243Sobrien 211559243Sobrien if (stat(tempfilename, &stc) != -1 && S_ISDIR(stc.st_mode)) { 211659243Sobrien /* 211759243Sobrien * "filename/new" exists and is a directory; you are 211859243Sobrien * using Qmail. 211959243Sobrien */ 212059243Sobrien stb = stc; 212159243Sobrien#if defined(BSDTIMES) || defined(_SEQUENT_) 212259243Sobrien new = stb.st_mtime > time0.tv_sec; 212359243Sobrien#else 212459415Sobrien new = stb.st_mtime > seconds0; 212559243Sobrien#endif 212659243Sobrien mboxdir = tempfilename; 212759243Sobrien } 212859243Sobrien 2129167465Smp if (stb.st_mtime <= chktim + 1 || (loginsh && !new)) { 2130167465Smp xfree(tempfilename); 213159243Sobrien continue; 2132167465Smp } 213359243Sobrien 2134167465Smp mailbox = opendir(mboxdir); 2135167465Smp xfree(tempfilename); 2136167465Smp if (mailbox == NULL) 213759243Sobrien continue; 213859243Sobrien 213959243Sobrien /* skip . and .. */ 214059243Sobrien if (!readdir(mailbox) || !readdir(mailbox)) 214159243Sobrien continue; 214259243Sobrien 214359243Sobrien while (readdir(mailbox)) 214459243Sobrien mailcount++; 214559243Sobrien 214659243Sobrien if (mailcount == 0) 214759243Sobrien continue; 214859243Sobrien 214959243Sobrien if (cnt == 1) 215059243Sobrien xprintf(CGETS(11, 3, "You have %d mail messages.\n"), 215159243Sobrien mailcount); 215259243Sobrien else 215359243Sobrien xprintf(CGETS(11, 4, "You have %d mail messages in %s.\n"), 215459243Sobrien mailcount, filename); 215559243Sobrien } 215659243Sobrien else { 2157145479Smp char *type; 2158145479Smp 215959243Sobrien if (stb.st_size == 0 || stb.st_atime > stb.st_mtime || 216059243Sobrien (stb.st_atime <= chktim && stb.st_mtime <= chktim) || 216159243Sobrien (loginsh && !new)) 216259243Sobrien continue; 2163145479Smp type = strsave(new ? CGETS(11, 6, "new ") : ""); 2164167465Smp cleanup_push(type, xfree); 216559243Sobrien if (cnt == 1) 2166145479Smp xprintf(CGETS(11, 5, "You have %smail.\n"), type); 216759243Sobrien else 2168145479Smp xprintf(CGETS(11, 7, "You have %smail in %s.\n"), type, filename); 2169167465Smp cleanup_until(type); 217059243Sobrien } 217159243Sobrien } 217259243Sobrien chktim = t; 217359243Sobrien} 217459243Sobrien 217559243Sobrien/* 217659243Sobrien * Extract a home directory from the password file 217759243Sobrien * The argument points to a buffer where the name of the 217859243Sobrien * user whose home directory is sought is currently. 2179167465Smp * We return home directory of the user, or NULL. 218059243Sobrien */ 2181167465SmpChar * 2182167465Smpgethdir(const Char *home) 218359243Sobrien{ 218459243Sobrien Char *h; 218559243Sobrien 218659243Sobrien /* 218759243Sobrien * Is it us? 218859243Sobrien */ 218959243Sobrien if (*home == '\0') { 2190167465Smp if ((h = varval(STRhome)) != STRNULL) 2191167465Smp return Strsave(h); 219259243Sobrien else 2193167465Smp return NULL; 219459243Sobrien } 219559243Sobrien 219659243Sobrien /* 219759243Sobrien * Look in the cache 219859243Sobrien */ 219959243Sobrien if ((h = gettilde(home)) == NULL) 2200167465Smp return NULL; 2201167465Smp else 2202167465Smp return Strsave(h); 220359243Sobrien} 220459243Sobrien 220559243Sobrien/* 220659243Sobrien * Move the initial descriptors to their eventual 220759243Sobrien * resting places, closing all other units. 220859243Sobrien */ 220959243Sobrienvoid 2210167465Smpinitdesc(void) 221159243Sobrien{ 221259243Sobrien#ifdef NLS_BUGS 221359243Sobrien#ifdef NLS_CATALOGS 2214145479Smp nlsclose(); 221559243Sobrien#endif /* NLS_CATALOGS */ 221659243Sobrien#endif /* NLS_BUGS */ 221759243Sobrien 221859243Sobrien 221959243Sobrien didfds = 0; /* 0, 1, 2 aren't set up */ 222059243Sobrien (void) close_on_exec(SHIN = dcopy(0, FSHIN), 1); 222159243Sobrien (void) close_on_exec(SHOUT = dcopy(1, FSHOUT), 1); 222259243Sobrien (void) close_on_exec(SHDIAG = dcopy(2, FSHDIAG), 1); 222359243Sobrien (void) close_on_exec(OLDSTD = dcopy(SHIN, FOLDSTD), 1); 222459243Sobrien#ifndef CLOSE_ON_EXEC 222559243Sobrien didcch = 0; /* Havent closed for child */ 222659243Sobrien#endif /* CLOSE_ON_EXEC */ 222759243Sobrien isdiagatty = isatty(SHDIAG); 222859243Sobrien isoutatty = isatty(SHOUT); 222959243Sobrien#ifdef NLS_BUGS 223059243Sobrien#ifdef NLS_CATALOGS 223159243Sobrien nlsinit(); 223259243Sobrien#endif /* NLS_CATALOGS */ 223359243Sobrien#endif /* NLS_BUGS */ 223459243Sobrien} 223559243Sobrien 223659243Sobrien 223759243Sobrienvoid 223859243Sobrien#ifdef PROF 2239167465Smpdone(int i) 224059243Sobrien#else 2241167465Smpxexit(int i) 224259243Sobrien#endif 224359243Sobrien{ 224459243Sobrien#ifdef TESLA 224559243Sobrien if (loginsh && do_logout) { 224659243Sobrien /* this is to send hangup signal to the develcon */ 224759243Sobrien /* we toggle DTR. clear dtr - sleep 1 - set dtr */ 224859243Sobrien /* ioctl will return ENOTTY for pty's but we ignore it */ 224959243Sobrien /* exitstat will run after disconnect */ 225059243Sobrien /* we sleep for 2 seconds to let things happen in */ 225159243Sobrien /* .logout and rechist() */ 225259243Sobrien#ifdef TIOCCDTR 225359243Sobrien (void) sleep(2); 225459243Sobrien (void) ioctl(FSHTTY, TIOCCDTR, NULL); 225559243Sobrien (void) sleep(1); 225659243Sobrien (void) ioctl(FSHTTY, TIOCSDTR, NULL); 225759243Sobrien#endif /* TIOCCDTR */ 225859243Sobrien } 225959243Sobrien#endif /* TESLA */ 226059243Sobrien 226159243Sobrien { 226259243Sobrien struct process *pp, *np; 226359243Sobrien 226459243Sobrien /* Kill all processes marked for hup'ing */ 226559243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 226659243Sobrien np = pp; 226759243Sobrien do 226859243Sobrien if ((np->p_flags & PHUP) && np->p_jobid != shpgrp) { 226959243Sobrien if (killpg(np->p_jobid, SIGHUP) != -1) { 227059243Sobrien /* In case the job was suspended... */ 227159243Sobrien#ifdef SIGCONT 227259243Sobrien (void) killpg(np->p_jobid, SIGCONT); 227359243Sobrien#endif 227459243Sobrien break; 227559243Sobrien } 227659243Sobrien } 227759243Sobrien while ((np = np->p_friends) != pp); 227859243Sobrien } 227959243Sobrien } 228059243Sobrien untty(); 228159243Sobrien#ifdef NLS_CATALOGS 228259243Sobrien /* 228359243Sobrien * We need to call catclose, because SVR4 leaves symlinks behind otherwise 228459243Sobrien * in the catalog directories. We cannot close on a vforked() child, 228559243Sobrien * because messages will stop working on the parent too. 228659243Sobrien */ 228759243Sobrien if (child == 0) 2288145479Smp nlsclose(); 228959243Sobrien#endif /* NLS_CATALOGS */ 229069408Sache#ifdef WINNT_NATIVE 229159243Sobrien nt_cleanup(); 229269408Sache#endif /* WINNT_NATIVE */ 229359243Sobrien _exit(i); 229459243Sobrien} 229559243Sobrien 229659243Sobrien#ifndef _PATH_DEFPATH 229759243Sobrienstatic Char ** 2298167465Smpdefaultpath(void) 229959243Sobrien{ 230059243Sobrien char *ptr; 230159243Sobrien Char **blk, **blkp; 230259243Sobrien struct stat stb; 230359243Sobrien 2304167465Smp blkp = blk = xmalloc(sizeof(Char *) * 10); 230559243Sobrien 230659243Sobrien#ifndef NODOT 230759243Sobrien# ifndef DOTLAST 230859243Sobrien *blkp++ = Strsave(STRdot); 230959243Sobrien# endif 231059243Sobrien#endif 231159243Sobrien 231259243Sobrien#define DIRAPPEND(a) \ 231359243Sobrien if (stat(ptr = a, &stb) == 0 && S_ISDIR(stb.st_mode)) \ 231459243Sobrien *blkp++ = SAVE(ptr) 231559243Sobrien 231659243Sobrien#ifdef _PATH_LOCAL 231759243Sobrien DIRAPPEND(_PATH_LOCAL); 231859243Sobrien#endif 231959243Sobrien 232059243Sobrien#ifdef _PATH_USRUCB 232159243Sobrien DIRAPPEND(_PATH_USRUCB); 232259243Sobrien#endif 232359243Sobrien 232459243Sobrien#ifdef _PATH_USRBSD 232559243Sobrien DIRAPPEND(_PATH_USRBSD); 232659243Sobrien#endif 232759243Sobrien 232859243Sobrien#ifdef _PATH_BIN 232959243Sobrien DIRAPPEND(_PATH_BIN); 233059243Sobrien#endif 233159243Sobrien 233259243Sobrien#ifdef _PATH_USRBIN 233359243Sobrien DIRAPPEND(_PATH_USRBIN); 233459243Sobrien#endif 233559243Sobrien 233659243Sobrien#undef DIRAPPEND 233759243Sobrien 233859243Sobrien#ifndef NODOT 233959243Sobrien# ifdef DOTLAST 234059243Sobrien *blkp++ = Strsave(STRdot); 234159243Sobrien# endif 234259243Sobrien#endif 234359243Sobrien *blkp = NULL; 234459243Sobrien return (blk); 234559243Sobrien} 234659243Sobrien#endif 234759243Sobrien 234859243Sobrienstatic void 2349167465Smprecord(void) 235059243Sobrien{ 235159243Sobrien if (!fast) { 235259243Sobrien recdirs(NULL, adrof(STRsavedirs) != NULL); 235359243Sobrien rechist(NULL, adrof(STRsavehist) != NULL); 235459243Sobrien } 235559243Sobrien} 2356195609Smp 2357195609Smp/* 2358195609Smp * Grab the tty repeatedly, and give up if we are not in the correct 2359195609Smp * tty process group. 2360195609Smp */ 2361195609Smpint 2362195609Smpgrabpgrp(int fd, pid_t desired) 2363195609Smp{ 2364195609Smp struct sigaction old; 2365195609Smp pid_t pgrp; 2366195609Smp size_t i; 2367195609Smp 2368195609Smp for (i = 0; i < 100; i++) { 2369195609Smp if ((pgrp = tcgetpgrp(fd)) == -1) 2370195609Smp return -1; 2371195609Smp if (pgrp == desired) 2372195609Smp return 0; 2373195609Smp (void)sigaction(SIGTTIN, NULL, &old); 2374195609Smp (void)signal(SIGTTIN, SIG_DFL); 2375195609Smp (void)kill(0, SIGTTIN); 2376195609Smp (void)sigaction(SIGTTIN, &old, NULL); 2377195609Smp } 2378195609Smp errno = EPERM; 2379195609Smp return -1; 2380195609Smp} 2381