From e43b2acd67a7b06d4653ff910af1b4b51aedcdfe Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Fri, 1 Apr 2005 10:30:08 +0000 Subject: 21078: parse errors didn't cause non-zero exit status --- Src/init.c | 407 ++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 312 insertions(+), 95 deletions(-) (limited to 'Src') diff --git a/Src/init.c b/Src/init.c index e7dec681e..4fdf38de7 100644 --- a/Src/init.c +++ b/Src/init.c @@ -34,6 +34,8 @@ #include "init.pro" +#include "version.h" + /**/ int noexitct = 0; @@ -105,7 +107,8 @@ loop(int toplevel, int justonce) pushheap(); for (;;) { freeheap(); - errflag = 0; + if (stophist == 3) /* re-entry via preprompt() */ + hend(NULL); hbegin(1); /* init history mech */ if (isset(SHINSTDIN)) { setblock_stdin(); @@ -113,43 +116,55 @@ loop(int toplevel, int justonce) int hstop = stophist; stophist = 3; preprompt(); - stophist = hstop; + if (stophist != 3) + hbegin(1); + else + stophist = hstop; + errflag = 0; } } intr(); /* interrupts on */ lexinit(); /* initialize lexical state */ if (!(prog = parse_event())) { /* if we couldn't parse a list */ - hend(); + hend(NULL); if ((tok == ENDINPUT && !errflag) || (tok == LEXERR && (!isset(SHINSTDIN) || !toplevel)) || justonce) break; + if (tok == LEXERR && !lastval) + lastval = 1; continue; } - if (hend()) { + if (hend(prog)) { int toksav = tok; Eprog preprog; if (toplevel && (preprog = getshfunc("preexec")) != &dummy_eprog) { LinkList args; int osc = sfcontext; + char *cmdstr; args = znewlinklist(); zaddlinknode(args, "preexec"); - if (hist_ring) + /* If curline got dumped from the history, we don't know + * what the user typed. */ + if (hist_ring && curline.histnum == curhist) zaddlinknode(args, hist_ring->text); + else + zaddlinknode(args, ""); + zaddlinknode(args, getjobtext(prog, NULL)); + zaddlinknode(args, cmdstr = getpermtext(prog, NULL)); sfcontext = SFC_HOOK; doshfunc("preexec", preprog, args, 0, 1); sfcontext = osc; + zsfree(cmdstr); freelinklist(args, (FreeFunc) NULL); errflag = 0; } if (stopmsg) /* unset 'you have stopped jobs' flag */ stopmsg--; execode(prog, 0, 0); - if (toplevel) - freeeprogs(); tok = toksav; if (toplevel) noexitct = 0; @@ -184,10 +199,10 @@ static int restricted; void parseargs(char **argv) { + int optionbreak = 0; char **x; int action, optno; LinkList paramlist; - int bourne = (emulation == EMULATE_KSH || emulation == EMULATE_SH); argzero = *argv++; SHIN = 0; @@ -204,24 +219,47 @@ parseargs(char **argv) opts[SINGLECOMMAND] = 0; /* loop through command line options (begins with "-" or "+") */ - while (*argv && (**argv == '-' || **argv == '+')) { + while (!optionbreak && *argv && (**argv == '-' || **argv == '+')) { char *args = *argv; action = (**argv == '-'); - if(!argv[0][1]) + if (!argv[0][1]) *argv = "--"; while (*++*argv) { - /* The pseudo-option `--' signifies the end of options. * - * `-b' does too, csh-style, unless we're emulating a * - * Bourne style shell. */ - if (**argv == '-' || (!bourne && **argv == 'b')) { - argv++; - goto doneoptions; + if (**argv == '-') { + if(!argv[0][1]) { + /* The pseudo-option `--' signifies the end of options. */ + argv++; + goto doneoptions; + } + if(*argv != args+1 || **argv != '-') + goto badoptionstring; + /* GNU-style long options */ + ++*argv; + if (!strcmp(*argv, "version")) { + printf("zsh %s (%s-%s-%s)\n", + ZSH_VERSION, MACHTYPE, VENDOR, OSTYPE); + exit(0); + } + if (!strcmp(*argv, "help")) { + printhelp(); + exit(0); + } + /* `-' characters are allowed in long options */ + for(args = *argv; *args; args++) + if(*args == '-') + *args = '_'; + goto longoptions; } - if (**argv == 'c') { /* -c command */ + if (unset(SHOPTIONLETTERS) && **argv == 'b') { + /* -b ends options at the end of this argument */ + optionbreak = 1; + } else if (**argv == 'c') { + /* -c command */ cmd = *argv; opts[INTERACTIVE] &= 1; opts[SHINSTDIN] = 0; + scriptname = ztrdup("zsh"); } else if (**argv == 'o') { if (!*++*argv) argv++; @@ -229,9 +267,11 @@ parseargs(char **argv) zerr("string expected after -o", NULL, 0); exit(1); } - if(!(optno = optlookup(*argv))) + longoptions: + if (!(optno = optlookup(*argv))) { zerr("no such option: %s", *argv, 0); - else if (optno == RESTRICTED) + exit(1); + } else if (optno == RESTRICTED) restricted = action; else dosetopt(optno, action, 1); @@ -240,6 +280,7 @@ parseargs(char **argv) /* zsh's typtab not yet set, have to use ctype */ while (*++*argv) if (!isspace(STOUC(**argv))) { + badoptionstring: zerr("bad option string: `%s'", args, 0); exit(1); } @@ -284,19 +325,37 @@ parseargs(char **argv) if(isset(SINGLECOMMAND)) opts[INTERACTIVE] &= 1; opts[INTERACTIVE] = !!opts[INTERACTIVE]; - pparams = x = (char **) zcalloc((countlinknodes(paramlist) + 1) * sizeof(char *)); + pparams = x = (char **) zshcalloc((countlinknodes(paramlist) + 1) * sizeof(char *)); while ((*x++ = (char *)getlinknode(paramlist))); free(paramlist); argzero = ztrdup(argzero); } +/**/ +static void +printhelp(void) +{ + printf("Usage: %s [] [ ...]\n", argzero); + printf("\nSpecial options:\n"); + printf(" --help show this message, then exit\n"); + printf(" --version show zsh version number, then exit\n"); + if(unset(SHOPTIONLETTERS)) + printf(" -b end option processing, like --\n"); + printf(" -c take first argument as a command to execute\n"); + printf(" -o OPTION set an option by name (see below)\n"); + printf("\nNormal options are named. An option may be turned on by\n"); + printf("`-o OPTION', `--OPTION', `+o no_OPTION' or `+-no-OPTION'. An\n"); + printf("option may be turned off by `-o no_OPTION', `--no-OPTION',\n"); + printf("`+o OPTION' or `+-OPTION'. Options are listed below only in\n"); + printf("`--OPTION' or `--no-OPTION' form.\n"); + printoptionlist(); +} /**/ mod_export void init_io(void) { - long ttpgrp; static char outbuf[BUFSIZ], errbuf[BUFSIZ]; #ifdef RSH_BUG_WORKAROUND @@ -322,7 +381,13 @@ init_io(void) #endif if (shout) { - fclose(shout); + /* + * Check if shout was set to stderr, if so don't close it. + * We do this if we are interactive but don't have a + * terminal. + */ + if (shout != stderr) + fclose(shout); shout = 0; } if (SHTTY != -1) { @@ -391,29 +456,21 @@ init_io(void) /* We will only use zle if shell is interactive, * * SHTTY != -1, and shout != 0 */ - if (interact && SHTTY != -1) { + if (interact) { init_shout(); - if(!shout) + if(!SHTTY || !shout) opts[USEZLE] = 0; } else opts[USEZLE] = 0; #ifdef JOB_CONTROL - /* If interactive, make the shell the foreground process */ + /* If interactive, make sure the shell is in the foreground and is the + * process group leader. + */ + mypid = (zlong)getpid(); if (opts[MONITOR] && interact && (SHTTY != -1)) { - if ((mypgrp = GETPGRP()) > 0) { - while ((ttpgrp = gettygrp()) != -1 && ttpgrp != mypgrp) { - sleep(1); /* give parent time to change pgrp */ - mypgrp = GETPGRP(); - if (mypgrp == mypid) - attachtty(mypgrp); - if (mypgrp == gettygrp()) - break; - killpg(mypgrp, SIGTTIN); - mypgrp = GETPGRP(); - } - } else - opts[MONITOR] = 0; + origpgrp = GETPGRP(); + acquire_pgrp(); /* might also clear opts[MONITOR] */ } else opts[MONITOR] = 0; #else @@ -427,8 +484,18 @@ init_shout(void) { static char shoutbuf[BUFSIZ]; #if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC) - int ldisc = NTTYDISC; + int ldisc; +#endif + + if (SHTTY == -1) + { + /* Since we're interative, it's nice to have somewhere to write. */ + shout = stderr; + return; + } +#if defined(JOB_CONTROL) && defined(TIOCSETD) && defined(NTTYDISC) + ldisc = NTTYDISC; ioctl(SHTTY, TIOCSETD, (char *)&ldisc); #endif @@ -450,7 +517,8 @@ init_shout(void) static char *tccapnams[TC_COUNT] = { "cl", "le", "LE", "nd", "RI", "up", "UP", "do", "DO", "dc", "DC", "ic", "IC", "cd", "ce", "al", "dl", "ta", - "md", "so", "us", "me", "se", "ue", "ch" + "md", "so", "us", "me", "se", "ue", "ch", + "ku", "kd", "kl", "kr" }; /* Initialise termcap */ @@ -474,13 +542,13 @@ init_term(void) #ifdef TGETENT_ACCEPTS_NULL /* If possible, we let tgetent allocate its own termcap buffer */ - if (tgetent(NULL, term) != 1) { + if (tgetent(NULL, term) != TGETENT_SUCCESS) #else - if (tgetent(termbuf, term) != 1) { + if (tgetent(termbuf, term) != TGETENT_SUCCESS) #endif - + { if (isset(INTERACTIVE)) - zerr("can't find termcap info for %s", term, 0); + zerr("can't find terminal definition for %s", term, 0); errflag = 0; termflags |= TERM_BAD; return 0; @@ -552,14 +620,11 @@ setupvals(void) #endif struct timezone dummy_tz; char *ptr; -#ifdef HAVE_GETRLIMIT - int i; -#endif + int i, j; #if defined(SITEFPATH_DIR) || defined(FPATH_DIR) char **fpathptr; # if defined(FPATH_DIR) && defined(FPATH_SUBDIRS) char *fpath_subdirs[] = FPATH_SUBDIRS; - int j; # endif # ifdef SITEFPATH_DIR int fpathlen = 1; @@ -567,6 +632,47 @@ setupvals(void) int fpathlen = 0; # endif #endif + int close_fds[10], tmppipe[2]; + + /* + * Workaround a problem with NIS (in one guise or another) which + * grabs file descriptors and keeps them for future reference. + * We don't want these to be in the range where the user can + * open fd's, i.e. 0 to 9 inclusive. So we make sure all + * fd's in that range are in use. + */ + memset(close_fds, 0, 10*sizeof(int)); + if (pipe(tmppipe) == 0) { + /* + * Strategy: Make sure we have at least fd 0 open (hence + * the pipe). From then on, keep dup'ing until we are + * up to 9. If we go over the top, close immediately, else + * mark for later closure. + */ + i = -1; /* max fd we have checked */ + while (i < 9) { + /* j is current fd */ + if (i < tmppipe[0]) + j = tmppipe[0]; + else if (i < tmppipe[1]) + j = tmppipe[1]; + else { + j = dup(0); + if (j == -1) + break; + } + if (j < 10) + close_fds[j] = 1; + else + close(j); + if (i < j) + i = j; + } + if (i < tmppipe[0]) + close(tmppipe[0]); + if (i < tmppipe[1]) + close(tmppipe[1]); + } addhookdefs(argzero, zshhooks, sizeof(zshhooks)/sizeof(*zshhooks)); @@ -594,9 +700,6 @@ setupvals(void) gettimeofday(&shtimer, &dummy_tz); /* init $SECONDS */ srand((unsigned int)(shtimer.tv_sec + shtimer.tv_usec)); /* seed $RANDOM */ - hostnam = (char *) zalloc(256); - gethostname(hostnam, 256); - /* Set default path */ path = (char **) zalloc(sizeof(*path) * 5); path[0] = ztrdup("/bin"); @@ -695,7 +798,8 @@ setupvals(void) * initialize `PWD' from `HOME' */ if (ispwd(home)) pwd = ztrdup(home); - else if ((ptr = zgetenv("PWD")) && ispwd(ptr)) + else if ((ptr = zgetenv("PWD")) && (strlen(ptr) < PATH_MAX) && + (ptr = metafy(ptr, -1, META_STATIC), ispwd(ptr))) pwd = ztrdup(ptr); else pwd = metafy(zgetcwd(), -1, META_DUP); @@ -706,12 +810,12 @@ setupvals(void) initlextabs(); /* initialize lexing tables */ createreswdtable(); /* create hash table for reserved words */ - createaliastable(); /* create hash table for aliases */ + createaliastables(); /* create hash tables for aliases */ createcmdnamtable(); /* create hash table for external commands */ createshfunctable(); /* create hash table for shell functions */ createbuiltintable(); /* create hash table for builtin commands */ createnameddirtable(); /* create hash table for named directories */ - createparamtable(); /* create paramater hash table */ + createparamtable(); /* create parameter hash table */ condtab = NULL; wrappers = NULL; @@ -754,7 +858,12 @@ setupvals(void) #endif } - times(&shtms); + get_usage(); + + /* Close the file descriptors we opened to block off 0 to 9 */ + for (i = 0; i < 10; i++) + if (close_fds[i]) + close(i); } /* Initialize signal handling */ @@ -763,6 +872,12 @@ setupvals(void) void init_signals(void) { + if (interact) { + int i; + signal_setmask(signal_mask(0)); + for (i=0; i= PATH_MAX) { - zerr("path too long: %s", s, 0); - return; + + { + /* Let source() complain if path is too long */ + VARARR(char, buf, strlen(h) + strlen(s) + 2); + sprintf(buf, "%s/%s", h, s); + unqueue_signals(); + source(buf); } - sprintf(buf, "%s/%s", h, s); - source(buf); } /**/ @@ -1009,7 +1110,7 @@ noop_function(void) /**/ mod_export void -noop_function_int(int nothing) +noop_function_int(UNUSED(int nothing)) { /* do nothing */ } @@ -1024,51 +1125,63 @@ noop_function_int(int nothing) /**/ mod_export ZleVoidFn trashzleptr = noop_function; /**/ -mod_export ZleVoidFn gotwordptr = noop_function; -/**/ mod_export ZleVoidFn refreshptr = noop_function; /**/ mod_export ZleVoidIntFn spaceinlineptr = noop_function_int; /**/ mod_export ZleReadFn zlereadptr = autoload_zleread; +/**/ +mod_export ZleVoidIntFn zlesetkeymapptr = noop_function_int; #else /* !LINKED_XMOD_zshQszle */ mod_export ZleVoidFn trashzleptr = noop_function; -mod_export ZleVoidFn gotwordptr = noop_function; mod_export ZleVoidFn refreshptr = noop_function; mod_export ZleVoidIntFn spaceinlineptr = noop_function_int; # ifdef UNLINKED_XMOD_zshQszle mod_export ZleReadFn zlereadptr = autoload_zleread; +mod_export ZleVoidIntFn zlesetkeymapptr = autoload_zlesetkeymap; # else /* !UNLINKED_XMOD_zshQszle */ mod_export ZleReadFn zlereadptr = fallback_zleread; +mod_export ZleVoidIntFn zlesetkeymapptr = noop_function_int; # endif /* !UNLINKED_XMOD_zshQszle */ #endif /* !LINKED_XMOD_zshQszle */ /**/ unsigned char * -autoload_zleread(char *lp, char *rp, int ha) +autoload_zleread(char **lp, char **rp, int ha, int con) { zlereadptr = fallback_zleread; if (load_module("zsh/zle")) load_module("zsh/compctl"); - return zleread(lp, rp, ha); + return zleread(lp, rp, ha, con); } /**/ mod_export unsigned char * -fallback_zleread(char *lp, char *rp, int ha) +fallback_zleread(char **lp, UNUSED(char **rp), UNUSED(int ha), UNUSED(int con)) { char *pptbuf; int pptlen; - pptbuf = unmetafy(promptexpand(lp, 0, NULL, NULL), &pptlen); + pptbuf = unmetafy(promptexpand(lp ? *lp : NULL, 0, NULL, NULL), &pptlen); write(2, (WRITE_ARG_2_T)pptbuf, pptlen); free(pptbuf); + return (unsigned char *)shingetline(); } +/**/ +static void +autoload_zlesetkeymap(int mode) +{ + zlesetkeymapptr = noop_function_int; + load_module("zsh/zle"); + (*zlesetkeymapptr)(mode); +} + + /* compctl entry point pointers. Similar to the ZLE ones. */ /**/ @@ -1076,9 +1189,113 @@ mod_export CompctlReadFn compctlreadptr = fallback_compctlread; /**/ mod_export int -fallback_compctlread(char *name, char **args, char *ops, char *reply) +fallback_compctlread(char *name, UNUSED(char **args), UNUSED(Options ops), UNUSED(char *reply)) { zwarnnam(name, "option valid only in functions called from completion", NULL, 0); return 1; } + +/* + * This is real main entry point. This has to be mod_export'ed + * so zsh.exe can found it on Cygwin + */ + +/**/ +mod_export int +zsh_main(UNUSED(int argc), char **argv) +{ + char **t; + int t0; +#ifdef USE_LOCALE + setlocale(LC_ALL, ""); +#endif + + init_jobs(argv, environ); + + /* + * Provisionally set up the type table to allow metafication. + * This will be done properly when we have decided if we are + * interactive + */ + typtab['\0'] |= IMETA; + typtab[STOUC(Meta) ] |= IMETA; + typtab[STOUC(Marker)] |= IMETA; + for (t0 = (int)STOUC(Pound); t0 <= (int)STOUC(Nularg); t0++) + typtab[t0] |= ITOK | IMETA; + + for (t = argv; *t; *t = metafy(*t, -1, META_ALLOC), t++); + + zsh_name = argv[0]; + do { + char *arg0 = zsh_name; + if (!(zsh_name = strrchr(arg0, '/'))) + zsh_name = arg0; + else + zsh_name++; + if (*zsh_name == '-') + zsh_name++; + if (strcmp(zsh_name, "su") == 0) { + char *sh = zgetenv("SHELL"); + if (sh && *sh && arg0 != sh) + zsh_name = sh; + else + break; + } else + break; + } while (zsh_name); + + fdtable_size = zopenmax(); + fdtable = zshcalloc(fdtable_size); + + createoptiontable(); + emulate(zsh_name, 1); /* initialises most options */ + opts[LOGINSHELL] = (**argv == '-'); + opts[MONITOR] = 1; /* may be unset in init_io() */ + opts[PRIVILEGED] = (getuid() != geteuid() || getgid() != getegid()); + opts[USEZLE] = 1; /* may be unset in init_io() */ + parseargs(argv); /* sets INTERACTIVE, SHINSTDIN and SINGLECOMMAND */ + + SHTTY = -1; + init_io(); + setupvals(); + init_signals(); + init_bltinmods(); + run_init_scripts(); + init_misc(); + + for (;;) { + /* + * See if we can free up some of jobtab. + * We only do this at top level, because if we are + * executing stuff we may refer to them by job pointer. + */ + maybeshrinkjobtab(); + + do + loop(1,0); + while (tok != ENDINPUT && (tok != LEXERR || isset(SHINSTDIN))); + if (tok == LEXERR) { + /* Make sure a parse error exits with non-zero status */ + if (!lastval) + lastval = 1; + stopmsg = 1; + zexit(lastval, 0); + } + if (!(isset(IGNOREEOF) && interact)) { +#if 0 + if (interact) + fputs(islogin ? "logout\n" : "exit\n", shout); +#endif + zexit(lastval, 0); + continue; + } + noexitct++; + if (noexitct >= 10) { + stopmsg = 1; + zexit(lastval, 0); + } + zerrnam("zsh", (!islogin) ? "use 'exit' to exit." + : "use 'logout' to logout.", NULL, 0); + } +} -- cgit 1.4.1