📄 main.c
字号:
/* * startup, main loop, enviroments and error handling */#define EXTERN /* define EXTERNs in sh.h */#include "sh.h"#include "ksh_stat.h"#include "ksh_time.h"extern char **environ;/* * global data */static void reclaim ARGS((void));static void remove_temps ARGS((struct temp *tp));static int is_restricted ARGS((char *name));/* * shell initialization */static const char initifs[] = "IFS= \t\n";static const char initsubs[] = "${PS2=> } ${PS3=#? } ${PS4=+ }";static const char version_param[] =#ifdef KSH "KSH_VERSION"#else /* KSH */ "SH_VERSION"#endif /* KSH */ ;static const char *const initcoms [] = { "typeset", "-x", "SHELL", "PATH", "HOME", NULL, "typeset", "-r", version_param, NULL, "typeset", "-i", "PPID", NULL, "typeset", "-i", "OPTIND=1", NULL,#ifdef KSH "eval", "typeset -i RANDOM MAILCHECK=\"${MAILCHECK-600}\" SECONDS=\"${SECONDS-0}\" TMOUT=\"${TMOUT-0}\"", NULL,#endif /* KSH */ "alias", /* Standard ksh aliases */ "hash=alias -t", /* not "alias -t --": hash -r needs to work */ "type=whence -v",#ifdef JOBS "stop=kill -STOP", "suspend=kill -STOP $$",#endif#ifdef KSH "autoload=typeset -fu", "functions=typeset -f",# ifdef HISTORY "history=fc -l",# endif /* HISTORY */ "integer=typeset -i", "nohup=nohup ", "local=typeset", "r=fc -e -",#endif /* KSH */#ifdef KSH /* Aliases that are builtin commands in at&t */ "login=exec login", "newgrp=exec newgrp",#endif /* KSH */ NULL, /* this is what at&t ksh seems to track, with the addition of emacs */ "alias", "-tU", "cat", "cc", "chmod", "cp", "date", "ed", "emacs", "grep", "ls", "mail", "make", "mv", "pr", "rm", "sed", "sh", "vi", "who", NULL,#ifdef EXTRA_INITCOMS EXTRA_INITCOMS, NULL,#endif /* EXTRA_INITCOMS */ NULL};intmain(argc, argv) int argc; register char **argv;{ register int i; int argi; Source *s; struct block *l; int restricted, errexit; char **wp; struct env env; pid_t ppid;#ifdef MEM_DEBUG chmem_set_defaults("ct", 1); /* chmem_push("+c", 1); */#endif /* MEM_DEBUG */#ifdef OS2 setmode (0, O_BINARY); setmode (1, O_TEXT);#endif /* make sure argv[] is sane */ if (!*argv) { static const char *empty_argv[] = { "pdksh", (char *) 0 }; argv = (char **) empty_argv; argc = 1; } kshname = *argv; ainit(&aperm); /* initialize permanent Area */ /* set up base enviroment */ memset(&env, 0, sizeof(env)); env.type = E_NONE; ainit(&env.area); e = &env; newblock(); /* set up global l->vars and l->funs */ /* Do this first so output routines (eg, errorf, shellf) can work */ initio(); initvar(); initctypes(); inittraps();#ifdef KSH coproc_init();#endif /* KSH */ /* set up variable and command dictionaries */ tinit(&taliases, APERM, 0); tinit(&aliases, APERM, 0); tinit(&homedirs, APERM, 0); /* define shell keywords */ initkeywords(); /* define built-in commands */ tinit(&builtins, APERM, 64); /* must be 2^n (currently 40 builtins) */ for (i = 0; shbuiltins[i].name != NULL; i++) builtin(shbuiltins[i].name, shbuiltins[i].func); for (i = 0; kshbuiltins[i].name != NULL; i++) builtin(kshbuiltins[i].name, kshbuiltins[i].func); init_histvec(); def_path = DEFAULT__PATH;#if defined(HAVE_CONFSTR) && defined(_CS_PATH) { size_t len = confstr(_CS_PATH, (char *) 0, 0); char *new; if (len > 0) { confstr(_CS_PATH, new = alloc(len + 1, APERM), len + 1); def_path = new; } }#endif /* HAVE_CONFSTR && _CS_PATH */ /* Set PATH to def_path (will set the path global variable). * (import of environment below will probably change this setting). */ { struct tbl *vp = global("PATH"); /* setstr can't fail here */ setstr(vp, def_path, KSH_RETURN_ERROR); } /* Turn on nohup by default for how - will change to off * by default once people are aware of its existance * (at&t ksh does not have a nohup option - it always sends * the hup). */ Flag(FNOHUP) = 1; /* Turn on brace expansion by default. At&t ksh's that have * alternation always have it on. BUT, posix doesn't have * brace expansion, so set this before setting up FPOSIX * (change_flag() clears FBRACEEXPAND when FPOSIX is set). */#ifdef BRACE_EXPAND Flag(FBRACEEXPAND) = 1;#endif /* BRACE_EXPAND */ /* set posix flag just before environment so that it will have * exactly the same effect as the POSIXLY_CORRECT environment * variable. If this needs to be done sooner to ensure correct posix * operation, an initial scan of the environment will also have * done sooner. */#ifdef POSIXLY_CORRECT change_flag(FPOSIX, OF_SPECIAL, 1);#endif /* POSIXLY_CORRECT */ /* import enviroment */ if (environ != NULL) for (wp = environ; *wp != NULL; wp++) typeset(*wp, IMPORT|EXPORT, 0, 0, 0); kshpid = procpid = getpid(); typeset(initifs, 0, 0, 0, 0); /* for security */ /* assign default shell variable values */ substitute(initsubs, 0); /* Figure out the current working directory and set $PWD */ { struct stat s_pwd, s_dot; struct tbl *pwd_v = global("PWD"); char *pwd = str_val(pwd_v); char *pwdx = pwd; /* Try to use existing $PWD if it is valid */ if (!ISABSPATH(pwd) || stat(pwd, &s_pwd) < 0 || stat(".", &s_dot) < 0 || s_pwd.st_dev != s_dot.st_dev || s_pwd.st_ino != s_dot.st_ino) pwdx = (char *) 0; set_current_wd(pwdx); if (current_wd[0]) simplify_path(current_wd); /* Only set pwd if we know where we are or if it had a * bogus value */ if (current_wd[0] || pwd != null) /* setstr can't fail here */ setstr(pwd_v, current_wd, KSH_RETURN_ERROR); } ppid = getppid(); setint(global("PPID"), (long) ppid);#ifdef KSH setint(global("RANDOM"), (long) (time((time_t *)0) * kshpid * ppid));#endif /* KSH */ /* setstr can't fail here */ setstr(global(version_param), ksh_version, KSH_RETURN_ERROR); /* execute initialization statements */ for (wp = (char**) initcoms; *wp != NULL; wp++) { shcomexec(wp); for (; *wp != NULL; wp++) ; } ksheuid = geteuid(); safe_prompt = ksheuid ? "$ " : "# "; { struct tbl *vp = global("PS1"); /* Set PS1 if it isn't set, or we are root and prompt doesn't * contain a #. */ if (!(vp->flag & ISSET) || (!ksheuid && !strchr(str_val(vp), '#'))) /* setstr can't fail here */ setstr(vp, safe_prompt, KSH_RETURN_ERROR); } /* Set this before parsing arguments */ Flag(FPRIVILEGED) = getuid() != ksheuid || getgid() != getegid(); /* this to note if monitor is set on command line (see below) */ Flag(FMONITOR) = 127; argi = parse_args(argv, OF_CMDLINE, (int *) 0); if (argi < 0) exit(1); if (Flag(FCOMMAND)) { s = pushs(SSTRING, ATEMP); if (!(s->start = s->str = argv[argi++])) errorf("-c requires an argument"); if (argv[argi]) kshname = argv[argi++]; } else if (argi < argc && !Flag(FSTDIN)) { s = pushs(SFILE, ATEMP);#ifdef OS2 /* a bug in os2 extproc shell processing doesn't * pass full pathnames so we have to search for it. * This changes the behavior of 'ksh arg' to search * the users search path but it can't be helped. */ s->file = search(argv[argi++], path, R_OK, (int *) 0); if (!s->file || !*s->file) s->file = argv[argi - 1];#else s->file = argv[argi++];#endif /* OS2 */ s->u.shf = shf_open(s->file, O_RDONLY, 0, SHF_MAPHI|SHF_CLEXEC); if (s->u.shf == NULL) { exstat = 127; /* POSIX */ errorf("%s: %s", s->file, strerror(errno)); } kshname = s->file; } else { Flag(FSTDIN) = 1; s = pushs(SSTDIN, ATEMP); s->file = "<stdin>"; s->u.shf = shf_fdopen(0, SHF_RD | can_seek(0), (struct shf *) 0); if (!Flag(FNOTTALKING) && isatty(0) && isatty(2)) { Flag(FTALKING) = Flag(FTALKING_I) = 1; /* The following only if isatty(0) */ s->flags |= SF_TTY; s->u.shf->flags |= SHF_INTERRUPT; s->file = (char *) 0; } } /* This bizarreness is mandated by POSIX */ { struct stat s_stdin; if (fstat(0, &s_stdin) >= 0 && S_ISCHR(s_stdin.st_mode)) reset_nonblock(0); } /* initialize job control */ i = Flag(FMONITOR) != 127; Flag(FMONITOR) = 0; j_init(i);#ifdef EDIT /* Do this after j_init(), as tty_fd is not initialized 'til then */ if (Flag(FTALKING)) x_init();#endif l = e->loc; l->argv = &argv[argi - 1]; l->argc = argc - argi; l->argv[0] = (char *) kshname; getopts_reset(1); /* Disable during .profile/ENV reading */ restricted = Flag(FRESTRICTED); Flag(FRESTRICTED) = 0; errexit = Flag(FERREXIT); Flag(FERREXIT) = 0; /* Do this before profile/$ENV so that if it causes problems in them, * user will know why things broke. */ if (!current_wd[0] && Flag(FTALKING)) warningf(FALSE, "Cannot determine current working directory"); if (Flag(FLOGIN)) {#ifdef OS2 char *profile; /* Try to find a profile - first see if $INIT has a value, * then try /etc/profile.ksh, then c:/usr/etc/profile.ksh. */ if (!Flag(FPRIVILEGED) && strcmp(profile = substitute("$INIT/profile.ksh", 0), "/profile.ksh")) include(profile, 0, (char **) 0, 1); else if (include("/etc/profile.ksh", 0, (char **) 0, 1) < 0) include("c:/usr/etc/profile.ksh", 0, (char **) 0, 1); if (!Flag(FPRIVILEGED)) include(substitute("$HOME/profile.ksh", 0), 0, (char **) 0, 1);#else /* OS2 */ include(KSH_SYSTEM_PROFILE, 0, (char **) 0, 1); if (!Flag(FPRIVILEGED)) include(substitute("$HOME/.profile", 0), 0, (char **) 0, 1);#endif /* OS2 */ } if (Flag(FPRIVILEGED)) include("/etc/suid_profile", 0, (char **) 0, 1); else { char *env_file;#ifndef KSH if (!Flag(FPOSIX)) env_file = null; else#endif /* !KSH */ /* include $ENV */ env_file = str_val(global("ENV"));#ifdef DEFAULT_ENV /* If env isn't set, include default environment */ if (env_file == null) env_file = DEFAULT_ENV;#endif /* DEFAULT_ENV */ env_file = substitute(env_file, DOTILDE); if (*env_file != '\0') include(env_file, 0, (char **) 0, 1);#ifdef OS2 else if (Flag(FTALKING)) include(substitute("$HOME/kshrc.ksh", 0), 0, (char **) 0, 1);#endif /* OS2 */ } if (is_restricted(argv[0]) || is_restricted(str_val(global("SHELL")))) restricted = 1; if (restricted) { static const char *const restr_com[] = { "typeset", "-r", "PATH", "ENV", "SHELL", (char *) 0 }; shcomexec((char **) restr_com); /* After typeset command... */ Flag(FRESTRICTED) = 1; } if (errexit) Flag(FERREXIT) = 1; if (Flag(FTALKING)) { hist_init(s);#ifdef KSH alarm_init();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -