1*0a6a1f1dSLionel Sambuc /* $NetBSD: main.c,v 1.59 2015/05/26 21:35:15 christos Exp $ */
2d90bee97SLionel Sambuc
3d90bee97SLionel Sambuc /*-
4d90bee97SLionel Sambuc * Copyright (c) 1991, 1993
5d90bee97SLionel Sambuc * The Regents of the University of California. All rights reserved.
6d90bee97SLionel Sambuc *
7d90bee97SLionel Sambuc * This code is derived from software contributed to Berkeley by
8d90bee97SLionel Sambuc * Kenneth Almquist.
9d90bee97SLionel Sambuc *
10d90bee97SLionel Sambuc * Redistribution and use in source and binary forms, with or without
11d90bee97SLionel Sambuc * modification, are permitted provided that the following conditions
12d90bee97SLionel Sambuc * are met:
13d90bee97SLionel Sambuc * 1. Redistributions of source code must retain the above copyright
14d90bee97SLionel Sambuc * notice, this list of conditions and the following disclaimer.
15d90bee97SLionel Sambuc * 2. Redistributions in binary form must reproduce the above copyright
16d90bee97SLionel Sambuc * notice, this list of conditions and the following disclaimer in the
17d90bee97SLionel Sambuc * documentation and/or other materials provided with the distribution.
18d90bee97SLionel Sambuc * 3. Neither the name of the University nor the names of its contributors
19d90bee97SLionel Sambuc * may be used to endorse or promote products derived from this software
20d90bee97SLionel Sambuc * without specific prior written permission.
21d90bee97SLionel Sambuc *
22d90bee97SLionel Sambuc * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23d90bee97SLionel Sambuc * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24d90bee97SLionel Sambuc * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25d90bee97SLionel Sambuc * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26d90bee97SLionel Sambuc * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27d90bee97SLionel Sambuc * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28d90bee97SLionel Sambuc * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29d90bee97SLionel Sambuc * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30d90bee97SLionel Sambuc * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31d90bee97SLionel Sambuc * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32d90bee97SLionel Sambuc * SUCH DAMAGE.
33d90bee97SLionel Sambuc */
34d90bee97SLionel Sambuc
35d90bee97SLionel Sambuc #include <sys/cdefs.h>
36d90bee97SLionel Sambuc #ifndef lint
37d90bee97SLionel Sambuc __COPYRIGHT("@(#) Copyright (c) 1991, 1993\
38d90bee97SLionel Sambuc The Regents of the University of California. All rights reserved.");
39d90bee97SLionel Sambuc #endif /* not lint */
40d90bee97SLionel Sambuc
41d90bee97SLionel Sambuc #ifndef lint
42d90bee97SLionel Sambuc #if 0
43d90bee97SLionel Sambuc static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95";
44d90bee97SLionel Sambuc #else
45*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: main.c,v 1.59 2015/05/26 21:35:15 christos Exp $");
46d90bee97SLionel Sambuc #endif
47d90bee97SLionel Sambuc #endif /* not lint */
48d90bee97SLionel Sambuc
49d90bee97SLionel Sambuc #include <errno.h>
50d90bee97SLionel Sambuc #include <stdio.h>
51d90bee97SLionel Sambuc #include <signal.h>
52d90bee97SLionel Sambuc #include <sys/stat.h>
53d90bee97SLionel Sambuc #include <unistd.h>
54d90bee97SLionel Sambuc #include <stdlib.h>
55d90bee97SLionel Sambuc #include <locale.h>
56d90bee97SLionel Sambuc #include <fcntl.h>
57d90bee97SLionel Sambuc
58d90bee97SLionel Sambuc
59d90bee97SLionel Sambuc #include "shell.h"
60d90bee97SLionel Sambuc #include "main.h"
61d90bee97SLionel Sambuc #include "mail.h"
62d90bee97SLionel Sambuc #include "options.h"
63d90bee97SLionel Sambuc #include "builtins.h"
64d90bee97SLionel Sambuc #include "output.h"
65d90bee97SLionel Sambuc #include "parser.h"
66d90bee97SLionel Sambuc #include "nodes.h"
67d90bee97SLionel Sambuc #include "expand.h"
68d90bee97SLionel Sambuc #include "eval.h"
69d90bee97SLionel Sambuc #include "jobs.h"
70d90bee97SLionel Sambuc #include "input.h"
71d90bee97SLionel Sambuc #include "trap.h"
72d90bee97SLionel Sambuc #include "var.h"
73d90bee97SLionel Sambuc #include "show.h"
74d90bee97SLionel Sambuc #include "memalloc.h"
75d90bee97SLionel Sambuc #include "error.h"
76d90bee97SLionel Sambuc #include "init.h"
77d90bee97SLionel Sambuc #include "mystring.h"
78d90bee97SLionel Sambuc #include "exec.h"
79d90bee97SLionel Sambuc #include "cd.h"
80d90bee97SLionel Sambuc
81d90bee97SLionel Sambuc #define PROFILE 0
82d90bee97SLionel Sambuc
83d90bee97SLionel Sambuc int rootpid;
84d90bee97SLionel Sambuc int rootshell;
85d90bee97SLionel Sambuc int posix;
86d90bee97SLionel Sambuc #if PROFILE
87d90bee97SLionel Sambuc short profile_buf[16384];
88d90bee97SLionel Sambuc extern int etext();
89d90bee97SLionel Sambuc #endif
90d90bee97SLionel Sambuc
91d90bee97SLionel Sambuc STATIC void read_profile(const char *);
92d90bee97SLionel Sambuc int main(int, char **);
93d90bee97SLionel Sambuc
94d90bee97SLionel Sambuc /*
95d90bee97SLionel Sambuc * Main routine. We initialize things, parse the arguments, execute
96d90bee97SLionel Sambuc * profiles if we're a login shell, and then call cmdloop to execute
97d90bee97SLionel Sambuc * commands. The setjmp call sets up the location to jump to when an
98d90bee97SLionel Sambuc * exception occurs. When an exception occurs the variable "state"
99d90bee97SLionel Sambuc * is used to figure out how far we had gotten.
100d90bee97SLionel Sambuc */
101d90bee97SLionel Sambuc
102d90bee97SLionel Sambuc int
main(int argc,char ** argv)103d90bee97SLionel Sambuc main(int argc, char **argv)
104d90bee97SLionel Sambuc {
105d90bee97SLionel Sambuc struct jmploc jmploc;
106d90bee97SLionel Sambuc struct stackmark smark;
107d90bee97SLionel Sambuc volatile int state;
108d90bee97SLionel Sambuc char *shinit;
109*0a6a1f1dSLionel Sambuc uid_t uid;
110*0a6a1f1dSLionel Sambuc gid_t gid;
111*0a6a1f1dSLionel Sambuc
112*0a6a1f1dSLionel Sambuc uid = getuid();
113*0a6a1f1dSLionel Sambuc gid = getgid();
114d90bee97SLionel Sambuc
115d90bee97SLionel Sambuc setlocale(LC_ALL, "");
116d90bee97SLionel Sambuc
117d90bee97SLionel Sambuc posix = getenv("POSIXLY_CORRECT") != NULL;
118d90bee97SLionel Sambuc #if PROFILE
119d90bee97SLionel Sambuc monitor(4, etext, profile_buf, sizeof profile_buf, 50);
120d90bee97SLionel Sambuc #endif
121d90bee97SLionel Sambuc state = 0;
122d90bee97SLionel Sambuc if (setjmp(jmploc.loc)) {
123d90bee97SLionel Sambuc /*
124d90bee97SLionel Sambuc * When a shell procedure is executed, we raise the
125d90bee97SLionel Sambuc * exception EXSHELLPROC to clean up before executing
126d90bee97SLionel Sambuc * the shell procedure.
127d90bee97SLionel Sambuc */
128d90bee97SLionel Sambuc switch (exception) {
129d90bee97SLionel Sambuc case EXSHELLPROC:
130d90bee97SLionel Sambuc rootpid = getpid();
131d90bee97SLionel Sambuc rootshell = 1;
132d90bee97SLionel Sambuc minusc = NULL;
133d90bee97SLionel Sambuc state = 3;
134d90bee97SLionel Sambuc break;
135d90bee97SLionel Sambuc
136d90bee97SLionel Sambuc case EXEXEC:
137d90bee97SLionel Sambuc exitstatus = exerrno;
138d90bee97SLionel Sambuc break;
139d90bee97SLionel Sambuc
140d90bee97SLionel Sambuc case EXERROR:
141d90bee97SLionel Sambuc exitstatus = 2;
142d90bee97SLionel Sambuc break;
143d90bee97SLionel Sambuc
144d90bee97SLionel Sambuc default:
145d90bee97SLionel Sambuc break;
146d90bee97SLionel Sambuc }
147d90bee97SLionel Sambuc
148d90bee97SLionel Sambuc if (exception != EXSHELLPROC) {
149d90bee97SLionel Sambuc if (state == 0 || iflag == 0 || ! rootshell)
150d90bee97SLionel Sambuc exitshell(exitstatus);
151d90bee97SLionel Sambuc }
152d90bee97SLionel Sambuc reset();
153d90bee97SLionel Sambuc if (exception == EXINT
154d90bee97SLionel Sambuc #if ATTY
155d90bee97SLionel Sambuc && (! attyset() || equal(termval(), "emacs"))
156d90bee97SLionel Sambuc #endif
157d90bee97SLionel Sambuc ) {
158d90bee97SLionel Sambuc out2c('\n');
159d90bee97SLionel Sambuc flushout(&errout);
160d90bee97SLionel Sambuc }
161d90bee97SLionel Sambuc popstackmark(&smark);
162d90bee97SLionel Sambuc FORCEINTON; /* enable interrupts */
163d90bee97SLionel Sambuc if (state == 1)
164d90bee97SLionel Sambuc goto state1;
165d90bee97SLionel Sambuc else if (state == 2)
166d90bee97SLionel Sambuc goto state2;
167d90bee97SLionel Sambuc else if (state == 3)
168d90bee97SLionel Sambuc goto state3;
169d90bee97SLionel Sambuc else
170d90bee97SLionel Sambuc goto state4;
171d90bee97SLionel Sambuc }
172d90bee97SLionel Sambuc handler = &jmploc;
173d90bee97SLionel Sambuc #ifdef DEBUG
174d90bee97SLionel Sambuc #if DEBUG == 2
175d90bee97SLionel Sambuc debug = 1;
176d90bee97SLionel Sambuc #endif
177d90bee97SLionel Sambuc opentrace();
178d90bee97SLionel Sambuc trputs("Shell args: "); trargs(argv);
179d90bee97SLionel Sambuc #endif
180d90bee97SLionel Sambuc rootpid = getpid();
181d90bee97SLionel Sambuc rootshell = 1;
182d90bee97SLionel Sambuc init();
183d90bee97SLionel Sambuc initpwd();
184d90bee97SLionel Sambuc setstackmark(&smark);
185d90bee97SLionel Sambuc procargs(argc, argv);
186*0a6a1f1dSLionel Sambuc
187*0a6a1f1dSLionel Sambuc /*
188*0a6a1f1dSLionel Sambuc * Limit bogus system(3) or popen(3) calls in setuid binaries,
189*0a6a1f1dSLionel Sambuc * by requiring the -p flag
190*0a6a1f1dSLionel Sambuc */
191*0a6a1f1dSLionel Sambuc if (!pflag && (uid != geteuid() || gid != getegid())) {
192*0a6a1f1dSLionel Sambuc setuid(uid);
193*0a6a1f1dSLionel Sambuc setgid(gid);
194*0a6a1f1dSLionel Sambuc /* PS1 might need to be changed accordingly. */
195*0a6a1f1dSLionel Sambuc choose_ps1();
196*0a6a1f1dSLionel Sambuc }
197*0a6a1f1dSLionel Sambuc
198d90bee97SLionel Sambuc if (argv[0] && argv[0][0] == '-') {
199d90bee97SLionel Sambuc state = 1;
200d90bee97SLionel Sambuc read_profile("/etc/profile");
201d90bee97SLionel Sambuc state1:
202d90bee97SLionel Sambuc state = 2;
203d90bee97SLionel Sambuc read_profile(".profile");
204d90bee97SLionel Sambuc }
205d90bee97SLionel Sambuc state2:
206d90bee97SLionel Sambuc state = 3;
207d90bee97SLionel Sambuc if ((iflag || !posix) &&
208d90bee97SLionel Sambuc getuid() == geteuid() && getgid() == getegid()) {
209d90bee97SLionel Sambuc if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
210d90bee97SLionel Sambuc state = 3;
211d90bee97SLionel Sambuc read_profile(shinit);
212d90bee97SLionel Sambuc }
213d90bee97SLionel Sambuc }
214d90bee97SLionel Sambuc state3:
215d90bee97SLionel Sambuc state = 4;
216d90bee97SLionel Sambuc if (sflag == 0 || minusc) {
217d90bee97SLionel Sambuc static int sigs[] = {
218d90bee97SLionel Sambuc SIGINT, SIGQUIT, SIGHUP,
219d90bee97SLionel Sambuc #ifdef SIGTSTP
220d90bee97SLionel Sambuc SIGTSTP,
221d90bee97SLionel Sambuc #endif
222d90bee97SLionel Sambuc SIGPIPE
223d90bee97SLionel Sambuc };
224d90bee97SLionel Sambuc #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
225d90bee97SLionel Sambuc size_t i;
226d90bee97SLionel Sambuc
227d90bee97SLionel Sambuc for (i = 0; i < SIGSSIZE; i++)
228d90bee97SLionel Sambuc setsignal(sigs[i], 0);
229d90bee97SLionel Sambuc }
230d90bee97SLionel Sambuc
231d90bee97SLionel Sambuc if (minusc)
232d90bee97SLionel Sambuc evalstring(minusc, 0);
233d90bee97SLionel Sambuc
234d90bee97SLionel Sambuc if (sflag || minusc == NULL) {
235d90bee97SLionel Sambuc state4: /* XXX ??? - why isn't this before the "if" statement */
236d90bee97SLionel Sambuc cmdloop(1);
237d90bee97SLionel Sambuc }
238d90bee97SLionel Sambuc #if PROFILE
239d90bee97SLionel Sambuc monitor(0);
240d90bee97SLionel Sambuc #endif
241d90bee97SLionel Sambuc exitshell(exitstatus);
242d90bee97SLionel Sambuc /* NOTREACHED */
243d90bee97SLionel Sambuc }
244d90bee97SLionel Sambuc
245d90bee97SLionel Sambuc
246d90bee97SLionel Sambuc /*
247d90bee97SLionel Sambuc * Read and execute commands. "Top" is nonzero for the top level command
248d90bee97SLionel Sambuc * loop; it turns on prompting if the shell is interactive.
249d90bee97SLionel Sambuc */
250d90bee97SLionel Sambuc
251d90bee97SLionel Sambuc void
cmdloop(int top)252d90bee97SLionel Sambuc cmdloop(int top)
253d90bee97SLionel Sambuc {
254d90bee97SLionel Sambuc union node *n;
255d90bee97SLionel Sambuc struct stackmark smark;
256d90bee97SLionel Sambuc int inter;
257d90bee97SLionel Sambuc int numeof = 0;
258*0a6a1f1dSLionel Sambuc enum skipstate skip;
259d90bee97SLionel Sambuc
260d90bee97SLionel Sambuc TRACE(("cmdloop(%d) called\n", top));
261d90bee97SLionel Sambuc setstackmark(&smark);
262d90bee97SLionel Sambuc for (;;) {
263d90bee97SLionel Sambuc if (pendingsigs)
264d90bee97SLionel Sambuc dotrap();
265d90bee97SLionel Sambuc inter = 0;
266d90bee97SLionel Sambuc if (iflag == 1 && top) {
267d90bee97SLionel Sambuc inter = 1;
268d90bee97SLionel Sambuc showjobs(out2, SHOW_CHANGED);
269d90bee97SLionel Sambuc chkmail(0);
270d90bee97SLionel Sambuc flushout(&errout);
271d90bee97SLionel Sambuc }
272d90bee97SLionel Sambuc n = parsecmd(inter);
273d90bee97SLionel Sambuc /* showtree(n); DEBUG */
274d90bee97SLionel Sambuc if (n == NEOF) {
275d90bee97SLionel Sambuc if (!top || numeof >= 50)
276d90bee97SLionel Sambuc break;
277d90bee97SLionel Sambuc if (!stoppedjobs()) {
278d90bee97SLionel Sambuc if (!Iflag)
279d90bee97SLionel Sambuc break;
280d90bee97SLionel Sambuc out2str("\nUse \"exit\" to leave shell.\n");
281d90bee97SLionel Sambuc }
282d90bee97SLionel Sambuc numeof++;
283d90bee97SLionel Sambuc } else if (n != NULL && nflag == 0) {
284d90bee97SLionel Sambuc job_warning = (job_warning == 2) ? 1 : 0;
285d90bee97SLionel Sambuc numeof = 0;
286d90bee97SLionel Sambuc evaltree(n, 0);
287d90bee97SLionel Sambuc }
288d90bee97SLionel Sambuc popstackmark(&smark);
289d90bee97SLionel Sambuc setstackmark(&smark);
290*0a6a1f1dSLionel Sambuc
291*0a6a1f1dSLionel Sambuc /*
292*0a6a1f1dSLionel Sambuc * Any SKIP* can occur here! SKIP(FUNC|BREAK|CONT) occur when
293*0a6a1f1dSLionel Sambuc * a dotcmd is in a loop or a function body and appropriate
294*0a6a1f1dSLionel Sambuc * built-ins occurs in file scope in the sourced file. Values
295*0a6a1f1dSLionel Sambuc * other than SKIPFILE are reset by the appropriate eval*()
296*0a6a1f1dSLionel Sambuc * that contained the dotcmd() call.
297*0a6a1f1dSLionel Sambuc */
298*0a6a1f1dSLionel Sambuc skip = current_skipstate();
299*0a6a1f1dSLionel Sambuc if (skip != SKIPNONE) {
300*0a6a1f1dSLionel Sambuc if (skip == SKIPFILE)
301*0a6a1f1dSLionel Sambuc stop_skipping();
302d90bee97SLionel Sambuc break;
303d90bee97SLionel Sambuc }
304d90bee97SLionel Sambuc }
305d90bee97SLionel Sambuc popstackmark(&smark);
306d90bee97SLionel Sambuc }
307d90bee97SLionel Sambuc
308d90bee97SLionel Sambuc
309d90bee97SLionel Sambuc
310d90bee97SLionel Sambuc /*
311d90bee97SLionel Sambuc * Read /etc/profile or .profile. Return on error.
312d90bee97SLionel Sambuc */
313d90bee97SLionel Sambuc
314d90bee97SLionel Sambuc STATIC void
read_profile(const char * name)315d90bee97SLionel Sambuc read_profile(const char *name)
316d90bee97SLionel Sambuc {
317d90bee97SLionel Sambuc int fd;
318d90bee97SLionel Sambuc int xflag_set = 0;
319d90bee97SLionel Sambuc int vflag_set = 0;
320d90bee97SLionel Sambuc
321d90bee97SLionel Sambuc INTOFF;
322d90bee97SLionel Sambuc if ((fd = open(name, O_RDONLY)) >= 0)
323d90bee97SLionel Sambuc setinputfd(fd, 1);
324d90bee97SLionel Sambuc INTON;
325d90bee97SLionel Sambuc if (fd < 0)
326d90bee97SLionel Sambuc return;
327d90bee97SLionel Sambuc /* -q turns off -x and -v just when executing init files */
328d90bee97SLionel Sambuc if (qflag) {
329d90bee97SLionel Sambuc if (xflag)
330d90bee97SLionel Sambuc xflag = 0, xflag_set = 1;
331d90bee97SLionel Sambuc if (vflag)
332d90bee97SLionel Sambuc vflag = 0, vflag_set = 1;
333d90bee97SLionel Sambuc }
334d90bee97SLionel Sambuc cmdloop(0);
335d90bee97SLionel Sambuc if (qflag) {
336d90bee97SLionel Sambuc if (xflag_set)
337d90bee97SLionel Sambuc xflag = 1;
338d90bee97SLionel Sambuc if (vflag_set)
339d90bee97SLionel Sambuc vflag = 1;
340d90bee97SLionel Sambuc }
341d90bee97SLionel Sambuc popfile();
342d90bee97SLionel Sambuc }
343d90bee97SLionel Sambuc
344d90bee97SLionel Sambuc
345d90bee97SLionel Sambuc
346d90bee97SLionel Sambuc /*
347d90bee97SLionel Sambuc * Read a file containing shell functions.
348d90bee97SLionel Sambuc */
349d90bee97SLionel Sambuc
350d90bee97SLionel Sambuc void
readcmdfile(char * name)351d90bee97SLionel Sambuc readcmdfile(char *name)
352d90bee97SLionel Sambuc {
353d90bee97SLionel Sambuc int fd;
354d90bee97SLionel Sambuc
355d90bee97SLionel Sambuc INTOFF;
356d90bee97SLionel Sambuc if ((fd = open(name, O_RDONLY)) >= 0)
357d90bee97SLionel Sambuc setinputfd(fd, 1);
358d90bee97SLionel Sambuc else
359d90bee97SLionel Sambuc error("Can't open %s", name);
360d90bee97SLionel Sambuc INTON;
361d90bee97SLionel Sambuc cmdloop(0);
362d90bee97SLionel Sambuc popfile();
363d90bee97SLionel Sambuc }
364d90bee97SLionel Sambuc
365d90bee97SLionel Sambuc
366d90bee97SLionel Sambuc
367d90bee97SLionel Sambuc int
exitcmd(int argc,char ** argv)368d90bee97SLionel Sambuc exitcmd(int argc, char **argv)
369d90bee97SLionel Sambuc {
370d90bee97SLionel Sambuc if (stoppedjobs())
371d90bee97SLionel Sambuc return 0;
372d90bee97SLionel Sambuc if (argc > 1)
373d90bee97SLionel Sambuc exitstatus = number(argv[1]);
374d90bee97SLionel Sambuc exitshell(exitstatus);
375d90bee97SLionel Sambuc /* NOTREACHED */
376d90bee97SLionel Sambuc }
377