📄 main.c
字号:
#endif /* KSH */ } else Flag(FTRACKALL) = 1; /* set after ENV */ shell(s, TRUE); /* doesn't return */ return 0;}intinclude(name, argc, argv, intr_ok) const char *name; int argc; char **argv; int intr_ok;{ register Source *volatile s = NULL; Source *volatile sold; struct shf *shf; char **volatile old_argv; volatile int old_argc; int i; shf = shf_open(name, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); if (shf == NULL) return -1; if (argv) { old_argv = e->loc->argv; old_argc = e->loc->argc; } else { old_argv = (char **) 0; old_argc = 0; } sold = source; newenv(E_INCL); i = ksh_sigsetjmp(e->jbuf, 0); if (i) { source = sold; if (s) /* Do this before quitenv(), which frees the memory */ shf_close(s->u.shf); quitenv(); if (old_argv) { e->loc->argv = old_argv; e->loc->argc = old_argc; } switch (i) { case LRETURN: case LERROR: return exstat & 0xff; /* see below */ case LINTR: /* intr_ok is set if we are including .profile or $ENV. * If user ^C's out, we don't want to kill the shell... */ if (intr_ok && (exstat - 128) != SIGTERM) return 1; /* fall through... */ case LEXIT: case LLEAVE: case LSHELL: unwind(i); /*NOREACHED*/ default: internal_errorf(1, "include: %d", i); /*NOREACHED*/ } } if (argv) { e->loc->argv = argv; e->loc->argc = argc; } s = pushs(SFILE, ATEMP); s->u.shf = shf; s->file = str_save(name, ATEMP); i = shell(s, FALSE); source = sold; shf_close(s->u.shf); quitenv(); if (old_argv) { e->loc->argv = old_argv; e->loc->argc = old_argc; } return i & 0xff; /* & 0xff to ensure value not -1 */}intcommand(comm) const char *comm;{ register Source *s; s = pushs(SSTRING, ATEMP); s->start = s->str = comm; return shell(s, FALSE);}/* * run the commands from the input source, returning status. */intshell(s, toplevel) Source *volatile s; /* input source */ int volatile toplevel;{ struct op *t; volatile int wastty = s->flags & SF_TTY; volatile int attempts = 13; volatile int interactive = Flag(FTALKING) && toplevel; int i; newenv(E_PARSE); if (interactive) really_exit = 0; i = ksh_sigsetjmp(e->jbuf, 0); if (i) { s->start = s->str = null; switch (i) { case LINTR: /* we get here if SIGINT not caught or ignored */ case LERROR: case LSHELL: if (interactive) { if (i == LINTR) shellf(newline); /* Reset any eof that was read as part of a * multiline command. */ if (Flag(FIGNOREEOF) && s->type == SEOF && wastty) s->type = SSTDIN; /* Used by exit command to get back to * top level shell. Kind of strange since * interactive is set if we are reading from * a tty, but to have stopped jobs, one only * needs FMONITOR set (not FTALKING/SF_TTY)... */ break; } /* fall through... */ case LEXIT: case LLEAVE: case LRETURN: quitenv(); unwind(i); /* keep on going */ /*NOREACHED*/ default: quitenv(); internal_errorf(1, "shell: %d", i); /*NOREACHED*/ } } while (1) { if (trap) runtraps(0); if (s->next == NULL) if (Flag(FVERBOSE)) s->flags |= SF_ECHO; else s->flags &= ~SF_ECHO; if (interactive) { j_notify();#ifdef KSH mcheck();#endif /* KSH */ set_prompt(PS1, s); } t = compile(s); if (t != NULL && t->type == TEOF) { if (wastty && Flag(FIGNOREEOF) && --attempts > 0) { shellf("Use `exit' to leave ksh\n"); s->type = SSTDIN; } else if (wastty && !really_exit && j_stopped_running()) { really_exit = 1; s->type = SSTDIN; } else { /* this for POSIX, which says EXIT traps * shall be taken in the environment * immediately after the last command * executed. */ if (toplevel) unwind(LEXIT); break; } } if (t && (!Flag(FNOEXEC) || (s->flags & SF_TTY))) exstat = execute(t, 0); if (t != NULL && t->type != TEOF && interactive && really_exit) really_exit = 0; reclaim(); } quitenv(); return exstat;}/* return to closest error handler or shell(), exit if none found */voidunwind(i) int i;{ /* ordering for EXIT vs ERR is a bit odd (this is what at&t ksh does) */ if (i == LEXIT || (Flag(FERREXIT) && (i == LERROR || i == LINTR) && sigtraps[SIGEXIT_].trap)) { runtrap(&sigtraps[SIGEXIT_]); i = LLEAVE; } else if (Flag(FERREXIT) && (i == LERROR || i == LINTR)) { runtrap(&sigtraps[SIGERR_]); i = LLEAVE; } while (1) { switch (e->type) { case E_PARSE: case E_FUNC: case E_INCL: case E_LOOP: case E_ERRH: ksh_siglongjmp(e->jbuf, i); /*NOTREACHED*/ case E_NONE: if (i == LINTR) e->flags |= EF_FAKE_SIGDIE; /* Fall through... */ default: quitenv(); } }}voidnewenv(type) int type;{ register struct env *ep; ep = (struct env *) alloc(sizeof(*ep), ATEMP); ep->type = type; ep->flags = 0; ainit(&ep->area); ep->loc = e->loc; ep->savefd = NULL; ep->oenv = e; ep->temps = NULL; e = ep;}voidquitenv(){ register struct env *ep = e; register int fd; if (ep->oenv && ep->oenv->loc != ep->loc) popblock(); if (ep->savefd != NULL) { for (fd = 0; fd < NUFILE; fd++) /* if ep->savefd[fd] < 0, means fd was closed */ if (ep->savefd[fd]) restfd(fd, ep->savefd[fd]); if (ep->savefd[2]) /* Clear any write errors */ shf_reopen(2, SHF_WR, shl_out); } reclaim(); /* Bottom of the stack. * Either main shell is exiting or cleanup_parents_env() was called. */ if (ep->oenv == NULL) { if (ep->type == E_NONE) { /* Main shell exiting? */ if (Flag(FTALKING)) hist_finish(); j_exit(); if (ep->flags & EF_FAKE_SIGDIE) { int sig = exstat - 128; /* ham up our death a bit (at&t ksh * only seems to do this for SIGTERM) * Don't do it for SIGQUIT, since we'd * dump a core.. */ if (sig == SIGINT || sig == SIGTERM) { setsig(&sigtraps[sig], SIG_DFL, SS_RESTORE_CURR|SS_FORCE); kill(0, sig); } }#ifdef MEM_DEBUG chmem_allfree();#endif /* MEM_DEBUG */ } exit(exstat); } e = e->oenv; afree(ep, ATEMP);}/* Called after a fork to cleanup stuff left over from parents environment */voidcleanup_parents_env(){ struct env *ep; int fd; /* Don't clean up temporary files - parent will probably need them. * Also, can't easily reclaim memory since variables, etc. could be * anywyere. */ /* close all file descriptors hiding in savefd */ for (ep = e; ep; ep = ep->oenv) { if (ep->savefd) { for (fd = 0; fd < NUFILE; fd++) if (ep->savefd[fd] > 0) close(ep->savefd[fd]); afree(ep->savefd, &ep->area); ep->savefd = (short *) 0; } } e->oenv = (struct env *) 0;}/* Called just before an execve cleanup stuff temporary files */voidcleanup_proc_env(){ struct env *ep; for (ep = e; ep; ep = ep->oenv) remove_temps(ep->temps);}/* remove temp files and free ATEMP Area */static voidreclaim(){ remove_temps(e->temps); e->temps = NULL; afreeall(&e->area);}static voidremove_temps(tp) struct temp *tp;{#ifdef OS2 static struct temp *delayed_remove; struct temp *t, **tprev; if (delayed_remove) { for (tprev = &delayed_remove, t = delayed_remove; t; t = *tprev) /* No need to check t->pid here... */ if (unlink(t->name) >= 0 || errno == ENOENT) { *tprev = t->next; afree(t, APERM); } else tprev = &t->next; }#endif /* OS2 */ for (; tp != NULL; tp = tp->next) if (tp->pid == procpid) {#ifdef OS2 /* OS/2 (and dos) do not allow files that are currently * open to be removed, so we cache it away for future * removal. * XXX should only do this if errno * is Efile-still-open-can't-remove * (but I don't know what that is...) */ if (unlink(tp->name) < 0 && errno != ENOENT) { t = (struct temp *) alloc( sizeof(struct temp) + strlen(tp->name) + 1, APERM); memset(t, 0, sizeof(struct temp)); t->name = (char *) &t[1]; strcpy(t->name, tp->name); t->next = delayed_remove; delayed_remove = t; }#else /* OS2 */ unlink(tp->name);#endif /* OS2 */ }}/* Returns true if name refers to a restricted shell */static intis_restricted(name) char *name;{ char *p; /* this silly function prevents you running a command called runconf.sh. */ /* we don't care about restricted shells, which aren't very restricted anyway */ /* and introduce a false sense of security */ return 0;#ifdef dumbidea if ((p = ksh_strrchr_dirsep(name))) name = p; /* accepts rsh, rksh, rpdksh, pdrksh, etc. */ return (p = strchr(name, 'r')) && strstr(p, "sh");#endif}voidaerror(ap, msg) Area *ap; const char *msg;{ internal_errorf(1, "alloc: %s", msg); errorf(null); /* this is never executed - keeps gcc quiet */ /*NOTREACHED*/}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -