reenabled swaptest. quake should now load data and start on big endian architectures...
[AROS-Contrib.git] / gnu / abc-shell / main.c
blob54a64c36d8810ebd5ecdb52b61ed4f8297f17bc7
1 /*
2 * startup, main loop, environments and error handling
3 */
5 #define EXTERN /* define EXTERNs in sh.h */
7 #define DEBUG 0
8 #include <aros/debug.h>
10 #include <sys/stat.h>
11 #include <pwd.h>
12 #include "sh.h"
13 #include "ksh_time.h"
15 extern char **environ;
18 * global data
21 static void reclaim(void);
22 static void remove_temps(struct temp *tp);
25 * shell initialization
28 static const char initifs[] = "IFS= \t\n";
30 static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";
32 static const char *const initcoms [] = {
33 "typeset", "-r", "KSH_VERSION", NULL,
34 "typeset", "-x", "SHELL", "PATH", "HOME", "TMPDIR", "tmp", "LOGNAME",
35 "USER", "HISTFILE", "MAKE", "PREFIX", "PATH_SEPARATOR", "DIR_SEPARATOR", "LD", NULL,
36 "typeset", "-i", "PPID", NULL,
37 "typeset", "-i", "OPTIND=1", NULL,
38 "alias",
39 /* Standard ksh aliases */
40 "hash=alias -t", /* not "alias -t --": hash -r needs to work */
41 "type=whence -v",
42 "autoload=typeset -fu",
43 "functions=typeset -f",
44 #ifdef HISTORY
45 "history=fc -l",
46 #endif /* HISTORY */
47 "integer=typeset -i",
48 "local=typeset",
49 "r=fc -e -",
50 /* Aliases that are builtin commands in at&t */
51 "newgrp=exec newgrp",
52 /* Aliases that are AmigaOS4 specific - coreutils renames */
53 #ifdef __amigaos4__
54 "date=gdate", "dir=gdir", "install=ginstall", "env=genv",
55 "make=gmake", "info=ginfo",
56 #endif
57 "/dev/null=/nil",
58 NULL,
59 /* this is what at&t ksh seems to track, with the addition of emacs */
60 "alias", "-tU",
61 "cat", "cc", "chmod", "cp", "date", "ed", "grep", "ls",
62 "make", "mv", "pr", "rm", "sed", "sh", "who",
63 NULL,
64 NULL
67 #define version_param (initcoms[2])
69 const char *amiversion __attribute__((used)) = "$VER: abc-shell " ABC_VERSION " (" RELEASE_DATE ") " RELEASE_COMMENT "\0";
70 const char * stack_cookie __attribute__((used)) = "$STACK: " STACK_SIZE "\0";
72 int
73 main(int argc, char *argv[])
75 int i;
76 int argi;
77 Source *s;
78 struct block *l;
79 int errexit;
80 char **wp;
81 struct env env;
82 pid_t ppid;
84 /* make sure argv[] is sane */
85 if (!*argv) {
86 static const char *empty_argv[] = {"sh", (char *) 0};
88 argv = (char **) empty_argv;
89 argc = 1;
92 kshname = *argv;
94 aperm = &perm_space;
95 ainit(aperm); /* initialize permanent Area */
97 /* set up base environment */
98 memset(&env, 0, sizeof(env));
99 env.type = E_NONE;
100 ainit(&env.area);
101 e = &env;
102 newblock(); /* set up global l->vars and l->funs */
104 /* Do this first so output routines (eg, errorf, shellf) can work */
105 initio();
107 initvar();
109 initctypes();
111 inittraps();
113 coproc_init();
115 /* allocate tables */
117 taliases = malloc(sizeof(struct table));
118 aliases = malloc(sizeof(struct table));
119 homedirs = malloc(sizeof(struct table));
121 /* set up variable and command dictionaries */
122 ktinit(taliases, APERM, 0);
123 ktinit(aliases, APERM, 0);
124 ktinit(homedirs, APERM, 0);
126 /* define shell keywords */
127 initkeywords();
129 /* define built-in commands */
130 ktinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */
131 for (i = 0; shbuiltins[i].name != NULL; i++)
132 builtin(shbuiltins[i].name, shbuiltins[i].func);
133 for (i = 0; kshbuiltins[i].name != NULL; i++)
134 builtin(kshbuiltins[i].name, kshbuiltins[i].func);
136 init_histvec();
138 #if defined(__AROS__)
139 def_path = "/Developer/bin:/Developer/usr/bin:/C:.";
140 #else
141 def_path = "/gcc/bin:/SDK/C:/SDK/Local/C:/SDK/Local/newlib/bin:/SDK/Local/clib2/bin:/C:.";
142 #endif
144 /* Set PATH to def_path (will set the path global variable).
145 * (import of environment below will probably change this setting).
148 struct tbl *vp = global("PATH");
149 /* setstr can't fail here */
150 setstr(vp, def_path, KSH_RETURN_ERROR);
153 /* Set PATH_SEPARATOR and DIR_SEPARATOR. */
155 struct tbl *vp = global("PATH_SEPARATOR");
156 /* setstr can't fail here */
157 setstr(vp, ":", KSH_RETURN_ERROR);
161 struct tbl *vp = global("DIR_SEPARATOR");
162 /* setstr can't fail here */
163 setstr(vp, "/", KSH_RETURN_ERROR);
166 /* Set DISABLE_COMMANDLINE_WILDCARD_EXPANSION - to disable
167 * wildcard expansion in applications using clib2 >= 1.201
170 struct tbl *vp = global("DISABLE_COMMANDLINE_WILDCARD_EXPANSION");
171 /* setstr can't fail here */
172 setstr(vp, "true", KSH_RETURN_ERROR);
175 /* Set SHELL. */
177 struct tbl *vp = global("SHELL");
178 /* setstr can't fail here */
179 #if defined(__AROS__)
180 setstr(vp, "/Developer/bin/sh", KSH_RETURN_ERROR);
181 #else
182 setstr(vp, "/SDK/C/sh", KSH_RETURN_ERROR);
183 #endif
186 /* Set HOME. */
188 struct tbl *vp = global("HOME");
189 /* setstr can't fail here */
190 setstr(vp, "/home", KSH_RETURN_ERROR);
193 /* Set TMPDIR. */
195 struct tbl *vp = global("TMPDIR");
196 /* setstr can't fail here */
197 setstr(vp, "/T", KSH_RETURN_ERROR);
200 /* Set tmp. */
202 struct tbl *vp = global("tmp");
203 /* setstr can't fail here */
204 setstr(vp, "/T", KSH_RETURN_ERROR);
207 /* Set LOGNAME. */
209 struct tbl *vp = global("LOGNAME");
210 /* setstr can't fail here */
211 setstr(vp, "root", KSH_RETURN_ERROR);
214 /* Set USER - deprecated synonym of LOGNAME. */
216 struct tbl *vp = global("USER");
217 /* setstr can't fail here */
218 setstr(vp, "root", KSH_RETURN_ERROR);
221 /* Set HISTFILE - history file. */
223 struct tbl *vp = global("HISTFILE");
224 /* setstr can't fail here */
225 #if defined(__AROS__)
226 setstr(vp, "/Developer/Data/abc-shell/history", KSH_RETURN_ERROR);
227 #else
228 setstr(vp, "/SDK/Data/abc-shell/history", KSH_RETURN_ERROR);
229 #endif
232 #ifndef __AROS__
233 /* Set MAKE. */
235 struct tbl *vp = global("MAKE");
236 /* setstr can't fail here */
237 setstr(vp, "/SDK/C/gmake", KSH_RETURN_ERROR);
240 /* Set LD. */
242 struct tbl *vp = global("LD");
243 /* setstr can't fail here */
244 setstr(vp, "ld", KSH_RETURN_ERROR);
246 #endif
248 /* Turn on brace expansion by default. At&t ksh's that have
249 * alternation always have it on. BUT, posix doesn't have
250 * brace expansion, so set this before setting up FPOSIX
251 * (change_flag() clears FBRACEEXPAND when FPOSIX is set).
254 Flag(FBRACEEXPAND) = 1;
256 /* set posix flag just before environment so that it will have
257 * exactly the same effect as the POSIXLY_CORRECT environment
258 * variable. If this needs to be done sooner to ensure correct posix
259 * operation, an initial scan of the environment will also have
260 * done sooner.
262 change_flag(FPOSIX, OF_SPECIAL, 1);
264 /* import environment */
265 if (environ != NULL)
267 for (wp = environ; *wp != NULL; wp++)
269 if(strncmp("_=",*wp,2))
271 typeset(*wp, IMPORTV|EXPORTV, 0, 0, 0);
273 else
275 typeset(*wp,IMPORTV, 0, 0, 0);
279 kshpid = procpid = getpid();
280 typeset(initifs, 0, 0, 0, 0); /* for security */
282 /* assign default shell variable values */
283 substitute(initsubs, 0);
285 /* Figure out the current working directory and set $PWD */
287 struct stat s_pwd, s_dot;
288 struct tbl *pwd_v = global("PWD");
289 char *pwd = str_val(pwd_v);
290 char *pwdx = pwd;
292 /* Try to use existing $PWD if it is valid */
293 if (pwd[0] != '/' ||
294 stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0 ||
295 s_pwd.st_dev != s_dot.st_dev ||
296 s_pwd.st_ino != s_dot.st_ino)
297 pwdx = (char *) 0;
298 set_current_wd(pwdx);
299 if (current_wd[0])
300 simplify_path(current_wd);
301 /* Only set pwd if we know where we are or if it had a
302 * bogus value
304 if (current_wd[0] || pwd != null)
305 /* setstr can't fail here */
306 setstr(pwd_v, current_wd, KSH_RETURN_ERROR);
308 ppid = getppid();
309 setint(global("PPID"), (long) ppid);
310 setint(global("RANDOM"), (long) (time((time_t *)0) * kshpid * ppid));
311 /* setstr can't fail here */
312 setstr(global(version_param), ksh_version, KSH_RETURN_ERROR);
314 /* execute initialization statements */
315 for (wp = (char**) initcoms; *wp != NULL; wp++) {
316 shcomexec(wp);
317 for (; *wp != NULL; wp++)
321 ksheuid = geteuid();
322 kshuid = getuid();
323 kshgid = getgid();
324 kshegid = getegid();
325 safe_prompt = "$PWD> ";
327 struct tbl *vp = global("PS1");
329 /* Set PS1 if it isn't set, or we are root and prompt doesn't
330 * contain a #.
332 if (!(vp->flag & ISSET))
333 /* setstr can't fail here */
334 setstr(vp, safe_prompt, KSH_RETURN_ERROR);
337 argi = parse_args(argv, OF_CMDLINE, (int *) 0);
338 if (argi < 0)
339 exit(1);
341 if (Flag(FCOMMAND)) {
342 s = pushs(SSTRING, ATEMP);
343 if (!(s->start = s->str = argv[argi++]))
344 errorf("-c requires an argument");
345 if (argv[argi])
346 kshname = argv[argi++];
347 } else if (argi < argc && !Flag(FSTDIN)) {
348 s = pushs(SFILE, ATEMP);
349 s->file = argv[argi++];
350 s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
351 if (s->u.shf == NULL) {
352 exstat = 127; /* POSIX */
353 errorf("%s: %s", s->file, strerror(errno));
355 kshname = s->file;
356 } else {
357 Flag(FSTDIN) = 1;
358 s = pushs(SSTDIN, ATEMP);
359 s->file = "<stdin>";
360 s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0),
361 (struct shf *) 0);
362 if (isatty(0) && isatty(2)) {
363 Flag(FTALKING) = Flag(FTALKING_I) = 1;
364 /* The following only if isatty(0) */
365 s->flags |= SF_TTY;
366 s->u.shf->flags |= SHF_INTERRUPT;
367 s->file = (char *) 0;
371 /* This bizarreness is mandated by POSIX */
373 struct stat s_stdin;
375 if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode) &&
376 Flag(FTALKING))
377 reset_nonblock(0);
380 j_init(i);
382 l = e->loc;
383 l->argv = &argv[argi - 1];
384 l->argc = argc - argi;
385 l->argv[0] = (char *) kshname;
386 getopts_reset(1);
388 errexit = Flag(FERREXIT);
389 Flag(FERREXIT) = 0;
391 if (!current_wd[0] && Flag(FTALKING))
392 warningf(false, "Cannot determine current working directory");
394 char *env_file;
396 /* include $ENV */
397 env_file = str_val(global("ENV"));
399 /* If env isn't set, include default environment */
400 if (env_file == null)
401 #if defined(__AROS__)
402 env_file = strdup("/Developer/Data/abc-shell/variables");
403 #else
404 env_file = strdup("/SDK/Data/abc-shell/variables");
405 #endif
407 env_file = substitute(env_file, DOTILDE);
408 if (*env_file != '\0')
409 include(env_file, 0, (char **) 0, 1);
411 if (errexit)
412 Flag(FERREXIT) = 1;
414 if (Flag(FTALKING)) {
415 hist_init(s);
416 alarm_init();
417 } else
418 Flag(FTRACKALL) = 1; /* set after ENV */
420 shell(s, true); /* doesn't return */
421 return 0;
425 include(const char *name, int argc, char **argv, int intr_ok)
427 Source *volatile s = NULL;
428 struct shf *shf;
429 char **volatile old_argv;
430 volatile int old_argc;
431 int i;
433 shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC);
434 if (shf == NULL)
435 return -1;
437 if (argv) {
438 old_argv = e->loc->argv;
439 old_argc = e->loc->argc;
440 } else {
441 old_argv = (char **) 0;
442 old_argc = 0;
444 newenv(E_INCL);
445 i = ksh_sigsetjmp(e->jbuf, 0);
446 if (i) {
447 quitenv(s ? s->u.shf : NULL);
448 if (old_argv) {
449 e->loc->argv = old_argv;
450 e->loc->argc = old_argc;
452 switch (i) {
453 case LRETURN:
454 case LERROR:
455 return exstat & 0xff; /* see below */
456 case LINTR:
457 if (intr_ok && (exstat - 128) != SIGTERM)
458 return 1;
459 /* FALLTHROUGH */
460 case LEXIT:
461 case LLEAVE:
462 case LSHELL:
463 unwind(i);
464 /* NOTREACHED */
465 default:
466 internal_errorf(1, "include: %d", i);
467 /* NOTREACHED */
470 if (argv) {
471 e->loc->argv = argv;
472 e->loc->argc = argc;
474 s = pushs(SFILE, ATEMP);
475 s->u.shf = shf;
476 s->file = str_save(name, ATEMP);
477 i = shell(s, false);
478 quitenv(s->u.shf);
479 if (old_argv) {
480 e->loc->argv = old_argv;
481 e->loc->argc = old_argc;
483 return i & 0xff; /* & 0xff to ensure value not -1 */
487 command(const char *comm)
489 Source *s;
491 s = pushs(SSTRING, ATEMP);
492 s->start = s->str = comm;
493 return shell(s, false);
497 * run the commands from the input source, returning status.
500 shell(Source *volatile s, volatile int toplevel)
502 struct op *t;
503 volatile int wastty = s->flags & SF_TTY;
504 volatile int attempts = 13;
505 volatile int interactive = Flag(FTALKING) && toplevel;
506 Source *volatile old_source = source;
507 int i;
509 newenv(E_PARSE);
510 if (interactive)
511 really_exit = 0;
512 i = ksh_sigsetjmp(e->jbuf, 0);
513 if (i) {
514 switch (i) {
515 case LINTR: /* we get here if SIGINT not caught or ignored */
516 case LERROR:
517 case LSHELL:
518 if (interactive) {
519 if (i == LINTR)
520 shellf(newline);
521 /* Reset any eof that was read as part of a
522 * multiline command.
524 if (Flag(FIGNOREEOF) && s->type == SEOF &&
525 wastty)
526 s->type = SSTDIN;
527 /* Used by exit command to get back to
528 * top level shell. Kind of strange since
529 * interactive is set if we are reading from
530 * a tty...
532 /* toss any input we have so far */
533 s->start = s->str = null;
534 break;
536 /* FALLTHROUGH */
537 case LEXIT:
538 case LLEAVE:
539 case LRETURN:
540 source = old_source;
541 quitenv(NULL);
542 unwind(i); /* keep on going */
543 /* NOTREACHED */
544 default:
545 source = old_source;
546 quitenv(NULL);
547 internal_errorf(1, "shell: %d", i);
548 /* NOTREACHED */
552 while (1) {
553 if (trap)
554 runtraps(0);
556 if (s->next == NULL) {
557 if (Flag(FVERBOSE))
558 s->flags |= SF_ECHO;
559 else
560 s->flags &= ~SF_ECHO;
563 if (interactive) {
564 j_notify();
565 set_prompt(PS1, s);
568 t = compile(s);
569 if (t != NULL && t->type == TEOF) {
570 if (wastty && Flag(FIGNOREEOF) && --attempts > 0) {
571 shellf("Use `exit' to leave ksh\n");
572 s->type = SSTDIN;
573 } else if (wastty && !really_exit &&
574 j_stopped_running())
576 really_exit = 1;
577 s->type = SSTDIN;
578 } else {
579 /* this for POSIX, which says EXIT traps
580 * shall be taken in the environment
581 * immediately after the last command
582 * executed.
584 if (toplevel)
585 unwind(LEXIT);
586 break;
590 if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY)))
591 exstat = execute(t, 0);
593 if (t != NULL && t->type != TEOF && interactive && really_exit)
594 really_exit = 0;
596 reclaim();
598 quitenv(NULL);
599 source = old_source;
600 return exstat;
603 /* return to closest error handler or shell(), exit if none found */
604 void
605 unwind(int i)
607 /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */
608 if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) &&
609 sigtraps[SIGEXIT_].trap))
611 runtrap(&sigtraps[SIGEXIT_]);
612 i = LLEAVE;
613 } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) {
614 runtrap(&sigtraps[SIGERR_]);
615 i = LLEAVE;
617 while (1) {
618 switch (e->type) {
619 case E_PARSE:
620 case E_FUNC:
621 case E_INCL:
622 case E_LOOP:
623 case E_ERRH:
624 case E_SUBSHELL:
625 ksh_siglongjmp(e->jbuf, i);
626 /*NOTREACHED*/
628 case E_NONE:
629 if (i == LINTR)
630 e->flags |= EF_FAKE_SIGDIE;
631 /* FALLTHROUGH */
632 default:
633 quitenv(NULL);
638 void
639 newenv(int type)
641 struct env *ep;
643 ep = (struct env *) alloc(sizeof(*ep), ATEMP);
644 ep->type = type;
645 ep->flags = 0;
646 ainit(&ep->area);
647 ep->loc = e->loc;
648 ep->savefd = NULL;
649 ep->oenv = e;
650 ep->temps = NULL;
651 e = ep;
654 void
655 quitenv(struct shf *shf)
657 struct env *ep = e;
658 int fd;
660 if (ep->oenv && ep->oenv->loc != ep->loc)
661 popblock();
662 if (ep->savefd != NULL) {
663 for (fd = 0; fd < NUFILE; fd++)
664 /* if ep->savefd[fd] < 0, means fd was closed */
665 if (ep->savefd[fd])
666 restfd(fd, ep->savefd[fd]);
667 if (ep->savefd[2]) /* Clear any write errors */
668 shf_reopen(2, SHF_WR, shl_out);
671 /* Bottom of the stack.
672 * Either main shell is exiting or cleanup_parents_env() was called.
674 if (ep->oenv == NULL) {
675 if (ep->type == E_NONE) { /* Main shell exiting? */
676 if (Flag(FTALKING))
677 hist_finish();
678 j_exit();
679 if (ep->flags & EF_FAKE_SIGDIE) {
680 int sig = exstat - 128;
682 /* ham up our death a bit (at&t ksh
683 * only seems to do this for SIGTERM)
684 * Don't do it for SIGQUIT, since we'd
685 * dump a core..
687 if (sig == SIGINT || sig == SIGTERM) {
688 setsig(&sigtraps[sig], SIG_DFL,
689 SS_RESTORE_CURR|SS_FORCE);
690 kill(0, sig);
693 #ifdef MEM_DEBUG
694 chmem_allfree();
695 #endif /* MEM_DEBUG */
697 if (shf)
698 shf_close(shf);
699 reclaim();
700 exit(exstat);
702 if (shf)
703 shf_close(shf);
704 reclaim();
706 e = e->oenv;
707 afree(ep, ATEMP);
710 /* Called after a fork to cleanup stuff left over from parents environment */
711 void
712 cleanup_parents_env(void)
714 struct env *ep;
715 int fd;
717 /* Don't clean up temporary files - parent will probably need them.
718 * Also, can't easily reclaim memory since variables, etc. could be
719 * anywhere.
722 /* close all file descriptors hiding in savefd */
723 for (ep = e; ep; ep = ep->oenv) {
724 if (ep->savefd) {
725 for (fd = 0; fd < NUFILE; fd++)
726 if (ep->savefd[fd] > 0)
727 close(ep->savefd[fd]);
728 afree(ep->savefd, &ep->area);
729 ep->savefd = (short *) 0;
732 e->oenv = (struct env *) 0;
735 /* Called just before an execve cleanup stuff temporary files */
736 void
737 cleanup_proc_env(void)
739 struct env *ep;
741 for (ep = e; ep; ep = ep->oenv)
742 remove_temps(ep->temps);
745 /* remove temp files and free ATEMP Area */
746 static void
747 reclaim(void)
749 remove_temps(e->temps);
750 e->temps = NULL;
751 afreeall(&e->area);
754 static void
755 remove_temps(struct temp *tp)
757 for (; tp != NULL; tp = tp->next)
758 if (tp->pid == procpid) {
759 unlink(tp->name);