/* PATCH IDEA FROM Issei.Suzuki VERY THANKS */ void autoset_dspmbyte(const Char *pcp) { int i; static const struct dspm_autoset_Table { Char *n; Char *v; } dspmt[] = { { STRLANGEUCJP, STReuc }, { STRLANGEUCKR, STReuc }, { STRLANGEUCZH, STReuc }, { STRLANGEUCJPB, STReuc }, { STRLANGEUCKRB, STReuc }, { STRLANGEUCZHB, STReuc }, #ifdef __linux__ { STRLANGEUCJPC, STReuc }, #endif { STRLANGSJIS, STRsjis }, { STRLANGSJISB, STRsjis }, { STRLANGBIG5, STRbig5 }, { STRstarutfstar8, STRutf8 }, { NULL, NULL } }; #if defined(HAVE_NL_LANGINFO) && defined(CODESET) static const struct dspm_autoset_Table dspmc[] = { { STRstarutfstar8, STRutf8 }, { STReuc, STReuc }, { STRGB2312, STReuc }, { STRLANGBIG5, STRbig5 }, { NULL, NULL } }; Char *codeset; codeset = str2short(nl_langinfo(CODESET)); if (*codeset != '\0') { for (i = 0; dspmc[i].n; i++) { const Char *estr; if (dspmc[i].n[0] && t_pmatch(pcp, dspmc[i].n, &estr, 0) > 0) { setcopy(CHECK_MBYTEVAR, dspmc[i].v, VAR_READWRITE); update_dspmbyte_vars(); return; } } } #endif if (*pcp == '\0') return; for (i = 0; dspmt[i].n; i++) { const Char *estr; if (dspmt[i].n[0] && t_pmatch(pcp, dspmt[i].n, &estr, 0) > 0) { setcopy(CHECK_MBYTEVAR, dspmt[i].v, VAR_READWRITE); update_dspmbyte_vars(); break; } } }
static void dset(Char *dp) { /* * Don't call set() directly cause if the directory contains ` or * other junk characters glob will fail. */ setcopy(STRowd, varval(STRcwd), VAR_READWRITE|VAR_NOGLOB); setcopy(STRcwd, dp, VAR_READWRITE|VAR_NOGLOB); tsetenv(STRPWD, dp); }
static void auto_logout(void) { xprintf("auto-logout\n"); /* Don't leave the tty in raw mode */ if (editing) (void) Cookedmode(); xclose(SHIN); setcopy(STRlogout, STRautomatic, VAR_READWRITE); child = 1; #ifdef TESLA do_logout = 1; #endif /* TESLA */ GettingInput = FALSE; /* make flush() work to write hist files. Huber*/ goodbye(NULL, NULL); }
/*ARGSUSED*/ void dowhich(Char **v, struct command *c) { int rv = TRUE; USE(c); /* * We don't want to glob dowhich args because we lose quoteing * E.g. which \ls if ls is aliased will not work correctly if * we glob here. */ while (*++v) rv &= cmd_expand(*v, NULL); if (!rv) setcopy(STRstatus, STR1, VAR_READWRITE); }
void dotitle(Char **vc, struct command * c) { int k; char titlebuf[512]; char errbuf[128],err2[128]; char **v; Char **nvc; UNREFERENCED_PARAMETER(c); vc++; nvc = glob_all_or_error(vc); if (nvc == NULL) return; if (nvc != vc) cleanup_push(nvc, blk_cleanup); if ((k = GetConsoleTitle(titlebuf, sizeof(titlebuf))) != 0) { setcopy(STRoldtitle,str2short(titlebuf), VAR_READWRITE|VAR_NOGLOB); } titlebuf[0] = '\0'; v = short2blk(nvc); if (nvc != vc) cleanup_until(nvc); cleanup_push((Char **)v, blk_cleanup); for (k = 0; v[k] != NULL ; k++){ __try { StringCbCat(titlebuf,sizeof(titlebuf),v[k]); StringCbCat(titlebuf,sizeof(titlebuf)," "); } __except(GetExceptionCode()) { stderror(ERR_TOOMANY); } } if (!SetConsoleTitle(titlebuf) ) { make_err_str(GetLastError(),errbuf,128); (void)StringCbPrintf(err2,sizeof(err2),"%s",v[k]); stderror(ERR_SYSTEM,err2,errbuf); } cleanup_until((Char **)v); return; }
void fixerror(void) { didfds = 0; /* Forget about 0,1,2 */ /* * Go away if -e or we are a child shell */ if (!exitset || exiterr || child) xexit(1); /* * Reset the state of the input. This buffered seek to end of file will * also clear the while/foreach stack. */ btoeof(); setcopy(STRstatus, STR1, VAR_READWRITE);/*FIXRESET*/ #ifdef BSDJOBS if (tpgrp > 0) (void) tcsetpgrp(FSHTTY, tpgrp); #endif }
/* Set variable name to NULL. */ void setNS(const Char *varName) { setcopy(varName, STRNULL, VAR_READWRITE); }
static void update_vars(Char *vp) { if (eq(vp, STRpath)) { struct varent *p = adrof(STRpath); if (p == NULL) stderror(ERR_NAME | ERR_UNDVAR); else { exportpath(p->vec); dohash(NULL, NULL); } } else if (eq(vp, STRnoclobber)) { struct varent *p = adrof(STRnoclobber); if (p == NULL) stderror(ERR_NAME | ERR_UNDVAR); else no_clobber = set_noclobber(p->vec); } else if (eq(vp, STRhistchars)) { Char *pn = varval(vp); HIST = *pn++; if (HIST) HISTSUB = *pn; else HISTSUB = HIST; } else if (eq(vp, STRpromptchars)) { Char *pn = varval(vp); PRCH = *pn++; if (PRCH) PRCHROOT = *pn; else PRCHROOT = PRCH; } else if (eq(vp, STRhistlit)) { HistLit = 1; } else if (eq(vp, STRuser)) { tsetenv(STRKUSER, varval(vp)); tsetenv(STRLOGNAME, varval(vp)); } else if (eq(vp, STRgroup)) { tsetenv(STRKGROUP, varval(vp)); } else if (eq(vp, STRwordchars)) { word_chars = varval(vp); } else if (eq(vp, STRloginsh)) { loginsh = 1; } else if (eq(vp, STRanyerror)) { anyerror = 1; } else if (eq(vp, STRsymlinks)) { Char *pn = varval(vp); if (eq(pn, STRignore)) symlinks = SYM_IGNORE; else if (eq(pn, STRexpand)) symlinks = SYM_EXPAND; else if (eq(pn, STRchase)) symlinks = SYM_CHASE; else symlinks = 0; } else if (eq(vp, STRterm)) { Char *cp = varval(vp); tsetenv(STRKTERM, cp); #ifdef DOESNT_WORK_RIGHT cp = getenv("TERMCAP"); if (cp && (*cp != '/')) /* if TERMCAP and not a path */ Unsetenv(STRTERMCAP); #endif /* DOESNT_WORK_RIGHT */ GotTermCaps = 0; if (noediting && Strcmp(cp, STRnetwork) != 0 && Strcmp(cp, STRunknown) != 0 && Strcmp(cp, STRdumb) != 0) { editing = 1; noediting = 0; setNS(STRedit); } ed_Init(); /* reset the editor */ } else if (eq(vp, STRhome)) { Char *cp, *canon; cp = Strsave(varval(vp)); /* get the old value back */ cleanup_push(cp, xfree); /* * convert to cononical pathname (possibly resolving symlinks) */ canon = dcanon(cp, cp); cleanup_ignore(cp); cleanup_until(cp); cleanup_push(canon, xfree); setcopy(vp, canon, VAR_READWRITE); /* have to save the new val */ /* and now mirror home with HOME */ tsetenv(STRKHOME, canon); /* fix directory stack for new tilde home */ dtilde(); cleanup_until(canon); } else if (eq(vp, STRedit)) { editing = 1; noediting = 0; /* PWP: add more stuff in here later */ } else if (eq(vp, STRvimode)) { VImode = 1; update_wordchars(); } else if (eq(vp, STRshlvl)) { tsetenv(STRKSHLVL, varval(vp)); } else if (eq(vp, STRignoreeof)) { Char *cp; numeof = 0; for ((cp = varval(STRignoreeof)); cp && *cp; cp++) { if (!Isdigit(*cp)) { numeof = 0; break; } numeof = numeof * 10 + *cp - '0'; } if (numeof <= 0) numeof = 26; /* Sanity check */ } else if (eq(vp, STRbackslash_quote)) { bslash_quote = 1; } else if (eq(vp, STRcompat_expr)) { compat_expr = 1; } else if (eq(vp, STRdirstack)) { dsetstack(); } else if (eq(vp, STRrecognize_only_executables)) { tw_cmd_free(); } else if (eq(vp, STRkillring)) { SetKillRing((int)getn(varval(vp))); } else if (eq(vp, STRhistory)) { sethistory((int)getn(varval(vp))); } #ifndef HAVENOUTMP else if (eq(vp, STRwatch)) { resetwatch(); } #endif /* HAVENOUTMP */ else if (eq(vp, STRimplicitcd)) { implicit_cd = ((eq(varval(vp), STRverbose)) ? 2 : 1); } else if (eq(vp, STRcdtohome)) { cdtohome = 1; } #ifdef COLOR_LS_F else if (eq(vp, STRcolor)) { set_color_context(); } #endif /* COLOR_LS_F */ #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) else if(eq(vp, CHECK_MBYTEVAR) || eq(vp, STRnokanji)) { update_dspmbyte_vars(); } #endif #ifdef NLS_CATALOGS else if (eq(vp, STRcatalog)) { nlsclose(); nlsinit(); } #if defined(FILEC) && defined(TIOCSTI) else if (eq(vp, STRfilec)) filec = 1; #endif #endif /* NLS_CATALOGS */ }
void update_dspmbyte_vars(void) { int lp, iskcode; Char *dstr1; struct varent *vp; /* if variable "nokanji" is set, multi-byte display is disabled */ if ((vp = adrof(CHECK_MBYTEVAR)) && !adrof(STRnokanji)) { _enable_mbdisp = 1; dstr1 = vp->vec[0]; if(eq (dstr1, STRsjis)) iskcode = 1; else if (eq(dstr1, STReuc)) iskcode = 2; else if (eq(dstr1, STRbig5)) iskcode = 3; else if (eq(dstr1, STRutf8)) iskcode = 4; else if ((dstr1[0] - '0') >= 0 && (dstr1[0] - '0') <= 3) { iskcode = 0; } else { xprintf(CGETS(18, 2, "Warning: unknown multibyte display; using default(euc(JP))\n")); iskcode = 2; } if (dstr1 && vp->vec[1] && eq(vp->vec[1], STRls)) dspmbyte_ls = 1; else dspmbyte_ls = 0; for (lp = 0; lp < 256 && iskcode > 0; lp++) { switch (iskcode) { case 1: /* Shift-JIS */ _cmap[lp] = _cmap_mbyte[lp]; _mbmap[lp] = _mbmap_sjis[lp]; break; case 2: /* 2 ... euc */ _cmap[lp] = _cmap_mbyte[lp]; _mbmap[lp] = _mbmap_euc[lp]; break; case 3: /* 3 ... big5 */ _cmap[lp] = _cmap_mbyte[lp]; _mbmap[lp] = _mbmap_big5[lp]; break; case 4: /* 4 ... utf8 */ _cmap[lp] = _cmap_mbyte[lp]; _mbmap[lp] = _mbmap_utf8[lp]; break; default: xprintf(CGETS(18, 3, "Warning: unknown multibyte code %d; multibyte disabled\n"), iskcode); _cmap[lp] = _cmap_c[lp]; _mbmap[lp] = 0; /* Default map all 0 */ _enable_mbdisp = 0; break; } } if (iskcode == 0) { /* check original table */ if (Strlen(dstr1) != 256) { xprintf(CGETS(18, 4, "Warning: Invalid multibyte table length (%d); multibyte disabled\n"), Strlen(dstr1)); _enable_mbdisp = 0; } for (lp = 0; lp < 256 && _enable_mbdisp == 1; lp++) { if (!((dstr1[lp] - '0') >= 0 && (dstr1[lp] - '0') <= 3)) { xprintf(CGETS(18, 4, "Warning: bad multibyte code at offset +%d; multibyte diabled\n"), lp); _enable_mbdisp = 0; break; } } /* set original table */ for (lp = 0; lp < 256; lp++) { if (_enable_mbdisp == 1) { _cmap[lp] = _cmap_mbyte[lp]; _mbmap[lp] = (unsigned short) ((dstr1[lp] - '0') & 0x0f); } else { _cmap[lp] = _cmap_c[lp]; _mbmap[lp] = 0; /* Default map all 0 */ } } } } else { for (lp = 0; lp < 256; lp++) { _cmap[lp] = _cmap_c[lp]; _mbmap[lp] = 0; /* Default map all 0 */ } _enable_mbdisp = 0; dspmbyte_ls = 0; } #ifdef MBYTEDEBUG /* Sorry, use for beta testing */ { Char mbmapstr[300]; for (lp = 0; lp < 256; lp++) mbmapstr[lp] = _mbmap[lp] + '0'; mbmapstr[lp] = 0; setcopy(STRmbytemap, mbmapstr, VAR_READWRITE); } #endif /* MBYTEMAP */ }
/* fix_version(): * Print a reasonable version string, printing all compile time * options that might affect the user. */ void fix_version(void) { #ifdef WIDE_STRINGS # define SSSTR "wide" #elif defined (SHORT_STRINGS) # define SSSTR "8b" #else # define SSSTR "7b" #endif #ifdef NLS # define NLSSTR ",nls" #else # define NLSSTR "" #endif #ifdef LOGINFIRST # define LFSTR ",lf" #else # define LFSTR "" #endif #ifdef DOTLAST # define DLSTR ",dl" #else # define DLSTR "" #endif #ifdef VIDEFAULT # define VISTR ",vi" #else # define VISTR "" #endif #ifdef TESLA # define DTRSTR ",dtr" #else # define DTRSTR "" #endif #ifdef KAI # define BYESTR ",bye" #else # define BYESTR "" #endif #ifdef AUTOLOGOUT # define ALSTR ",al" #else # define ALSTR "" #endif #ifdef KANJI # define KANSTR ",kan" #else # define KANSTR "" #endif #ifdef SYSMALLOC # define SMSTR ",sm" #else # define SMSTR "" #endif #ifdef HASHBANG # define HBSTR ",hb" #else # define HBSTR "" #endif #ifdef NEWGRP # define NGSTR ",ng" #else # define NGSTR "" #endif #ifdef REMOTEHOST # define RHSTR ",rh" #else # define RHSTR "" #endif #ifdef AFS # define AFSSTR ",afs" #else # define AFSSTR "" #endif #ifdef NODOT # define NDSTR ",nd" #else # define NDSTR "" #endif #ifdef COLOR_LS_F # define COLORSTR ",color" #else /* ifndef COLOR_LS_F */ # define COLORSTR "" #endif /* COLOR_LS_F */ #ifdef DSPMBYTE # define DSPMSTR ",dspm" #else # define DSPMSTR "" #endif #ifdef COLORCAT # define CCATSTR ",ccat" #else # define CCATSTR "" #endif #if defined(FILEC) && defined(TIOCSTI) # define FILECSTR ",filec" #else # define FILECSTR "" #endif /* if you want your local version to say something */ #ifndef LOCALSTR # define LOCALSTR "" #endif /* LOCALSTR */ char *version; const Char *machtype = tgetenv(STRMACHTYPE); const Char *vendor = tgetenv(STRVENDOR); const Char *ostype = tgetenv(STROSTYPE); if (vendor == NULL) vendor = STRunknown; if (machtype == NULL) machtype = STRunknown; if (ostype == NULL) ostype = STRunknown; version = xasprintf( "%s" #ifdef CATCH_EXEC "(%s)" #endif " %d.%.2d.%.2d (%s) %s (%S-%S-%S) options %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", PROG_NAME, #ifdef CATCH_EXEC GDI_VERSION, #endif REV, VERS, PATCHLEVEL, ORIGIN, DATE, machtype, vendor, ostype, SSSTR, NLSSTR, LFSTR, DLSTR, VISTR, DTRSTR, BYESTR, ALSTR, KANSTR, SMSTR, HBSTR, NGSTR, RHSTR, AFSSTR, NDSTR, COLORSTR, DSPMSTR, CCATSTR, FILECSTR, LOCALSTR); cleanup_push(version, xfree); setcopy(STRversion, str2short(version), VAR_READWRITE); cleanup_until(version); version = xasprintf("%d.%.2d.%.2d", REV, VERS, PATCHLEVEL); cleanup_push(version, xfree); setcopy(STRtcsh, str2short(version), VAR_READWRITE); cleanup_until(version); }
void setNS(Char *cp) { setcopy(cp, STRNULL, VAR_READWRITE); }
/*VARARGS 1*/ void execute(struct command *t, volatile int wanttty, int *pipein, int *pipeout, int do_glob) { int forked = 0; const struct biltins * volatile bifunc; pid_t pid = 0; int pv[2]; sigset_t set; static sigset_t csigset; #ifdef VFORK static int onosigchld = 0; #endif /* VFORK */ static int nosigchld = 0; (void) &wanttty; (void) &forked; (void) &bifunc; if (t == 0) return; #ifdef WINNT_NATIVE { if ((varval(STRNTslowexec) == STRNULL) && !t->t_dcdr && !t->t_dcar && !t->t_dflg && !didfds && (intty || intact) && (t->t_dtyp == NODE_COMMAND) && !isbfunc(t)) { if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) (void) Strcpy(t->t_dcom[0], t->t_dcom[0] + 1); Dfix(t); if (nt_try_fast_exec(t) == 0) return; } } #endif /* WINNT_NATIVE */ /* * Ed [email protected] & Dominic [email protected] * Sat Feb 25 03:13:11 PST 1995 * try implicit cd if we have a 1 word command */ if (implicit_cd && (intty || intact) && t->t_dcom && t->t_dcom[0] && t->t_dcom[0][0] && (blklen(t->t_dcom) == 1) && !noexec) { Char *sCName; struct stat stbuf; char *pathname; sCName = dollar(t->t_dcom[0]); if (sCName != NULL && sCName[0] == '~') { struct Strbuf buf = Strbuf_INIT; const Char *name_end; for (name_end = sCName + 1; *name_end != '\0' && *name_end != '/'; name_end++) continue; if (name_end != sCName + 1) { Char *name, *home; name = Strnsave(sCName + 1, name_end - (sCName + 1)); home = gethdir(name); if (home != NULL) { Strbuf_append(&buf, home); xfree(home); } else Strbuf_append(&buf, name); xfree(name); } else Strbuf_append(&buf, varval(STRhome)); Strbuf_append(&buf, name_end); xfree(sCName); sCName = Strbuf_finish(&buf); } pathname = short2str(sCName); xfree(sCName); /* if this is a dir, tack a "cd" on as the first arg */ if (pathname != NULL && ((stat(pathname, &stbuf) != -1 && S_ISDIR(stbuf.st_mode)) #ifdef WINNT_NATIVE || (pathname[0] && pathname[1] == ':' && pathname[2] == '\0') #endif /* WINNT_NATIVE */ )) { Char *vCD[2]; Char **ot_dcom = t->t_dcom; vCD[0] = Strsave(STRcd); vCD[1] = NULL; t->t_dcom = blkspl(vCD, ot_dcom); xfree(ot_dcom); if (implicit_cd > 1) { blkpr(t->t_dcom); xputchar( '\n' ); } } } /* * From: Michael Schroeder <*****@*****.**> * Don't check for wantty > 0... */ if (t->t_dflg & F_AMPERSAND) wanttty = 0; switch (t->t_dtyp) { case NODE_COMMAND: if ((t->t_dcom[0][0] & (QUOTE | TRIM)) == QUOTE) memmove(t->t_dcom[0], t->t_dcom[0] + 1, (Strlen(t->t_dcom[0] + 1) + 1) * sizeof (*t->t_dcom[0])); if ((t->t_dflg & F_REPEAT) == 0) Dfix(t); /* $ " ' \ */ if (t->t_dcom[0] == 0) { return; } /*FALLTHROUGH*/ case NODE_PAREN: #ifdef BACKPIPE if (t->t_dflg & F_PIPEIN) mypipe(pipein); #else /* !BACKPIPE */ if (t->t_dflg & F_PIPEOUT) mypipe(pipeout); #endif /* BACKPIPE */ /* * Must do << early so parent will know where input pointer should be. * If noexec then this is all we do. */ if (t->t_dflg & F_READ) { xclose(0); heredoc(t->t_dlef); if (noexec) xclose(0); } setcopy(STRstatus, STR0, VAR_READWRITE); /* * This mess is the necessary kludge to handle the prefix builtins: * nice, nohup, time. These commands can also be used by themselves, * and this is not handled here. This will also work when loops are * parsed. */ while (t->t_dtyp == NODE_COMMAND) if (eq(t->t_dcom[0], STRnice)) { if (t->t_dcom[1]) { if (strchr("+-", t->t_dcom[1][0])) { if (t->t_dcom[2]) { setname("nice"); t->t_nice = (unsigned char)getn(t->t_dcom[1]); lshift(t->t_dcom, 2); t->t_dflg |= F_NICE; } else break; } else { t->t_nice = 4; lshift(t->t_dcom, 1); t->t_dflg |= F_NICE; } } else break; } else if (eq(t->t_dcom[0], STRnohup)) { if (t->t_dcom[1]) { t->t_dflg |= F_NOHUP; lshift(t->t_dcom, 1); } else break; } else if (eq(t->t_dcom[0], STRhup)) { if (t->t_dcom[1]) { t->t_dflg |= F_HUP; lshift(t->t_dcom, 1); } else break; } else if (eq(t->t_dcom[0], STRtime)) { if (t->t_dcom[1]) { t->t_dflg |= F_TIME; lshift(t->t_dcom, 1); } else break; } #ifdef F_VER else if (eq(t->t_dcom[0], STRver)) if (t->t_dcom[1] && t->t_dcom[2]) { setname("ver"); t->t_systype = getv(t->t_dcom[1]); lshift(t->t_dcom, 2); t->t_dflg |= F_VER; } else break; #endif /* F_VER */ else break; /* is it a command */ if (t->t_dtyp == NODE_COMMAND) { /* * Check if we have a builtin function and remember which one. */ bifunc = isbfunc(t); if (noexec) { /* * Continue for builtins that are part of the scripting language */ if (bifunc == NULL) break; if (bifunc->bfunct != (bfunc_t)dobreak && bifunc->bfunct != (bfunc_t)docontin && bifunc->bfunct != (bfunc_t)doelse && bifunc->bfunct != (bfunc_t)doend && bifunc->bfunct != (bfunc_t)doforeach&& bifunc->bfunct != (bfunc_t)dogoto && bifunc->bfunct != (bfunc_t)doif && bifunc->bfunct != (bfunc_t)dorepeat && bifunc->bfunct != (bfunc_t)doswbrk && bifunc->bfunct != (bfunc_t)doswitch && bifunc->bfunct != (bfunc_t)dowhile && bifunc->bfunct != (bfunc_t)dozip) break; } } else { /* not a command */ bifunc = NULL; if (noexec) break; } /* * GrP Executing a command - run jobcmd hook * Don't run for builtins * Don't run if we're not in a tty * Don't run if we're not really executing */ /* * CR - Charles Ross Aug 2005 * added "isoutatty". * The new behavior is that the jobcmd won't be executed * if stdout (SHOUT) isnt attached to a tty.. IE when * redirecting, or using backquotes etc.. */ if (t->t_dtyp == NODE_COMMAND && !bifunc && !noexec && intty && isoutatty) { Char *cmd = unparse(t); cleanup_push(cmd, xfree); job_cmd(cmd); cleanup_until(cmd); } /* * We fork only if we are timed, or are not the end of a parenthesized * list and not a simple builtin function. Simple meaning one that is * not pipedout, niced, nohupped, or &'d. It would be nice(?) to not * fork in some of these cases. */ #ifdef BACKPIPE /* * Can't have NOFORK for the tail of a pipe - because it is not the * last command spawned (even if it is at the end of a parenthesised * list). */ if (t->t_dflg & F_PIPEIN) t->t_dflg &= ~(F_NOFORK); #else /* * "command | builtin" may cause major misbehaviour as noted in * in the BUGS file entry * Subject: Redirected input to built-in functions misbehaves badly * forking when the builtin is the end of the pipe corrects the * problem. */ if (bifunc && (t->t_dflg & F_PIPEIN)) t->t_dflg &= ~(F_NOFORK); #endif /* BACKPIPE */ /* * Prevent forking cd, pushd, popd, chdir cause this will cause the * shell not to change dir! (XXX: but only for nice?) */ if (bifunc && (bifunc->bfunct == (bfunc_t)dochngd || bifunc->bfunct == (bfunc_t)dopushd || bifunc->bfunct == (bfunc_t)dopopd)) t->t_dflg &= ~(F_NICE); if (((t->t_dflg & F_TIME) || ((t->t_dflg & F_NOFORK) == 0 && (!bifunc || t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NICE | F_NOHUP | F_HUP)))) || /* * We have to fork for eval too. */ (bifunc && (t->t_dflg & F_PIPEIN) != 0 && bifunc->bfunct == (bfunc_t)doeval)) { #ifdef VFORK if (t->t_dtyp == NODE_PAREN || t->t_dflg & (F_REPEAT | F_AMPERSAND) || bifunc) #endif /* VFORK */ { forked++; /* * We need to block SIGCHLD here, so that if the process does * not die before we can set the process group */ if (wanttty >= 0 && !nosigchld) { sigemptyset(&set); sigaddset(&set, SIGCHLD); (void)sigprocmask(SIG_BLOCK, &set, &csigset); nosigchld = 1; } pid = pfork(t, wanttty); if (pid == 0 && nosigchld) { sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } else if (pid != 0 && (t->t_dflg & F_AMPERSAND)) backpid = pid; } #ifdef VFORK else { int ochild, osetintr, ohaderr, odidfds; int oSHIN, oSHOUT, oSHDIAG, oOLDSTD, otpgrp; int oisoutatty, oisdiagatty; sigset_t oset, ocsigset; # ifndef CLOSE_ON_EXEC int odidcch; # endif /* !CLOSE_ON_EXEC */ /* * Prepare for the vfork by saving everything that the child * corrupts before it exec's. Note that in some signal * implementations which keep the signal info in user space * (e.g. Sun's) it will also be necessary to save and restore * the current sigvec's for the signals the child touches * before it exec's. */ /* * Sooooo true... If this is a Sun, save the sigvec's. (Skip * Gilbrech - 11/22/87) */ # ifdef SAVESIGVEC struct sigaction savesv[NSIGSAVED]; sigset_t savesm; # endif /* SAVESIGVEC */ if (wanttty >= 0 && !nosigchld && !noexec) { sigemptyset(&set); sigaddset(&set, SIGCHLD); (void)sigprocmask(SIG_BLOCK, &set, &csigset); nosigchld = 1; } sigemptyset(&set); sigaddset(&set, SIGCHLD); sigaddset(&set, SIGINT); (void)sigprocmask(SIG_BLOCK, &set, &oset); ochild = child; osetintr = setintr; ohaderr = haderr; odidfds = didfds; # ifndef CLOSE_ON_EXEC odidcch = didcch; # endif /* !CLOSE_ON_EXEC */ oSHIN = SHIN; oSHOUT = SHOUT; oSHDIAG = SHDIAG; oOLDSTD = OLDSTD; otpgrp = tpgrp; oisoutatty = isoutatty; oisdiagatty = isdiagatty; ocsigset = csigset; onosigchld = nosigchld; Vsav = Vdp = 0; Vexpath = 0; Vt = 0; # ifdef SAVESIGVEC savesigvec(savesv, savesm); # endif /* SAVESIGVEC */ if (use_fork) pid = fork(); else pid = vfork(); if (pid < 0) { # ifdef SAVESIGVEC restoresigvec(savesv, savesm); # endif /* SAVESIGVEC */ sigprocmask(SIG_SETMASK, &oset, NULL); stderror(ERR_NOPROC); } forked++; if (pid) { /* parent */ # ifdef SAVESIGVEC restoresigvec(savesv, savesm); # endif /* SAVESIGVEC */ child = ochild; setintr = osetintr; haderr = ohaderr; didfds = odidfds; SHIN = oSHIN; # ifndef CLOSE_ON_EXEC didcch = odidcch; # endif /* !CLOSE_ON_EXEC */ SHOUT = oSHOUT; SHDIAG = oSHDIAG; OLDSTD = oOLDSTD; tpgrp = otpgrp; isoutatty = oisoutatty; isdiagatty = oisdiagatty; csigset = ocsigset; nosigchld = onosigchld; xfree(Vsav); Vsav = 0; xfree(Vdp); Vdp = 0; xfree(Vexpath); Vexpath = 0; blk_cleanup(Vt); Vt = 0; /* this is from pfork() */ palloc(pid, t); sigprocmask(SIG_SETMASK, &oset, NULL); } else { /* child */ /* this is from pfork() */ pid_t pgrp; int ignint = 0; if (nosigchld) { sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } if (setintr) ignint = (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) || (gointr && eq(gointr, STRminus)); pgrp = pcurrjob ? pcurrjob->p_jobid : getpid(); child++; if (setintr) { setintr = 0; /* * casts made right for SunOS 4.0 by Douglas C. Schmidt * <*****@*****.**> * (thanks! -- PWP) * * ignint ifs cleaned by Johan Widen <[email protected]> * (thanks again) */ if (ignint) { (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); } else { (void) signal(SIGINT, vffree); (void) signal(SIGQUIT, SIG_DFL); } # ifdef BSDJOBS if (wanttty >= 0) { (void) signal(SIGTSTP, SIG_DFL); (void) signal(SIGTTIN, SIG_DFL); (void) signal(SIGTTOU, SIG_DFL); } # endif /* BSDJOBS */ sigaction(SIGTERM, &parterm, NULL); } else if (tpgrp == -1 && (t->t_dflg & F_NOINTERRUPT)) { (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); } pgetty(wanttty, pgrp); if (t->t_dflg & F_NOHUP) (void) signal(SIGHUP, SIG_IGN); if (t->t_dflg & F_HUP) (void) signal(SIGHUP, SIG_DFL); if (t->t_dflg & F_NICE) { int nval = SIGN_EXTEND_CHAR(t->t_nice); # if defined(HAVE_SETPRIORITY) && defined(PRIO_PROCESS) if (setpriority(PRIO_PROCESS, 0, nval) == -1 && errno) stderror(ERR_SYSTEM, "setpriority", strerror(errno)); # else /* !HAVE_SETPRIORITY || !PRIO_PROCESS */ (void) nice(nval); # endif /* HAVE_SETPRIORITY && PRIO_PROCESS */ } # ifdef F_VER if (t->t_dflg & F_VER) { tsetenv(STRSYSTYPE, t->t_systype ? STRbsd43 : STRsys53); dohash(NULL, NULL); } # endif /* F_VER */ } } #endif /* VFORK */ } if (pid != 0) { /* * It would be better if we could wait for the whole job when we * knew the last process had been started. Pwait, in fact, does * wait for the whole job anyway, but this test doesn't really * express our intentions. */ #ifdef BACKPIPE if (didfds == 0 && t->t_dflg & F_PIPEOUT) { xclose(pipeout[0]); xclose(pipeout[1]); } if ((t->t_dflg & F_PIPEIN) != 0) break; #else /* !BACKPIPE */ if (didfds == 0 && t->t_dflg & F_PIPEIN) { xclose(pipein[0]); xclose(pipein[1]); } if ((t->t_dflg & F_PIPEOUT) != 0) break; #endif /* BACKPIPE */ if (nosigchld) { sigprocmask(SIG_SETMASK, &csigset, NULL); nosigchld = 0; } if ((t->t_dflg & F_AMPERSAND) == 0) pwait(); break; } doio(t, pipein, pipeout); #ifdef BACKPIPE if (t->t_dflg & F_PIPEIN) { xclose(pipein[0]); xclose(pipein[1]); } #else /* !BACKPIPE */ if (t->t_dflg & F_PIPEOUT) { xclose(pipeout[0]); xclose(pipeout[1]); } #endif /* BACKPIPE */ /* * Perform a builtin function. If we are not forked, arrange for * possible stopping */ if (bifunc) { if (forked) { func(t, bifunc); exitstat(); } else { jmp_buf_t oldexit; int ohaderr = haderr; getexit(oldexit); if (setexit() == 0) func(t, bifunc); resexit(oldexit); haderr = ohaderr; if (adrof(STRprintexitvalue)) { int rv = getn(varval(STRstatus)); if (rv != 0) xprintf(CGETS(17, 2, "Exit %d\n"), rv); } } break; } if (t->t_dtyp != NODE_PAREN) { doexec(t, do_glob); /* NOTREACHED */ } /* * For () commands must put new 0,1,2 in FSH* and recurse */ if ((OLDSTD = dcopy(0, FOLDSTD)) >= 0) (void)close_on_exec(OLDSTD, 1); if ((SHOUT = dcopy(1, FSHOUT)) >= 0) { (void)close_on_exec(SHOUT, 1); isoutatty = isatty(SHOUT); } if ((SHDIAG = dcopy(2, FSHDIAG)) >= 0) { (void)close_on_exec(SHDIAG, 1); isdiagatty = isatty(SHDIAG); } xclose(SHIN); SHIN = -1; #ifndef CLOSE_ON_EXEC didcch = 0; #else (void) close_on_exec(FSHOUT, 1); (void) close_on_exec(FSHDIAG, 1); (void) close_on_exec(FOLDSTD, 1); #endif /* !CLOSE_ON_EXEC */ didfds = 0; wanttty = -1; t->t_dspr->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); execute(t->t_dspr, wanttty, NULL, NULL, do_glob); exitstat(); case NODE_PIPE: #ifdef BACKPIPE t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcdr, wanttty, pv, pipeout, do_glob); t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcar, wanttty, pipein, pv, do_glob); #else /* !BACKPIPE */ t->t_dcar->t_dflg |= F_PIPEOUT | (t->t_dflg & (F_PIPEIN | F_AMPERSAND | F_STDERR | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcar, wanttty, pipein, pv, do_glob); t->t_dcdr->t_dflg |= F_PIPEIN | (t->t_dflg & (F_PIPEOUT | F_AMPERSAND | F_NOFORK | F_NOINTERRUPT | F_BACKQ)); execute(t->t_dcdr, wanttty, pv, pipeout, do_glob); #endif /* BACKPIPE */ break; case NODE_LIST: if (t->t_dcar) { t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); execute(t->t_dcar, wanttty, NULL, NULL, do_glob); /* * In strange case of A&B make a new job after A */ if (t->t_dcar->t_dflg & F_AMPERSAND && t->t_dcdr && (t->t_dcdr->t_dflg & F_AMPERSAND) == 0) pendjob(); } if (t->t_dcdr) { t->t_dcdr->t_dflg |= t->t_dflg & (F_NOFORK | F_NOINTERRUPT | F_BACKQ); execute(t->t_dcdr, wanttty, NULL, NULL, do_glob); } break; case NODE_OR: case NODE_AND: if (t->t_dcar) { t->t_dcar->t_dflg |= t->t_dflg & (F_NOINTERRUPT | F_BACKQ); execute(t->t_dcar, wanttty, NULL, NULL, do_glob); if ((getn(varval(STRstatus)) == 0) != (t->t_dtyp == NODE_AND)) { return; } } if (t->t_dcdr) { t->t_dcdr->t_dflg |= t->t_dflg & (F_NOFORK | F_NOINTERRUPT | F_BACKQ); execute(t->t_dcdr, wanttty, NULL, NULL, do_glob); } break; default: break; } /* * Fall through for all breaks from switch * * If there will be no more executions of this command, flush all file * descriptors. Places that turn on the F_REPEAT bit are responsible for * doing donefds after the last re-execution */ if (didfds && !(t->t_dflg & F_REPEAT)) donefds(); }
/* * dinit - initialize current working directory */ void dinit(Char *hp) { Char *cp, *tcp; struct directory *dp; /* Don't believe the login shell home, because it may be a symlink */ tcp = agetcwd(); if (tcp == NULL) { xprintf("%s: %s\n", progname, strerror(errno)); if (hp && *hp) { char *xcp = short2str(hp); dstart(xcp); if (chdir(xcp) == -1) cp = NULL; else cp = Strsave(hp); } else cp = NULL; if (cp == NULL) { dstart("/"); if (chdir("/") == -1) /* I am not even try to print an error message! */ xexit(1); cp = SAVE("/"); } } else { #ifdef S_IFLNK struct stat swd, shp; int swd_ok; swd_ok = stat(short2str(tcp), &swd) == 0; /* * See if $HOME is the working directory we got and use that */ if (swd_ok && hp && *hp && stat(short2str(hp), &shp) != -1 && DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) && swd.st_ino == shp.st_ino) cp = Strsave(hp); else { char *cwd; /* * use PWD if we have it (for subshells) */ if (swd_ok && (cwd = getenv("PWD")) != NULL) { if (stat(cwd, &shp) != -1 && DEV_DEV_COMPARE(swd.st_dev, shp.st_dev) && swd.st_ino == shp.st_ino) { tcp = SAVE(cwd); cleanup_push(tcp, xfree); } } cleanup_push(tcp, xfree); cp = dcanon(tcp, STRNULL); cleanup_ignore(tcp); cleanup_until(tcp); } #else /* S_IFLNK */ cleanup_push(tcp, xfree); cp = dcanon(tcp, STRNULL); cleanup_ignore(tcp); cleanup_until(tcp); #endif /* S_IFLNK */ } dp = xcalloc(sizeof(struct directory), 1); dp->di_name = cp; dp->di_count = 0; dhead.di_next = dhead.di_prev = dp; dp->di_next = dp->di_prev = &dhead; printd = 0; dnewcwd(dp, 0); setcopy(STRdirstack, dp->di_name, VAR_READWRITE|VAR_NOGLOB); }
/* * dcanon - canonicalize the pathname, removing excess ./ and ../ etc. * we are of course assuming that the file system is standardly * constructed (always have ..'s, directories have links) */ Char * dcanon(Char *cp, Char *p) { Char *sp; Char *p1, *p2; /* general purpose */ int slash; #ifdef HAVE_SLASHSLASH int slashslash; #endif /* HAVE_SLASHSLASH */ size_t clen; #ifdef S_IFLNK /* if we have symlinks */ Char *mlink, *newcp; char *tlink; size_t cc; #endif /* S_IFLNK */ clen = Strlen(cp); /* * christos: if the path given does not start with a slash prepend cwd. If * cwd does not start with a slash or the result would be too long try to * correct it. */ if (!ABSOLUTEP(cp)) { Char *tmpdir; size_t len; p1 = varval(STRcwd); if (p1 == STRNULL || !ABSOLUTEP(p1)) { Char *new_cwd = agetcwd(); if (new_cwd == NULL) { xprintf("%s: %s\n", progname, strerror(errno)); setcopy(STRcwd, str2short("/"), VAR_READWRITE|VAR_NOGLOB); } else setv(STRcwd, new_cwd, VAR_READWRITE|VAR_NOGLOB); p1 = varval(STRcwd); } len = Strlen(p1); tmpdir = xmalloc((len + clen + 2) * sizeof (*tmpdir)); (void) Strcpy(tmpdir, p1); (void) Strcat(tmpdir, STRslash); (void) Strcat(tmpdir, cp); xfree(cp); cp = p = tmpdir; } #ifdef HAVE_SLASHSLASH slashslash = (cp[0] == '/' && cp[1] == '/'); #endif /* HAVE_SLASHSLASH */ while (*p) { /* for each component */ sp = p; /* save slash address */ while (*++p == '/') /* flush extra slashes */ continue; if (p != ++sp) for (p1 = sp, p2 = p; (*p1++ = *p2++) != '\0';) continue; p = sp; /* save start of component */ slash = 0; if (*p) while (*++p) /* find next slash or end of path */ if (*p == '/') { slash = 1; *p = 0; break; } #ifdef HAVE_SLASHSLASH if (&cp[1] == sp && sp[0] == '.' && sp[1] == '.' && sp[2] == '\0') slashslash = 1; #endif /* HAVE_SLASHSLASH */ if (*sp == '\0') { /* if component is null */ if (--sp == cp) /* if path is one char (i.e. /) */ break; else *sp = '\0'; } else if (sp[0] == '.' && sp[1] == 0) { if (slash) { for (p1 = sp, p2 = p + 1; (*p1++ = *p2++) != '\0';) continue; p = --sp; } else if (--sp != cp) *sp = '\0'; else sp[1] = '\0'; } else if (sp[0] == '.' && sp[1] == '.' && sp[2] == 0) { /* * We have something like "yyy/xxx/..", where "yyy" can be null or * a path starting at /, and "xxx" is a single component. Before * compressing "xxx/..", we want to expand "yyy/xxx", if it is a * symbolic link. */ *--sp = 0; /* form the pathname for readlink */ #ifdef S_IFLNK /* if we have symlinks */ if (sp != cp && /* symlinks != SYM_IGNORE && */ (tlink = areadlink(short2str(cp))) != NULL) { mlink = str2short(tlink); xfree(tlink); if (slash) *p = '/'; /* * Point p to the '/' in "/..", and restore the '/'. */ *(p = sp) = '/'; if (*mlink != '/') { /* * Relative path, expand it between the "yyy/" and the * "/..". First, back sp up to the character past "yyy/". */ while (*--sp != '/') continue; sp++; *sp = 0; /* * New length is "yyy/" + mlink + "/.." and rest */ p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) + Strlen(p) + 1) * sizeof(Char)); /* * Copy new path into newcp */ for (p2 = cp; (*p1++ = *p2++) != '\0';) continue; for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';) continue; for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) continue; /* * Restart canonicalization at expanded "/xxx". */ p = sp - cp - 1 + newcp; } else { newcp = Strspl(mlink, p); /* * Restart canonicalization at beginning */ p = newcp; } xfree(cp); cp = newcp; #ifdef HAVE_SLASHSLASH slashslash = (cp[0] == '/' && cp[1] == '/'); #endif /* HAVE_SLASHSLASH */ continue; /* canonicalize the link */ } #endif /* S_IFLNK */ *sp = '/'; if (sp != cp) while (*--sp != '/') continue; if (slash) { for (p1 = sp + 1, p2 = p + 1; (*p1++ = *p2++) != '\0';) continue; p = sp; } else if (cp == sp) *++sp = '\0'; else *sp = '\0'; } else { /* normal dir name (not . or .. or nothing) */ #ifdef S_IFLNK /* if we have symlinks */ if (sp != cp && symlinks == SYM_CHASE && (tlink = areadlink(short2str(cp))) != NULL) { mlink = str2short(tlink); xfree(tlink); /* * restore the '/'. */ if (slash) *p = '/'; /* * point sp to p (rather than backing up). */ sp = p; if (*mlink != '/') { /* * Relative path, expand it between the "yyy/" and the * remainder. First, back sp up to the character past * "yyy/". */ while (*--sp != '/') continue; sp++; *sp = 0; /* * New length is "yyy/" + mlink + "/.." and rest */ p1 = newcp = xmalloc(((sp - cp) + Strlen(mlink) + Strlen(p) + 1) * sizeof(Char)); /* * Copy new path into newcp */ for (p2 = cp; (*p1++ = *p2++) != '\0';) continue; for (p1--, p2 = mlink; (*p1++ = *p2++) != '\0';) continue; for (p1--, p2 = p; (*p1++ = *p2++) != '\0';) continue; /* * Restart canonicalization at expanded "/xxx". */ p = sp - cp - 1 + newcp; } else { newcp = Strspl(mlink, p); /* * Restart canonicalization at beginning */ p = newcp; } xfree(cp); cp = newcp; #ifdef HAVE_SLASHSLASH slashslash = (cp[0] == '/' && cp[1] == '/'); #endif /* HAVE_SLASHSLASH */ continue; /* canonicalize the mlink */ } #endif /* S_IFLNK */ if (slash) *p = '/'; } } /* * fix home... */ #ifdef S_IFLNK p1 = varval(STRhome); cc = Strlen(p1); /* * See if we're not in a subdir of STRhome */ if (p1 && *p1 == '/' && (Strncmp(p1, cp, cc) != 0 || (cp[cc] != '/' && cp[cc] != '\0'))) { static ino_t home_ino = (ino_t) -1; static dev_t home_dev = (dev_t) -1; static Char *home_ptr = NULL; struct stat statbuf; int found; Char *copy; /* * Get dev and ino of STRhome */ if (home_ptr != p1 && stat(short2str(p1), &statbuf) != -1) { home_dev = statbuf.st_dev; home_ino = statbuf.st_ino; home_ptr = p1; } /* * Start comparing dev & ino backwards */ p2 = copy = Strsave(cp); found = 0; while (*p2 && stat(short2str(p2), &statbuf) != -1) { if (DEV_DEV_COMPARE(statbuf.st_dev, home_dev) && statbuf.st_ino == home_ino) { found = 1; break; } if ((sp = Strrchr(p2, '/')) != NULL) *sp = '\0'; } /* * See if we found it */ if (*p2 && found) { /* * Use STRhome to make '~' work */ newcp = Strspl(p1, cp + Strlen(p2)); xfree(cp); cp = newcp; } xfree(copy); } #endif /* S_IFLNK */ #ifdef HAVE_SLASHSLASH if (slashslash) { if (cp[1] != '/') { p = xmalloc((Strlen(cp) + 2) * sizeof(Char)); *p = '/'; (void) Strcpy(&p[1], cp); xfree(cp); cp = p; } } if (cp[1] == '/' && cp[2] == '/') { for (p1 = &cp[1], p2 = &cp[2]; (*p1++ = *p2++) != '\0';) continue; } #endif /* HAVE_SLASHSLASH */ return cp; }