main.c

Go to the documentation of this file.
00001 /*-
00002  * Copyright (c) 1991 The Regents of the University of California.
00003  * All rights reserved.
00004  *
00005  * This code is derived from software contributed to Berkeley by
00006  * Kenneth Almquist.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions
00010  * are met:
00011  * 1. Redistributions of source code must retain the above copyright
00012  *    notice, this list of conditions and the following disclaimer.
00013  * 2. Redistributions in binary form must reproduce the above copyright
00014  *    notice, this list of conditions and the following disclaimer in the
00015  *    documentation and/or other materials provided with the distribution.
00016  * 3. All advertising materials mentioning features or use of this software
00017  *    must display the following acknowledgement:
00018  *      This product includes software developed by the University of
00019  *      California, Berkeley and its contributors.
00020  * 4. Neither the name of the University nor the names of its contributors
00021  *    may be used to endorse or promote products derived from this software
00022  *    without specific prior written permission.
00023  *
00024  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
00025  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00026  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00027  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
00028  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00029  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00030  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00031  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00032  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00033  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00034  * SUCH DAMAGE.
00035  */
00036 
00037 #ifndef lint
00038 char copyright[] =
00039 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
00040  All rights reserved.\n";
00041 #endif /* not lint */
00042 
00043 #ifndef lint
00044 static char sccsid[] = "@(#)main.c      5.2 (Berkeley) 3/13/91";
00045 #endif /* not lint */
00046 
00047 #include <sys/types.h>
00048 #include <signal.h>
00049 #include <fcntl.h>
00050 #include "shell.h"
00051 #include "main.h"
00052 #include "mail.h"
00053 #include "options.h"
00054 #include "output.h"
00055 #include "parser.h"
00056 #include "nodes.h"
00057 #include "eval.h"
00058 #include "jobs.h"
00059 #include "input.h"
00060 #include "trap.h"
00061 #if ATTY
00062 #include "var.h"
00063 #endif
00064 #include "memalloc.h"
00065 #include "error.h"
00066 #include "init.h"
00067 #include "mystring.h"
00068 
00069 #define PROFILE 0
00070 
00071 int rootpid;
00072 int rootshell;
00073 STATIC union node *curcmd;
00074 STATIC union node *prevcmd;
00075 extern int errno;
00076 #if PROFILE
00077 short profile_buf[16384];
00078 extern int etext();
00079 #endif
00080 
00081 #ifdef __STDC__
00082 STATIC void read_profile(char *);
00083 char *getenv(char *);
00084 #else
00085 STATIC void read_profile();
00086 char *getenv();
00087 #endif
00088 
00089 
00090 /*
00091  * Main routine.  We initialize things, parse the arguments, execute
00092  * profiles if we're a login shell, and then call cmdloop to execute
00093  * commands.  The setjmp call sets up the location to jump to when an
00094  * exception occurs.  When an exception occurs the variable "state"
00095  * is used to figure out how far we had gotten.
00096  */
00097 
00098 main(argc, argv)  char **argv; {
00099         struct jmploc jmploc;
00100         struct stackmark smark;
00101         volatile int state;
00102         char *shinit, *home;
00103         char *profile = NULL, *ashrc = NULL;
00104 
00105 #if PROFILE
00106         monitor(4, etext, profile_buf, sizeof profile_buf, 50);
00107 #endif
00108         state = 0;
00109         if (setjmp(jmploc.loc)) {
00110                 /*
00111                  * When a shell procedure is executed, we raise the
00112                  * exception EXSHELLPROC to clean up before executing
00113                  * the shell procedure.
00114                  */
00115                 if (exception == EXSHELLPROC) {
00116                         rootpid = getpid();
00117                         rootshell = 1;
00118                         minusc = NULL;
00119                         state = 3;
00120                 } else if (state == 0 || iflag == 0 || ! rootshell)
00121                         exitshell(2);
00122                 reset();
00123 #if ATTY
00124                 if (exception == EXINT
00125                  && (! attyset() || equal(termval(), "emacs"))) {
00126 #else
00127                 if (exception == EXINT) {
00128 #endif
00129                         out2c('\n');
00130                         flushout(&errout);
00131                 }
00132                 popstackmark(&smark);
00133                 FORCEINTON;                             /* enable interrupts */
00134                 if (state == 1)
00135                         goto state1;
00136                 else if (state == 2)
00137                         goto state2;
00138                 else if (state == 3)
00139                         goto state3;
00140                 else
00141                         goto state4;
00142         }
00143         handler = &jmploc;
00144 #if DEBUG
00145         opentrace();
00146         trputs("Shell args:  ");  trargs(argv);
00147 #endif
00148         rootpid = getpid();
00149         rootshell = 1;
00150         init();
00151         setstackmark(&smark);
00152         procargs(argc, argv);
00153         if (eflag) eflag = 2;   /* Truly enable [ex]flag after init. */
00154         if (xflag) xflag = 2;
00155         if (argv[0] && argv[0][0] == '-') {
00156                 state = 1;
00157                 read_profile("/etc/profile");
00158 state1:
00159                 state = 2;
00160                 if ((home = getenv("HOME")) != NULL
00161                     && (profile = (char *) malloc(strlen(home) + 10)) != NULL)
00162                 {
00163                         strcpy(profile, home);
00164                         strcat(profile, "/.profile");
00165                         read_profile(profile);
00166                 } else {
00167                         read_profile(".profile");
00168                 }
00169         } else if ((sflag || minusc) && (shinit = getenv("SHINIT")) != NULL) {
00170                 state = 2;
00171                 evalstring(shinit);
00172         }
00173 state2:
00174         if (profile != NULL) free(profile);
00175 
00176         state = 3;
00177         if (!argv[0] || argv[0][0] != '-') {
00178                 if ((home = getenv("HOME")) != NULL
00179                         && (ashrc = (char *) malloc(strlen(home) + 8)) != NULL)
00180                 {
00181                         strcpy(ashrc, home);
00182                         strcat(ashrc, "/.ashrc");
00183                         read_profile(ashrc);
00184                 }
00185         }
00186 state3:
00187         if (ashrc != NULL) free(ashrc);
00188         if (eflag) eflag = 1;   /* Init done, enable [ex]flag */
00189         if (xflag) xflag = 1;
00190         exitstatus = 0;         /* Init shouldn't influence initial $? */
00191 
00192         state = 4;
00193         if (minusc) {
00194                 evalstring(minusc);
00195         }
00196         if (sflag || minusc == NULL) {
00197 state4:
00198                 cmdloop(1);
00199         }
00200 #if PROFILE
00201         monitor(0);
00202 #endif
00203         exitshell(exitstatus);
00204 }
00205 
00206 
00207 /*
00208  * Read and execute commands.  "Top" is nonzero for the top level command
00209  * loop; it turns on prompting if the shell is interactive.
00210  */
00211 
00212 void
00213 cmdloop(top) {
00214         union node *n;
00215         struct stackmark smark;
00216         int inter;
00217         int numeof;
00218 
00219         TRACE(("cmdloop(%d) called\n", top));
00220         setstackmark(&smark);
00221         numeof = 0;
00222         for (;;) {
00223                 if (pendingsigs)
00224                         dotrap();
00225                 inter = 0;
00226                 if (iflag && top) {
00227                         inter++;
00228                         showjobs(1);
00229                         chkmail(0);
00230                         flushout(&output);
00231                 }
00232                 n = parsecmd(inter);
00233 #if DEBUG
00234                 /* showtree(n); */
00235 #endif
00236                 if (n == NEOF) {
00237                         if (Iflag == 0 || numeof >= 50)
00238                                 break;
00239                         out2str("\nUse \"exit\" to leave shell.\n");
00240                         numeof++;
00241                 } else if (n != NULL && nflag == 0) {
00242                         if (inter) {
00243                                 INTOFF;
00244                                 if (prevcmd)
00245                                         freefunc(prevcmd);
00246                                 prevcmd = curcmd;
00247                                 curcmd = copyfunc(n);
00248                                 INTON;
00249                         }
00250                         evaltree(n, 0);
00251 #ifdef notdef
00252                         if (exitstatus)                               /*DEBUG*/
00253                                 outfmt(&errout, "Exit status 0x%X\n", exitstatus);
00254 #endif
00255                 }
00256                 popstackmark(&smark);
00257         }
00258         popstackmark(&smark);           /* unnecessary */
00259 }
00260 
00261 
00262 
00263 /*
00264  * Read /etc/profile or .profile.  Return on error.
00265  */
00266 
00267 STATIC void
00268 read_profile(name)
00269         char *name;
00270         {
00271         int fd;
00272 
00273         INTOFF;
00274         if ((fd = open(name, O_RDONLY)) >= 0)
00275                 setinputfd(fd, 1);
00276         INTON;
00277         if (fd < 0)
00278                 return;
00279         cmdloop(0);
00280         popfile();
00281 }
00282 
00283 
00284 
00285 /*
00286  * Read a file containing shell functions.
00287  */
00288 
00289 void
00290 readcmdfile(name)
00291         char *name;
00292         {
00293         int fd;
00294 
00295         INTOFF;
00296         if ((fd = open(name, O_RDONLY)) >= 0)
00297                 setinputfd(fd, 1);
00298         else
00299                 error("Can't open %s", name);
00300         INTON;
00301         cmdloop(0);
00302         popfile();
00303 }
00304 
00305 
00306 /*
00307  * Take commands from a file.  To be compatable we should do a path
00308  * search for the file, but a path search doesn't make any sense.
00309  */
00310 
00311 dotcmd(argc, argv)  char **argv; {
00312         exitstatus = 0;
00313         if (argc >= 2) {                /* That's what SVR2 does */
00314                 setinputfile(argv[1], 1);
00315                 commandname = argv[1];
00316                 cmdloop(0);
00317                 popfile();
00318         }
00319         return exitstatus;
00320 }
00321 
00322 
00323 exitcmd(argc, argv)  char **argv; {
00324         extern int oexitstatus;
00325         if (argc > 1)
00326                 exitstatus = number(argv[1]);
00327         else
00328                 exitstatus = oexitstatus;
00329         exitshell(exitstatus);
00330 }
00331 
00332 
00333 lccmd(argc, argv)  char **argv; {
00334         if (argc > 1) {
00335                 defun(argv[1], prevcmd);
00336                 return 0;
00337         } else {
00338                 INTOFF;
00339                 freefunc(curcmd);
00340                 curcmd = prevcmd;
00341                 prevcmd = NULL;
00342                 INTON;
00343                 evaltree(curcmd, 0);
00344                 return exitstatus;
00345         }
00346 }
00347 
00348 
00349 
00350 #ifdef notdef
00351 /*
00352  * Should never be called.
00353  */
00354 
00355 void
00356 exit(exitstatus) {
00357         _exit(exitstatus);
00358 }
00359 #endif

Generated on Fri Apr 14 22:56:40 2006 for minix by  doxygen 1.4.6