1 /* $NetBSD: main.c,v 1.48 2003/09/14 12:09:29 jmmv Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 __COPYRIGHT("@(#) Copyright (c) 1991, 1993\n\
38 The Regents of the University of California. All rights reserved.\n");
41 static char sccsid
[] = "@(#)main.c 8.7 (Berkeley) 7/19/95";
43 __RCSID("$NetBSD: main.c,v 1.48 2003/09/14 12:09:29 jmmv Exp $");
73 #include "shinstance.h"
79 #ifdef unused_variables
80 STATIC
union node
*curcmd
;
81 STATIC
union node
*prevcmd
;
84 STATIC
void read_profile(struct shinstance
*, const char *);
85 STATIC
char *find_dot_file(struct shinstance
*, char *);
86 int main(int, char **);
87 int shell_main(shinstance
*, int, char **);
89 extern void init_syntax(void);
91 STATIC
int usage(const char *argv0
);
92 STATIC
int version(const char *argv0
);
95 * Main routine. We initialize things, parse the arguments, execute
96 * profiles if we're a login shell, and then call cmdloop to execute
97 * commands. The setjmp call sets up the location to jump to when an
98 * exception occurs. When an exception occurs the variable "state"
99 * is used to figure out how far we had gotten.
103 main(int argc
, char **argv
)
108 * Global initializations.
110 setlocale(LC_ALL
, "");
116 * Check for --version and --help.
118 if (argc
> 1 && argv
[1][0] == '-' && argv
[1][1] == '-') {
119 if (!strcmp(argv
[1], "--help"))
120 return usage(argv
[0]);
121 if (!strcmp(argv
[1], "--version"))
122 return version(argv
[0]);
126 * Create the root shell instance.
128 psh
= sh_create_root_shell(NULL
, argc
, argv
);
131 shthread_set_shell(psh
);
132 return shell_main(psh
, argc
, argv
);
136 shell_main(shinstance
*psh
, int argc
, char **argv
)
138 struct jmploc jmploc
;
139 struct stackmark smark
;
144 if (setjmp(jmploc
.loc
)) {
146 * When a shell procedure is executed, we raise the
147 * exception EXSHELLPROC to clean up before executing
148 * the shell procedure.
150 switch (psh
->exception
) {
152 psh
->rootpid
= /*getpid()*/ psh
->pid
;
159 psh
->exitstatus
= psh
->exerrno
;
170 if (psh
->exception
!= EXSHELLPROC
) {
171 if (state
== 0 || iflag(psh
) == 0 || ! psh
->rootshell
)
172 exitshell(psh
, psh
->exitstatus
);
175 if (psh
->exception
== EXINT
177 && (! attyset(psh
) || equal(termval(psh
), "emacs"))
181 flushout(&psh
->errout
);
183 popstackmark(psh
, &smark
);
184 FORCEINTON
; /* enable interrupts */
194 psh
->handler
= &jmploc
;
195 psh
->rootpid
= /*getpid()*/ psh
->pid
;
202 trputs(psh
, "Shell args: "); trargs(psh
, argv
);
206 setstackmark(psh
, &smark
);
207 procargs(psh
, argc
, argv
);
208 if (argv
[0] && argv
[0][0] == '-') {
210 read_profile(psh
, "/etc/profile");
213 read_profile(psh
, ".profile");
217 if (sh_getuid(psh
) == sh_geteuid(psh
) && sh_getgid(psh
) == sh_getegid(psh
)) {
218 if ((shinit
= lookupvar(psh
, "ENV")) != NULL
&& *shinit
!= '\0') {
220 read_profile(psh
, shinit
);
225 if (sflag(psh
) == 0 || psh
->minusc
) {
226 static int sigs
[] = {
227 SIGINT
, SIGQUIT
, SIGHUP
,
233 #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
236 for (i
= 0; i
< SIGSSIZE
; i
++)
237 setsignal(psh
, sigs
[i
], 0);
241 evalstring(psh
, psh
->minusc
, 0);
243 if (sflag(psh
) || psh
->minusc
== NULL
) {
244 state4
: /* XXX ??? - why isn't this before the "if" statement */
247 exitshell(psh
, psh
->exitstatus
);
254 * Read and execute commands. "Top" is nonzero for the top level command
255 * loop; it turns on prompting if the shell is interactive.
259 cmdloop(struct shinstance
*psh
, int top
)
262 struct stackmark smark
;
266 TRACE((psh
, "cmdloop(%d) called\n", top
));
267 setstackmark(psh
, &smark
);
269 if (psh
->pendingsigs
)
272 if (iflag(psh
) && top
) {
274 showjobs(psh
, psh
->out2
, SHOW_CHANGED
);
276 flushout(&psh
->errout
);
278 n
= parsecmd(psh
, inter
);
279 /* showtree(n); DEBUG */
281 if (!top
|| numeof
>= 50)
283 if (!stoppedjobs(psh
)) {
286 out2str(psh
, "\nUse \"exit\" to leave shell.\n");
289 } else if (n
!= NULL
&& nflag(psh
) == 0) {
290 psh
->job_warning
= (psh
->job_warning
== 2) ? 1 : 0;
294 popstackmark(psh
, &smark
);
295 setstackmark(psh
, &smark
);
296 if (psh
->evalskip
== SKIPFILE
) {
301 popstackmark(psh
, &smark
);
307 * Read /etc/profile or .profile. Return on error.
311 read_profile(struct shinstance
*psh
, const char *name
)
318 if ((fd
= shfile_open(&psh
->fdtab
, name
, O_RDONLY
, 0)) >= 0)
319 setinputfd(psh
, fd
, 1);
323 /* -q turns off -x and -v just when executing init files */
326 xflag(psh
) = 0, xflag_set
= 1;
328 vflag(psh
) = 0, vflag_set
= 1;
343 * Read a file containing shell functions.
347 readcmdfile(struct shinstance
*psh
, char *name
)
352 if ((fd
= shfile_open(&psh
->fdtab
, name
, O_RDONLY
, 0)) >= 0)
353 setinputfd(psh
, fd
, 1);
355 error(psh
, "Can't open %s", name
);
364 * Take commands from a file. To be compatible we should do a path
365 * search for the file, which is necessary to find sub-commands.
370 find_dot_file(struct shinstance
*psh
, char *basename
)
373 const char *path
= pathval(psh
);
376 /* don't try this for absolute or relative paths */
377 if (strchr(basename
, '/'))
380 while ((fullname
= padvance(psh
, &path
, basename
)) != NULL
) {
381 if ((shfile_stat(&psh
->fdtab
, fullname
, &statb
) == 0) && S_ISREG(statb
.st_mode
)) {
383 * Don't bother freeing here, since it will
384 * be freed by the caller.
388 stunalloc(psh
, fullname
);
391 /* not found in the PATH */
392 error(psh
, "%s: not found", basename
);
398 dotcmd(struct shinstance
*psh
, int argc
, char **argv
)
402 if (argc
>= 2) { /* That's what SVR2 does */
404 struct stackmark smark
;
406 setstackmark(psh
, &smark
);
407 fullname
= find_dot_file(psh
, argv
[1]);
408 setinputfile(psh
, fullname
, 1);
409 psh
->commandname
= fullname
;
412 popstackmark(psh
, &smark
);
414 return psh
->exitstatus
;
419 exitcmd(struct shinstance
*psh
, int argc
, char **argv
)
421 if (stoppedjobs(psh
))
424 psh
->exitstatus
= number(psh
, argv
[1]);
425 exitshell(psh
, psh
->exitstatus
);
432 strip_argv0(const char *argv0
, size_t *lenp
)
437 for (tmp
= strpbrk(argv0
, "\\/:"); tmp
; tmp
= strpbrk(argv0
, "\\/:"))
440 /* find the end, ignoring extenions */
441 tmp
= strrchr(argv0
, '.');
443 tmp
= strchr(argv0
, '\0');
449 usage(const char *argv0
)
452 argv0
= strip_argv0(argv0
, &len
);
455 "usage: %.*s [-aCefnuvxIimqVEb] [+aCefnuvxIimqVEb] [-o option_name]\n"
456 " [+o option_name] [command_file [argument ...]]\n"
457 " or: %.*s -c [-aCefnuvxIimqVEb] [+aCefnuvxIimqVEb] [-o option_name]\n"
458 " [+o option_name] command_string [command_name [argument ...]]\n"
459 " or: %.*s -s [-aCefnuvxIimqVEb] [+aCefnuvxIimqVEb] [-o option_name]\n"
460 " [+o option_name] [argument ...]\n"
462 " or: %.*s --version\n",
463 len
, argv0
, len
, argv0
, len
, argv0
, len
, argv0
, len
, argv0
);
468 version(const char *argv0
)
471 strip_argv0(argv0
, &len
);
474 "%.*s - kBuild version %d.%d.%d\n",
476 KBUILD_VERSION_MAJOR
, KBUILD_VERSION_MINOR
, KBUILD_VERSION_PATCH
);