main.c revision 17525
1215651Sweongyo/*- 2215651Sweongyo * Copyright (c) 1991, 1993 3215651Sweongyo * The Regents of the University of California. All rights reserved. 4215651Sweongyo * 5215651Sweongyo * This code is derived from software contributed to Berkeley by 6215651Sweongyo * Kenneth Almquist. 7215651Sweongyo * 8215651Sweongyo * Redistribution and use in source and binary forms, with or without 9215651Sweongyo * modification, are permitted provided that the following conditions 10215651Sweongyo * are met: 11215651Sweongyo * 1. Redistributions of source code must retain the above copyright 12215651Sweongyo * notice, this list of conditions and the following disclaimer. 13215651Sweongyo * 2. Redistributions in binary form must reproduce the above copyright 14215651Sweongyo * notice, this list of conditions and the following disclaimer in the 15215651Sweongyo * documentation and/or other materials provided with the distribution. 16215651Sweongyo * 3. All advertising materials mentioning features or use of this software 17215651Sweongyo * must display the following acknowledgement: 18215651Sweongyo * This product includes software developed by the University of 19215651Sweongyo * California, Berkeley and its contributors. 20215651Sweongyo * 4. Neither the name of the University nor the names of its contributors 21215651Sweongyo * may be used to endorse or promote products derived from this software 22215651Sweongyo * without specific prior written permission. 23215651Sweongyo * 24215651Sweongyo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25215651Sweongyo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26215651Sweongyo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27215651Sweongyo * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28215651Sweongyo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29215651Sweongyo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30215651Sweongyo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31215651Sweongyo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32215651Sweongyo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33215651Sweongyo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34215651Sweongyo * SUCH DAMAGE. 35215803Sweongyo * 36215651Sweongyo * $Id: main.c,v 1.3 1995/05/30 00:07:18 rgrimes Exp $ 37215651Sweongyo */ 38232035Shselasky 39215803Sweongyo#ifndef lint 40215803Sweongyostatic char copyright[] = 41215651Sweongyo"@(#) Copyright (c) 1991, 1993\n\ 42215651Sweongyo The Regents of the University of California. All rights reserved.\n"; 43215651Sweongyo#endif /* not lint */ 44215651Sweongyo 45215651Sweongyo#ifndef lint 46215651Sweongyostatic char sccsid[] = "@(#)main.c 8.1 (Berkeley) 5/31/93"; 47215651Sweongyo#endif /* not lint */ 48215651Sweongyo 49232035Shselasky#include <signal.h> 50215651Sweongyo#include <fcntl.h> 51215651Sweongyo#include <locale.h> 52215651Sweongyo 53221604Shselasky#include "shell.h" 54221604Shselasky#include "main.h" 55215651Sweongyo#include "mail.h" 56232035Shselasky#include "options.h" 57232035Shselasky#include "output.h" 58232035Shselasky#include "parser.h" 59232035Shselasky#include "nodes.h" 60232035Shselasky#include "eval.h" 61232035Shselasky#include "jobs.h" 62232035Shselasky#include "input.h" 63232035Shselasky#include "trap.h" 64232035Shselasky#include "var.h" 65232035Shselasky#include "memalloc.h" 66232035Shselasky#include "error.h" 67232035Shselasky#include "init.h" 68232035Shselasky#include "mystring.h" 69232035Shselasky 70232035Shselasky#define PROFILE 0 71232035Shselasky 72232035Shselaskyint rootpid; 73232035Shselaskyint rootshell; 74232035ShselaskySTATIC union node *curcmd; 75232035ShselaskySTATIC union node *prevcmd; 76215651Sweongyoextern int errno; 77215651Sweongyo#if PROFILE 78220301Shselaskyshort profile_buf[16384]; 79220301Shselaskyextern int etext(); 80215651Sweongyo#endif 81215651Sweongyo 82215651Sweongyo#ifdef __STDC__ 83215651SweongyoSTATIC void read_profile(char *); 84215651Sweongyochar *getenv(char *); 85215651Sweongyo#else 86215651SweongyoSTATIC void read_profile(); 87215651Sweongyochar *getenv(); 88220301Shselasky#endif 89215651Sweongyo 90220301Shselasky 91220301Shselasky/* 92220301Shselasky * Main routine. We initialize things, parse the arguments, execute 93215651Sweongyo * profiles if we're a login shell, and then call cmdloop to execute 94215651Sweongyo * commands. The setjmp call sets up the location to jump to when an 95215651Sweongyo * exception occurs. When an exception occurs the variable "state" 96215651Sweongyo * is used to figure out how far we had gotten. 97215651Sweongyo */ 98218010Shselasky 99215651Sweongyomain(argc, argv) char **argv; { 100215651Sweongyo struct jmploc jmploc; 101215651Sweongyo struct stackmark smark; 102220301Shselasky volatile int state; 103215651Sweongyo char *shinit; 104215651Sweongyo 105215651Sweongyo#if PROFILE 106215651Sweongyo monitor(4, etext, profile_buf, sizeof profile_buf, 50); 107215651Sweongyo#endif 108215651Sweongyo (void) setlocale(LC_ALL, ""); 109215651Sweongyo state = 0; 110215651Sweongyo if (setjmp(jmploc.loc)) { 111215651Sweongyo /* 112215651Sweongyo * When a shell procedure is executed, we raise the 113215651Sweongyo * exception EXSHELLPROC to clean up before executing 114215651Sweongyo * the shell procedure. 115215651Sweongyo */ 116215651Sweongyo if (exception == EXSHELLPROC) { 117215651Sweongyo rootpid = getpid(); 118215651Sweongyo rootshell = 1; 119215651Sweongyo minusc = NULL; 120215651Sweongyo state = 3; 121215651Sweongyo } else if (state == 0 || iflag == 0 || ! rootshell) 122215651Sweongyo exitshell(2); 123215651Sweongyo reset(); 124215651Sweongyo if (exception == EXINT 125215651Sweongyo#if ATTY 126215651Sweongyo && (! attyset() || equal(termval(), "emacs")) 127215651Sweongyo#endif 128215651Sweongyo ) { 129215651Sweongyo out2c('\n'); 130215651Sweongyo flushout(&errout); 131215651Sweongyo } 132215651Sweongyo popstackmark(&smark); 133220301Shselasky FORCEINTON; /* enable interrupts */ 134215651Sweongyo if (state == 1) 135215651Sweongyo goto state1; 136215651Sweongyo else if (state == 2) 137215651Sweongyo goto state2; 138215651Sweongyo else if (state == 3) 139215651Sweongyo goto state3; 140220301Shselasky else 141220301Shselasky goto state4; 142220301Shselasky } 143220301Shselasky handler = &jmploc; 144220301Shselasky#ifdef DEBUG 145220301Shselasky opentrace(); 146220301Shselasky trputs("Shell args: "); trargs(argv); 147220301Shselasky#endif 148232035Shselasky rootpid = getpid(); 149232035Shselasky rootshell = 1; 150232035Shselasky init(); 151215651Sweongyo setstackmark(&smark); 152232035Shselasky procargs(argc, argv); 153232035Shselasky if (argv[0] && argv[0][0] == '-') { 154232035Shselasky state = 1; 155232035Shselasky read_profile("/etc/profile"); 156232035Shselaskystate1: 157232035Shselasky state = 2; 158232035Shselasky read_profile(".profile"); 159232035Shselasky } 160232035Shselaskystate2: 161232035Shselasky state = 3; 162232035Shselasky if ((shinit = lookupvar("ENV")) != NULL && 163232035Shselasky *shinit != '\0') { 164232035Shselasky state = 3; 165232035Shselasky read_profile(shinit); 166232035Shselasky } 167232035Shselaskystate3: 168232035Shselasky state = 4; 169232035Shselasky if (minusc) { 170232035Shselasky evalstring(minusc); 171232035Shselasky } 172232035Shselasky if (sflag || minusc == NULL) { 173232035Shselaskystate4: /* XXX ??? - why isn't this before the "if" statement */ 174232035Shselasky cmdloop(1); 175232035Shselasky } 176232035Shselasky#if PROFILE 177232035Shselasky monitor(0); 178232035Shselasky#endif 179232035Shselasky exitshell(exitstatus); 180232035Shselasky} 181232035Shselasky 182232035Shselasky 183232035Shselasky/* 184232035Shselasky * Read and execute commands. "Top" is nonzero for the top level command 185232035Shselasky * loop; it turns on prompting if the shell is interactive. 186232035Shselasky */ 187232035Shselasky 188232035Shselaskyvoid 189232035Shselaskycmdloop(top) { 190232035Shselasky union node *n; 191232035Shselasky struct stackmark smark; 192232035Shselasky int inter; 193232035Shselasky int numeof = 0; 194232035Shselasky 195232035Shselasky TRACE(("cmdloop(%d) called\n", top)); 196232035Shselasky setstackmark(&smark); 197232035Shselasky for (;;) { 198232035Shselasky if (pendingsigs) 199232035Shselasky dotrap(); 200232035Shselasky inter = 0; 201232035Shselasky if (iflag && top) { 202232035Shselasky inter++; 203232035Shselasky showjobs(1); 204232035Shselasky chkmail(0); 205232035Shselasky flushout(&output); 206232035Shselasky } 207232035Shselasky n = parsecmd(inter); 208232035Shselasky /* showtree(n); DEBUG */ 209232035Shselasky if (n == NEOF) { 210232035Shselasky if (!top || numeof >= 50) 211232035Shselasky break; 212232035Shselasky if (!stoppedjobs()) { 213232035Shselasky if (!Iflag) 214232035Shselasky break; 215232035Shselasky out2str("\nUse \"exit\" to leave shell.\n"); 216232035Shselasky } 217232035Shselasky numeof++; 218232035Shselasky } else if (n != NULL && nflag == 0) { 219232035Shselasky job_warning = (job_warning == 2) ? 1 : 0; 220232035Shselasky numeof = 0; 221232035Shselasky evaltree(n, 0); 222232035Shselasky } 223232035Shselasky popstackmark(&smark); 224232035Shselasky } 225232035Shselasky popstackmark(&smark); /* unnecessary */ 226232035Shselasky} 227232035Shselasky 228232035Shselasky 229232035Shselasky 230232035Shselasky/* 231232035Shselasky * Read /etc/profile or .profile. Return on error. 232232035Shselasky */ 233232035Shselasky 234232035ShselaskySTATIC void 235232035Shselaskyread_profile(name) 236232035Shselasky char *name; 237232035Shselasky { 238232035Shselasky int fd; 239232035Shselasky 240232035Shselasky INTOFF; 241232035Shselasky if ((fd = open(name, O_RDONLY)) >= 0) 242232035Shselasky setinputfd(fd, 1); 243232035Shselasky INTON; 244232035Shselasky if (fd < 0) 245232035Shselasky return; 246232035Shselasky cmdloop(0); 247232035Shselasky popfile(); 248232035Shselasky} 249232035Shselasky 250232035Shselasky 251232035Shselasky 252232035Shselasky/* 253232035Shselasky * Read a file containing shell functions. 254232035Shselasky */ 255232035Shselasky 256232035Shselaskyvoid 257215651Sweongyoreadcmdfile(name) 258215651Sweongyo char *name; 259215651Sweongyo { 260215651Sweongyo int fd; 261215651Sweongyo 262215651Sweongyo INTOFF; 263215651Sweongyo if ((fd = open(name, O_RDONLY)) >= 0) 264220301Shselasky setinputfd(fd, 1); 265220301Shselasky else 266220301Shselasky error("Can't open %s", name); 267220301Shselasky INTON; 268220301Shselasky cmdloop(0); 269220301Shselasky popfile(); 270220301Shselasky} 271220301Shselasky 272220301Shselasky 273220301Shselasky 274220301Shselasky/* 275220301Shselasky * Take commands from a file. To be compatable we should do a path 276220301Shselasky * search for the file, but a path search doesn't make any sense. 277220301Shselasky */ 278220301Shselasky 279220301Shselaskydotcmd(argc, argv) char **argv; { 280220301Shselasky exitstatus = 0; 281220301Shselasky if (argc >= 2) { /* That's what SVR2 does */ 282220301Shselasky setinputfile(argv[1], 1); 283220301Shselasky commandname = argv[1]; 284220301Shselasky cmdloop(0); 285220301Shselasky popfile(); 286220301Shselasky } 287220301Shselasky return exitstatus; 288215651Sweongyo} 289220301Shselasky 290215651Sweongyo 291220301Shselaskyexitcmd(argc, argv) char **argv; { 292220301Shselasky if (stoppedjobs()) 293220301Shselasky return; 294220301Shselasky if (argc > 1) 295220301Shselasky exitstatus = number(argv[1]); 296220301Shselasky exitshell(exitstatus); 297220301Shselasky} 298220301Shselasky 299220301Shselasky 300220301Shselasky#ifdef notdef 301220301Shselasky/* 302215651Sweongyo * Should never be called. 303215651Sweongyo */ 304215651Sweongyo 305220301Shselaskyvoid 306215651Sweongyoexit(exitstatus) { 307220301Shselasky _exit(exitstatus); 308220301Shselasky} 309220301Shselasky#endif 310220301Shselasky