tc.func.c revision 195609
1195609Smp/* $Header: /p/tcsh/cvsroot/tcsh/tc.func.c,v 3.139 2009/06/25 21:15:38 christos Exp $ */ 259243Sobrien/* 359243Sobrien * tc.func.c: New tcsh builtins. 459243Sobrien */ 559243Sobrien/*- 659243Sobrien * Copyright (c) 1980, 1991 The Regents of the University of California. 759243Sobrien * All rights reserved. 859243Sobrien * 959243Sobrien * Redistribution and use in source and binary forms, with or without 1059243Sobrien * modification, are permitted provided that the following conditions 1159243Sobrien * are met: 1259243Sobrien * 1. Redistributions of source code must retain the above copyright 1359243Sobrien * notice, this list of conditions and the following disclaimer. 1459243Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1559243Sobrien * notice, this list of conditions and the following disclaimer in the 1659243Sobrien * documentation and/or other materials provided with the distribution. 17100616Smp * 3. Neither the name of the University nor the names of its contributors 1859243Sobrien * may be used to endorse or promote products derived from this software 1959243Sobrien * without specific prior written permission. 2059243Sobrien * 2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2459243Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3159243Sobrien * SUCH DAMAGE. 3259243Sobrien */ 3359243Sobrien#include "sh.h" 3459243Sobrien 35195609SmpRCSID("$tcsh: tc.func.c,v 3.139 2009/06/25 21:15:38 christos Exp $") 3659243Sobrien 3759243Sobrien#include "ed.h" 3859243Sobrien#include "ed.defns.h" /* for the function names */ 3959243Sobrien#include "tw.h" 4059243Sobrien#include "tc.h" 4169408Sache#ifdef WINNT_NATIVE 4259243Sobrien#include "nt.const.h" 43167465Smp#else /* WINNT_NATIVE */ 44167465Smp#include <sys/wait.h> 4569408Sache#endif /* WINNT_NATIVE */ 4659243Sobrien 4759243Sobrien#ifdef AFS 4859243Sobrien#include <afs/stds.h> 4959243Sobrien#include <afs/kautils.h> 5059243Sobrienlong ka_UserAuthenticateGeneral(); 5159243Sobrien#endif /* AFS */ 5259243Sobrien 5359243Sobrien#ifdef TESLA 5459243Sobrienextern int do_logout; 5559243Sobrien#endif /* TESLA */ 5659243Sobrienextern time_t t_period; 5759243Sobrienextern int just_signaled; 58145479Smpstatic int precmd_active = 0; 59145479Smpstatic int jobcmd_active = 0; /* GrP */ 60145479Smpstatic int postcmd_active = 0; 61145479Smpstatic int periodic_active = 0; 62145479Smpstatic int cwdcmd_active = 0; /* PWP: for cwd_cmd */ 63145479Smpstatic int beepcmd_active = 0; 64167465Smpstatic void (*alm_fun)(void) = NULL; 6559243Sobrien 66167465Smpstatic void auto_logout (void); 67167465Smpstatic char *xgetpass (const char *); 68167465Smpstatic void auto_lock (void); 6959243Sobrien#ifdef BSDJOBS 70167465Smpstatic void insert (struct wordent *, int); 71167465Smpstatic void insert_we (struct wordent *, struct wordent *); 72167465Smpstatic int inlist (Char *, Char *); 7359243Sobrien#endif /* BSDJOBS */ 74167465Smpstatic int tildecompare (const void *, const void *); 75167465Smpstatic Char *gethomedir (const Char *); 7659243Sobrien#ifdef REMOTEHOST 77167465Smpstatic void palarm (int); 78167465Smpstatic void getremotehost (int); 7959243Sobrien#endif /* REMOTEHOST */ 8059243Sobrien 8159243Sobrien/* 8259243Sobrien * Tops-C shell 8359243Sobrien */ 8459243Sobrien 8559243Sobrien/* 86167465Smp * expand_lex: Take the given lex and return an expanded version of it. 87167465Smp * First guy in lex list is ignored; last guy is ^J which we ignore. 88167465Smp * Only take lex'es from position 'from' to position 'to' inclusive 8961524Sobrien * 9061524Sobrien * Note: csh sometimes sets bit 8 in characters which causes all kinds 9161524Sobrien * of problems if we don't mask it here. Note: excl's in lexes have been 9261524Sobrien * un-back-slashed and must be re-back-slashed 9361524Sobrien * 9459243Sobrien */ 9559243Sobrien/* PWP: this is a combination of the old sprlex() and the expand_lex from 9659243Sobrien the magic-space stuff */ 9759243Sobrien 9859243SobrienChar * 99167465Smpexpand_lex(const struct wordent *sp0, int from, int to) 10059243Sobrien{ 101167465Smp struct Strbuf buf = Strbuf_INIT; 102167465Smp const struct wordent *sp; 103167465Smp Char *s; 104145479Smp Char prev_c; 105145479Smp int i; 10659243Sobrien 10759243Sobrien prev_c = '\0'; 10859243Sobrien 109167465Smp if (!sp0 || (sp = sp0->next) == sp0 || sp == (sp0 = sp0->prev)) 110167465Smp return Strbuf_finish(&buf); /* null lex */ 11159243Sobrien 112167465Smp for (i = 0; ; i++) { 11359243Sobrien if ((i >= from) && (i <= to)) { /* if in range */ 114167465Smp for (s = sp->word; *s; s++) { 11559243Sobrien /* 11659243Sobrien * bugfix by Michael Bloom: anything but the current history 11759243Sobrien * character {(PWP) and backslash} seem to be dealt with 11859243Sobrien * elsewhere. 11959243Sobrien */ 12059243Sobrien if ((*s & QUOTE) 12159243Sobrien && (((*s & TRIM) == HIST) || 12259243Sobrien (((*s & TRIM) == '\'') && (prev_c != '\\')) || 12359243Sobrien (((*s & TRIM) == '\"') && (prev_c != '\\')) || 12459243Sobrien (((*s & TRIM) == '\\') && (prev_c != '\\')))) { 125167465Smp Strbuf_append1(&buf, '\\'); 12659243Sobrien } 127167465Smp Strbuf_append1(&buf, *s & TRIM); 12859243Sobrien prev_c = *s; 12959243Sobrien } 130167465Smp Strbuf_append1(&buf, ' '); 13159243Sobrien } 13259243Sobrien sp = sp->next; 13359243Sobrien if (sp == sp0) 13459243Sobrien break; 13559243Sobrien } 136167465Smp if (buf.len != 0) 137167465Smp buf.len--; /* get rid of trailing space */ 13859243Sobrien 139167465Smp return Strbuf_finish(&buf); 14059243Sobrien} 14159243Sobrien 14259243SobrienChar * 143167465Smpsprlex(const struct wordent *sp0) 14459243Sobrien{ 145167465Smp return expand_lex(sp0, 0, INT_MAX); 14659243Sobrien} 14759243Sobrien 14859243Sobrien 14959243SobrienChar * 150167465SmpItoa(int n, size_t min_digits, Char attributes) 15159243Sobrien{ 15259243Sobrien /* 15359243Sobrien * The array size here is derived from 15459243Sobrien * log8(UINT_MAX) 15559243Sobrien * which is guaranteed to be enough for a decimal 15659243Sobrien * representation. We add 1 because integer divide 15759243Sobrien * rounds down. 15859243Sobrien */ 15959243Sobrien#ifndef CHAR_BIT 16059243Sobrien# define CHAR_BIT 8 16159243Sobrien#endif 162167465Smp Char buf[CHAR_BIT * sizeof(int) / 3 + 1], *res, *p, *s; 16359243Sobrien unsigned int un; /* handle most negative # too */ 16459243Sobrien int pad = (min_digits != 0); 16559243Sobrien 166167465Smp if (sizeof(buf) - 1 < min_digits) 16759243Sobrien min_digits = sizeof(buf) - 1; 16859243Sobrien 16959243Sobrien un = n; 170167465Smp if (n < 0) 17159243Sobrien un = -n; 17259243Sobrien 17359243Sobrien p = buf; 17459243Sobrien do { 17559243Sobrien *p++ = un % 10 + '0'; 17659243Sobrien un /= 10; 17759243Sobrien } while ((pad && --min_digits > 0) || un != 0); 17859243Sobrien 179167465Smp res = xmalloc((p - buf + 2) * sizeof(*res)); 180167465Smp s = res; 181167465Smp if (n < 0) 182167465Smp *s++ = '-'; 18359243Sobrien while (p > buf) 18459243Sobrien *s++ = *--p | attributes; 18559243Sobrien 18659243Sobrien *s = '\0'; 187167465Smp return res; 18859243Sobrien} 18959243Sobrien 19059243Sobrien 19159243Sobrien/*ARGSUSED*/ 19259243Sobrienvoid 193167465Smpdolist(Char **v, struct command *c) 19459243Sobrien{ 195167465Smp Char **globbed; 19659243Sobrien int i, k; 19759243Sobrien struct stat st; 19859243Sobrien 19959243Sobrien USE(c); 20059243Sobrien if (*++v == NULL) { 201167465Smp struct Strbuf word = Strbuf_INIT; 202167465Smp 203167465Smp Strbuf_terminate(&word); 204167465Smp cleanup_push(&word, Strbuf_cleanup); 205167465Smp (void) t_search(&word, LIST, TW_ZERO, 0, STRNULL, 0); 206167465Smp cleanup_until(&word); 20759243Sobrien return; 20859243Sobrien } 209167465Smp v = glob_all_or_error(v); 210167465Smp globbed = v; 211167465Smp cleanup_push(globbed, blk_cleanup); 21259243Sobrien for (k = 0; v[k] != NULL && v[k][0] != '-'; k++) 21359243Sobrien continue; 21459243Sobrien if (v[k]) { 21559243Sobrien /* 21659243Sobrien * We cannot process a flag therefore we let ls do it right. 21759243Sobrien */ 21859243Sobrien Char *lspath; 21959243Sobrien struct command *t; 22059243Sobrien struct wordent cmd, *nextword, *lastword; 22159243Sobrien Char *cp; 22259243Sobrien struct varent *vp; 22359243Sobrien 224167465Smp if (setintr) { 225167465Smp pintr_disabled++; 226167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 227167465Smp } 22859243Sobrien if (seterr) { 229167465Smp xfree(seterr); 23059243Sobrien seterr = NULL; 23159243Sobrien } 23259243Sobrien 23359243Sobrien lspath = STRls; 23459243Sobrien STRmCF[1] = 'C'; 23559243Sobrien STRmCF[3] = '\0'; 23659243Sobrien /* Look at listflags, to add -A to the flags, to get a path 23759243Sobrien of ls if necessary */ 238100616Smp if ((vp = adrof(STRlistflags)) != NULL && vp->vec != NULL && 239100616Smp vp->vec[0] != STRNULL) { 24059243Sobrien if (vp->vec[1] != NULL && vp->vec[1][0] != '\0') 24159243Sobrien lspath = vp->vec[1]; 24259243Sobrien for (cp = vp->vec[0]; *cp; cp++) 24359243Sobrien switch (*cp) { 24459243Sobrien case 'x': 24559243Sobrien STRmCF[1] = 'x'; 24659243Sobrien break; 24759243Sobrien case 'a': 24859243Sobrien STRmCF[3] = 'a'; 24959243Sobrien break; 25059243Sobrien case 'A': 25159243Sobrien STRmCF[3] = 'A'; 25259243Sobrien break; 25359243Sobrien default: 25459243Sobrien break; 25559243Sobrien } 25659243Sobrien } 25759243Sobrien 25859243Sobrien cmd.word = STRNULL; 25959243Sobrien lastword = &cmd; 260167465Smp nextword = xcalloc(1, sizeof cmd); 26159243Sobrien nextword->word = Strsave(lspath); 26259243Sobrien lastword->next = nextword; 26359243Sobrien nextword->prev = lastword; 26459243Sobrien lastword = nextword; 265167465Smp nextword = xcalloc(1, sizeof cmd); 26659243Sobrien nextword->word = Strsave(STRmCF); 26759243Sobrien lastword->next = nextword; 26859243Sobrien nextword->prev = lastword; 26959243Sobrien#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 27059243Sobrien if (dspmbyte_ls) { 27159243Sobrien lastword = nextword; 272167465Smp nextword = xcalloc(1, sizeof cmd); 27359243Sobrien nextword->word = Strsave(STRmmliteral); 27459243Sobrien lastword->next = nextword; 27559243Sobrien nextword->prev = lastword; 27659243Sobrien } 27759243Sobrien#endif 27859243Sobrien#ifdef COLOR_LS_F 27959243Sobrien if (color_context_ls) { 28059243Sobrien lastword = nextword; 281167465Smp nextword = xcalloc(1, sizeof cmd); 28259243Sobrien nextword->word = Strsave(STRmmcolormauto); 28359243Sobrien lastword->next = nextword; 28459243Sobrien nextword->prev = lastword; 28559243Sobrien } 28659243Sobrien#endif /* COLOR_LS_F */ 28759243Sobrien lastword = nextword; 28859243Sobrien for (cp = *v; cp; cp = *++v) { 289167465Smp nextword = xcalloc(1, sizeof cmd); 290100616Smp nextword->word = quote(Strsave(cp)); 29159243Sobrien lastword->next = nextword; 29259243Sobrien nextword->prev = lastword; 29359243Sobrien lastword = nextword; 29459243Sobrien } 29559243Sobrien lastword->next = &cmd; 29659243Sobrien cmd.prev = lastword; 297167465Smp cleanup_push(&cmd, lex_cleanup); 29859243Sobrien 29959243Sobrien /* build a syntax tree for the command. */ 30059243Sobrien t = syntax(cmd.next, &cmd, 0); 301167465Smp cleanup_push(t, syntax_cleanup); 30259243Sobrien if (seterr) 30359243Sobrien stderror(ERR_OLD); 30459243Sobrien /* expand aliases like process() does */ 30559243Sobrien /* alias(&cmd); */ 30659243Sobrien /* execute the parse tree. */ 307100616Smp execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL, FALSE); 30859243Sobrien /* done. free the lex list and parse tree. */ 309167465Smp cleanup_until(&cmd); 31059243Sobrien if (setintr) 311167465Smp cleanup_until(&pintr_disabled); 31259243Sobrien } 31359243Sobrien else { 314167465Smp Char *dp, *tmp; 315167465Smp struct Strbuf buf = Strbuf_INIT; 31659243Sobrien 317167465Smp cleanup_push(&buf, Strbuf_cleanup); 31859243Sobrien for (k = 0, i = 0; v[k] != NULL; k++) { 31959243Sobrien tmp = dnormalize(v[k], symlinks == SYM_IGNORE); 320167465Smp cleanup_push(tmp, xfree); 321167465Smp dp = Strend(tmp) - 1; 32259243Sobrien if (*dp == '/' && dp != tmp) 32359243Sobrien#ifdef apollo 32459243Sobrien if (dp != &tmp[1]) 32559243Sobrien#endif /* apollo */ 32659243Sobrien *dp = '\0'; 327167465Smp if (stat(short2str(tmp), &st) == -1) { 328167465Smp int err; 329167465Smp 330167465Smp err = errno; 33159243Sobrien if (k != i) { 33259243Sobrien if (i != 0) 33359243Sobrien xputchar('\n'); 33459243Sobrien print_by_column(STRNULL, &v[i], k - i, FALSE); 33559243Sobrien } 336167465Smp xprintf("%S: %s.\n", tmp, strerror(err)); 33759243Sobrien i = k + 1; 33859243Sobrien } 33959243Sobrien else if (S_ISDIR(st.st_mode)) { 34059243Sobrien Char *cp; 34159243Sobrien 34259243Sobrien if (k != i) { 34359243Sobrien if (i != 0) 34459243Sobrien xputchar('\n'); 34559243Sobrien print_by_column(STRNULL, &v[i], k - i, FALSE); 34659243Sobrien } 34759243Sobrien if (k != 0 && v[1] != NULL) 34859243Sobrien xputchar('\n'); 34959243Sobrien xprintf("%S:\n", tmp); 350167465Smp buf.len = 0; 351167465Smp for (cp = tmp; *cp; cp++) 352167465Smp Strbuf_append1(&buf, (*cp | QUOTE)); 353167465Smp Strbuf_terminate(&buf); 354167465Smp dp = &buf.s[buf.len - 1]; 35559243Sobrien if ( 35669408Sache#ifdef WINNT_NATIVE 357167465Smp (*dp != (Char) (':' | QUOTE)) && 35869408Sache#endif /* WINNT_NATIVE */ 359167465Smp (*dp != (Char) ('/' | QUOTE))) { 360167465Smp Strbuf_append1(&buf, '/'); 361167465Smp Strbuf_terminate(&buf); 362167465Smp } else 363167465Smp *dp &= TRIM; 364167465Smp (void) t_search(&buf, LIST, TW_ZERO, 0, STRNULL, 0); 36559243Sobrien i = k + 1; 36659243Sobrien } 367167465Smp cleanup_until(tmp); 36859243Sobrien } 369167465Smp cleanup_until(&buf); 37059243Sobrien if (k != i) { 37159243Sobrien if (i != 0) 37259243Sobrien xputchar('\n'); 37359243Sobrien print_by_column(STRNULL, &v[i], k - i, FALSE); 37459243Sobrien } 37559243Sobrien } 37659243Sobrien 377167465Smp cleanup_until(globbed); 37859243Sobrien} 37959243Sobrien 380145479Smpextern int GotTermCaps; 38159243Sobrien 38259243Sobrien/*ARGSUSED*/ 38359243Sobrienvoid 384167465Smpdotelltc(Char **v, struct command *c) 38559243Sobrien{ 386145479Smp USE(v); 38759243Sobrien USE(c); 38859243Sobrien if (!GotTermCaps) 38959243Sobrien GetTermCaps(); 390145479Smp TellTC(); 39159243Sobrien} 39259243Sobrien 39359243Sobrien/*ARGSUSED*/ 39459243Sobrienvoid 395167465Smpdoechotc(Char **v, struct command *c) 39659243Sobrien{ 397145479Smp USE(c); 39859243Sobrien if (!GotTermCaps) 39959243Sobrien GetTermCaps(); 40059243Sobrien EchoTC(++v); 40159243Sobrien} 40259243Sobrien 40359243Sobrien/*ARGSUSED*/ 40459243Sobrienvoid 405167465Smpdosettc(Char **v, struct command *c) 40659243Sobrien{ 407167465Smp char *tv[2]; 40859243Sobrien 409145479Smp USE(c); 41059243Sobrien if (!GotTermCaps) 41159243Sobrien GetTermCaps(); 41259243Sobrien 413167465Smp tv[0] = strsave(short2str(v[1])); 414167465Smp cleanup_push(tv[0], xfree); 415167465Smp tv[1] = strsave(short2str(v[2])); 416167465Smp cleanup_push(tv[1], xfree); 41759243Sobrien SetTC(tv[0], tv[1]); 418167465Smp cleanup_until(tv[0]); 41959243Sobrien} 42059243Sobrien 42159243Sobrien/* The dowhich() is by: 42259243Sobrien * Andreas Luik <luik@isaak.isa.de> 42359243Sobrien * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 42459243Sobrien * Azenberstr. 35 42559243Sobrien * D-7000 Stuttgart 1 42659243Sobrien * West-Germany 42759243Sobrien * Thanks!! 42859243Sobrien */ 42959243Sobrienint 430167465Smpcmd_expand(Char *cmd, Char **str) 43159243Sobrien{ 43259243Sobrien struct wordent lexp[3]; 43359243Sobrien struct varent *vp; 43459243Sobrien int rv = TRUE; 43559243Sobrien 43659243Sobrien lexp[0].next = &lexp[1]; 43759243Sobrien lexp[1].next = &lexp[2]; 43859243Sobrien lexp[2].next = &lexp[0]; 43959243Sobrien 44059243Sobrien lexp[0].prev = &lexp[2]; 44159243Sobrien lexp[1].prev = &lexp[0]; 44259243Sobrien lexp[2].prev = &lexp[1]; 44359243Sobrien 44459243Sobrien lexp[0].word = STRNULL; 44559243Sobrien lexp[2].word = STRret; 44659243Sobrien 447100616Smp if ((vp = adrof1(cmd, &aliases)) != NULL && vp->vec != NULL) { 44859243Sobrien if (str == NULL) { 44959243Sobrien xprintf(CGETS(22, 1, "%S: \t aliased to "), cmd); 45059243Sobrien blkpr(vp->vec); 45159243Sobrien xputchar('\n'); 45259243Sobrien } 453167465Smp else 454167465Smp *str = blkexpand(vp->vec); 45559243Sobrien } 45659243Sobrien else { 45759243Sobrien lexp[1].word = cmd; 45859243Sobrien rv = tellmewhat(lexp, str); 45959243Sobrien } 46059243Sobrien return rv; 46159243Sobrien} 46259243Sobrien 46359243Sobrien 46459243Sobrien/*ARGSUSED*/ 46559243Sobrienvoid 466167465Smpdowhich(Char **v, struct command *c) 46759243Sobrien{ 46859243Sobrien int rv = TRUE; 46959243Sobrien USE(c); 47059243Sobrien 471167465Smp /* 47259243Sobrien * We don't want to glob dowhich args because we lose quoteing 47359243Sobrien * E.g. which \ls if ls is aliased will not work correctly if 47459243Sobrien * we glob here. 47559243Sobrien */ 47659243Sobrien 47759243Sobrien while (*++v) 47859243Sobrien rv &= cmd_expand(*v, NULL); 47959243Sobrien 48059243Sobrien if (!rv) 481167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 48259243Sobrien} 48359243Sobrien 48459243Sobrien/* PWP: a hack to start up your stopped editor on a single keystroke */ 48559243Sobrien/* jbs - fixed hack so it worked :-) 3/28/89 */ 48659243Sobrien 48759243Sobrienstruct process * 488167465Smpfind_stop_ed(void) 48959243Sobrien{ 490145479Smp struct process *pp, *retp; 491145479Smp const char *ep, *vp; 492145479Smp char *cp, *p; 493167465Smp size_t epl, vpl; 494167465Smp int pstatus; 49559243Sobrien 49659243Sobrien if ((ep = getenv("EDITOR")) != NULL) { /* if we have a value */ 49759243Sobrien if ((p = strrchr(ep, '/')) != NULL) /* if it has a path */ 49859243Sobrien ep = p + 1; /* then we want only the last part */ 49959243Sobrien } 50059243Sobrien else 50159243Sobrien ep = "ed"; 50259243Sobrien 50359243Sobrien if ((vp = getenv("VISUAL")) != NULL) { /* if we have a value */ 50459243Sobrien if ((p = strrchr(vp, '/')) != NULL) /* and it has a path */ 50559243Sobrien vp = p + 1; /* then we want only the last part */ 50659243Sobrien } 50759243Sobrien else 50859243Sobrien vp = "vi"; 50959243Sobrien 510145479Smp for (vpl = 0; vp[vpl] && !isspace((unsigned char)vp[vpl]); vpl++) 51159243Sobrien continue; 512145479Smp for (epl = 0; ep[epl] && !isspace((unsigned char)ep[epl]); epl++) 51359243Sobrien continue; 51459243Sobrien 51559243Sobrien if (pcurrent == NULL) /* see if we have any jobs */ 51659243Sobrien return NULL; /* nope */ 51759243Sobrien 51859243Sobrien retp = NULL; 51959243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 52059243Sobrien if (pp->p_procid == pp->p_jobid) { 52159243Sobrien 52259243Sobrien /* 52359243Sobrien * Only foreground an edit session if it is suspended. Some GUI 52459243Sobrien * editors have may be happily running in a separate window, no 52559243Sobrien * point in foregrounding these if they're already running - webb 52659243Sobrien */ 52759243Sobrien pstatus = (int) (pp->p_flags & PALLSTATES); 52859243Sobrien if (pstatus != PINTERRUPTED && pstatus != PSTOPPED && 52959243Sobrien pstatus != PSIGNALED) 53059243Sobrien continue; 53159243Sobrien 53259243Sobrien p = short2str(pp->p_command); 53359243Sobrien /* get the first word */ 53459243Sobrien for (cp = p; *cp && !isspace((unsigned char) *cp); cp++) 53559243Sobrien continue; 53659243Sobrien *cp = '\0'; 53759243Sobrien 53859243Sobrien if ((cp = strrchr(p, '/')) != NULL) /* and it has a path */ 53959243Sobrien cp = cp + 1; /* then we want only the last part */ 54059243Sobrien else 54159243Sobrien cp = p; /* else we get all of it */ 54259243Sobrien 54359243Sobrien /* if we find either in the current name, fg it */ 544167465Smp if (strncmp(ep, cp, epl) == 0 || 545167465Smp strncmp(vp, cp, vpl) == 0) { 54659243Sobrien 54759243Sobrien /* 54859243Sobrien * If there is a choice, then choose the current process if 54959243Sobrien * available, or the previous process otherwise, or else 55059243Sobrien * anything will do - Robert Webb (robertw@mulga.cs.mu.oz.au). 55159243Sobrien */ 55259243Sobrien if (pp == pcurrent) 55359243Sobrien return pp; 55459243Sobrien else if (retp == NULL || pp == pprevious) 55559243Sobrien retp = pp; 55659243Sobrien } 55759243Sobrien } 55859243Sobrien 55959243Sobrien return retp; /* Will be NULL if we didn't find a job */ 56059243Sobrien} 56159243Sobrien 56259243Sobrienvoid 563167465Smpfg_proc_entry(struct process *pp) 56459243Sobrien{ 56559243Sobrien jmp_buf_t osetexit; 566145479Smp int ohaderr; 56759243Sobrien Char oGettingInput; 568167465Smp size_t omark; 56959243Sobrien 57059243Sobrien getexit(osetexit); 57159243Sobrien 572167465Smp pintr_disabled++; 57359243Sobrien oGettingInput = GettingInput; 57459243Sobrien GettingInput = 0; 57559243Sobrien 57659243Sobrien ohaderr = haderr; /* we need to ignore setting of haderr due to 57759243Sobrien * process getting stopped by a signal */ 578167465Smp omark = cleanup_push_mark(); 57959243Sobrien if (setexit() == 0) { /* come back here after pjwait */ 58059243Sobrien pendjob(); 58159243Sobrien (void) alarm(0); /* No autologout */ 582167465Smp alrmcatch_disabled = 1; 58359243Sobrien if (!pstart(pp, 1)) { 58459243Sobrien pp->p_procid = 0; 58559243Sobrien stderror(ERR_BADJOB, pp->p_command, strerror(errno)); 58659243Sobrien } 58759243Sobrien pjwait(pp); 58859243Sobrien } 58959243Sobrien setalarm(1); /* Autologout back on */ 590167465Smp cleanup_pop_mark(omark); 59159243Sobrien resexit(osetexit); 59259243Sobrien haderr = ohaderr; 59359243Sobrien GettingInput = oGettingInput; 59459243Sobrien 595167465Smp disabled_cleanup(&pintr_disabled); 59659243Sobrien} 59759243Sobrien 59859243Sobrienstatic char * 599167465Smpxgetpass(const char *prm) 60059243Sobrien{ 601167465Smp static struct strbuf pass; /* = strbuf_INIT; */ 602167465Smp int fd; 603167465Smp sigset_t oset, set; 604167465Smp struct sigaction sa, osa; 60559243Sobrien 606167465Smp sa.sa_handler = SIG_IGN; 607167465Smp sigemptyset(&sa.sa_mask); 608167465Smp sa.sa_flags = 0; 609167465Smp (void)sigaction(SIGINT, &sa, &osa); 610167465Smp 611167465Smp sigemptyset(&set); 612167465Smp sigaddset(&set, SIGINT); 613167465Smp (void)sigprocmask(SIG_UNBLOCK, &set, &oset); 614167465Smp 615167465Smp cleanup_push(&osa, sigint_cleanup); 616167465Smp cleanup_push(&oset, sigprocmask_cleanup); 61759243Sobrien (void) Rawmode(); /* Make sure, cause we want echo off */ 618167465Smp fd = xopen("/dev/tty", O_RDWR|O_LARGEFILE); 619167465Smp if (fd == -1) 62059243Sobrien fd = SHIN; 621167465Smp else 622167465Smp cleanup_push(&fd, open_cleanup); 62359243Sobrien 62459243Sobrien xprintf("%s", prm); flush(); 625167465Smp pass.len = 0; 626167465Smp for (;;) { 627167465Smp char c; 628167465Smp 629167465Smp if (xread(fd, &c, 1) < 1 || c == '\n') 63059243Sobrien break; 631167465Smp strbuf_append1(&pass, c); 63259243Sobrien } 633167465Smp strbuf_terminate(&pass); 63459243Sobrien 635180637Skeramida cleanup_until(&osa); 63659243Sobrien 637167465Smp return pass.s; 63859243Sobrien} 639167465Smp 640145479Smp#ifndef NO_CRYPT 641167465Smp#if !HAVE_DECL_CRYPT 642167465Smp extern char *crypt (); 643145479Smp#endif 644167465Smp#ifdef HAVE_CRYPT_H 645145479Smp#include <crypt.h> 646145479Smp#endif 647145479Smp#endif 648145479Smp 64959243Sobrien/* 65059243Sobrien * Ask the user for his login password to continue working 65159243Sobrien * On systems that have a shadow password, this will only 65259243Sobrien * work for root, but what can we do? 65359243Sobrien * 65459243Sobrien * If we fail to get the password, then we log the user out 65559243Sobrien * immediately 65659243Sobrien */ 65759243Sobrien/*ARGSUSED*/ 65859243Sobrienstatic void 659167465Smpauto_lock(void) 66059243Sobrien{ 66159243Sobrien#ifndef NO_CRYPT 66259243Sobrien 66359243Sobrien int i; 66459243Sobrien char *srpp = NULL; 66559243Sobrien struct passwd *pw; 66659243Sobrien 66759243Sobrien#undef XCRYPT 66859243Sobrien 669167465Smp#if defined(HAVE_AUTH_H) && defined(HAVE_GETAUTHUID) 67059243Sobrien 67159243Sobrien struct authorization *apw; 672167465Smp extern char *crypt16 (const char *, const char *); 67359243Sobrien 67459243Sobrien# define XCRYPT(a, b) crypt16(a, b) 67559243Sobrien 676167465Smp if ((pw = xgetpwuid(euid)) != NULL && /* effective user passwd */ 67759243Sobrien (apw = getauthuid(euid)) != NULL) /* enhanced ultrix passwd */ 67859243Sobrien srpp = apw->a_password; 67959243Sobrien 680145479Smp#elif defined(HAVE_SHADOW_H) 68159243Sobrien 68259243Sobrien struct spwd *spw; 68359243Sobrien 68459243Sobrien# define XCRYPT(a, b) crypt(a, b) 68559243Sobrien 686167465Smp if ((pw = xgetpwuid(euid)) != NULL) { /* effective user passwd */ 687167465Smp errno = 0; 688167465Smp while ((spw = getspnam(pw->pw_name)) == NULL && errno == EINTR) { 689167465Smp handle_pending_signals(); 690167465Smp errno = 0; 691167465Smp } 692167465Smp if (spw != NULL) /* shadowed passwd */ 693167465Smp srpp = spw->sp_pwdp; 694167465Smp } 69559243Sobrien 696145479Smp#else 69759243Sobrien 69859243Sobrien#define XCRYPT(a, b) crypt(a, b) 69959243Sobrien 70069408Sache#if !defined(__MVS__) 701167465Smp if ((pw = xgetpwuid(euid)) != NULL) /* effective user passwd */ 70259243Sobrien srpp = pw->pw_passwd; 70369408Sache#endif /* !MVS */ 70459243Sobrien 705145479Smp#endif 70659243Sobrien 70759243Sobrien if (srpp == NULL) { 708167465Smp auto_logout(); 70959243Sobrien /*NOTREACHED*/ 71059243Sobrien return; 71159243Sobrien } 71259243Sobrien 71359243Sobrien setalarm(0); /* Not for locking any more */ 714167465Smp xputchar('\n'); 71559243Sobrien for (i = 0; i < 5; i++) { 71659243Sobrien const char *crpp; 71759243Sobrien char *pp; 71859243Sobrien#ifdef AFS 71959243Sobrien char *afsname; 72059243Sobrien Char *safs; 72159243Sobrien 72259243Sobrien if ((safs = varval(STRafsuser)) != STRNULL) 72359243Sobrien afsname = short2str(safs); 72459243Sobrien else 72559243Sobrien if ((afsname = getenv("AFSUSER")) == NULL) 72659243Sobrien afsname = pw->pw_name; 72759243Sobrien#endif 728167465Smp pp = xgetpass("Password:"); 72959243Sobrien 73059243Sobrien crpp = XCRYPT(pp, srpp); 73159243Sobrien if ((strcmp(crpp, srpp) == 0) 73259243Sobrien#ifdef AFS 73359243Sobrien || (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, 73459243Sobrien afsname, /* name */ 73559243Sobrien NULL, /* instance */ 73659243Sobrien NULL, /* realm */ 73759243Sobrien pp, /* password */ 73859243Sobrien 0, /* lifetime */ 73959243Sobrien 0, 0, /* spare */ 74059243Sobrien NULL) /* reason */ 74159243Sobrien == 0) 74259243Sobrien#endif /* AFS */ 74359243Sobrien ) { 744167465Smp (void) memset(pp, 0, strlen(pp)); 74559243Sobrien if (GettingInput && !just_signaled) { 74659243Sobrien (void) Rawmode(); 747167465Smp ClearLines(); 748167465Smp ClearDisp(); 74959243Sobrien Refresh(); 75059243Sobrien } 75159243Sobrien just_signaled = 0; 75259243Sobrien return; 75359243Sobrien } 75459243Sobrien xprintf(CGETS(22, 2, "\nIncorrect passwd for %s\n"), pw->pw_name); 75559243Sobrien } 75659243Sobrien#endif /* NO_CRYPT */ 757167465Smp auto_logout(); 75859243Sobrien} 75959243Sobrien 76059243Sobrien 76159243Sobrienstatic void 762167465Smpauto_logout(void) 76359243Sobrien{ 76459243Sobrien xprintf("auto-logout\n"); 76559243Sobrien /* Don't leave the tty in raw mode */ 76659243Sobrien if (editing) 76759243Sobrien (void) Cookedmode(); 768167465Smp xclose(SHIN); 769167465Smp setcopy(STRlogout, STRautomatic, VAR_READWRITE); 77059243Sobrien child = 1; 77159243Sobrien#ifdef TESLA 77259243Sobrien do_logout = 1; 77359243Sobrien#endif /* TESLA */ 77459243Sobrien GettingInput = FALSE; /* make flush() work to write hist files. Huber*/ 77559243Sobrien goodbye(NULL, NULL); 77659243Sobrien} 77759243Sobrien 778167465Smpvoid 779167465Smpalrmcatch(void) 78059243Sobrien{ 781167465Smp (*alm_fun)(); 78259243Sobrien setalarm(1); 78359243Sobrien} 78459243Sobrien 78559243Sobrien/* 78659243Sobrien * Karl Kleinpaste, 21oct1983. 78759243Sobrien * Added precmd(), which checks for the alias 78859243Sobrien * precmd in aliases. If it's there, the alias 78959243Sobrien * is executed as a command. This is done 79059243Sobrien * after mailchk() and just before print- 79159243Sobrien * ing the prompt. Useful for things like printing 79259243Sobrien * one's current directory just before each command. 79359243Sobrien */ 79459243Sobrienvoid 795167465Smpprecmd(void) 79659243Sobrien{ 797167465Smp pintr_disabled++; 798167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 79959243Sobrien if (precmd_active) { /* an error must have been caught */ 80059243Sobrien aliasrun(2, STRunalias, STRprecmd); 801195609Smp xprintf("%s", CGETS(22, 3, "Faulty alias 'precmd' removed.\n")); 80259243Sobrien goto leave; 80359243Sobrien } 80459243Sobrien precmd_active = 1; 80559243Sobrien if (!whyles && adrof1(STRprecmd, &aliases)) 80659243Sobrien aliasrun(1, STRprecmd, NULL); 80759243Sobrienleave: 80859243Sobrien precmd_active = 0; 809167465Smp cleanup_until(&pintr_disabled); 81059243Sobrien} 81159243Sobrien 81259243Sobrienvoid 813167465Smppostcmd(void) 81459243Sobrien{ 815167465Smp pintr_disabled++; 816167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 81759243Sobrien if (postcmd_active) { /* an error must have been caught */ 81859243Sobrien aliasrun(2, STRunalias, STRpostcmd); 819195609Smp xprintf("%s", CGETS(22, 3, "Faulty alias 'postcmd' removed.\n")); 82059243Sobrien goto leave; 82159243Sobrien } 82259243Sobrien postcmd_active = 1; 82359243Sobrien if (!whyles && adrof1(STRpostcmd, &aliases)) 82459243Sobrien aliasrun(1, STRpostcmd, NULL); 82559243Sobrienleave: 82659243Sobrien postcmd_active = 0; 827167465Smp cleanup_until(&pintr_disabled); 82859243Sobrien} 82959243Sobrien 83059243Sobrien/* 83159243Sobrien * Paul Placeway 11/24/87 Added cwd_cmd by hacking precmd() into 83259243Sobrien * submission... Run every time $cwd is set (after it is set). Useful 83359243Sobrien * for putting your machine and cwd (or anything else) in an xterm title 83459243Sobrien * space. 83559243Sobrien */ 83659243Sobrienvoid 837167465Smpcwd_cmd(void) 83859243Sobrien{ 839167465Smp pintr_disabled++; 840167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 84159243Sobrien if (cwdcmd_active) { /* an error must have been caught */ 84259243Sobrien aliasrun(2, STRunalias, STRcwdcmd); 843195609Smp xprintf("%s", CGETS(22, 4, "Faulty alias 'cwdcmd' removed.\n")); 84459243Sobrien goto leave; 84559243Sobrien } 84659243Sobrien cwdcmd_active = 1; 84759243Sobrien if (!whyles && adrof1(STRcwdcmd, &aliases)) 84859243Sobrien aliasrun(1, STRcwdcmd, NULL); 84959243Sobrienleave: 85059243Sobrien cwdcmd_active = 0; 851167465Smp cleanup_until(&pintr_disabled); 85259243Sobrien} 85359243Sobrien 85459243Sobrien/* 85559243Sobrien * Joachim Hoenig 07/16/91 Added beep_cmd, run every time tcsh wishes 85659243Sobrien * to beep the terminal bell. Useful for playing nice sounds instead. 85759243Sobrien */ 85859243Sobrienvoid 859167465Smpbeep_cmd(void) 86059243Sobrien{ 861167465Smp pintr_disabled++; 862167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 86359243Sobrien if (beepcmd_active) { /* an error must have been caught */ 86459243Sobrien aliasrun(2, STRunalias, STRbeepcmd); 865195609Smp xprintf("%s", CGETS(22, 5, "Faulty alias 'beepcmd' removed.\n")); 86659243Sobrien } 86759243Sobrien else { 86859243Sobrien beepcmd_active = 1; 86959243Sobrien if (!whyles && adrof1(STRbeepcmd, &aliases)) 87059243Sobrien aliasrun(1, STRbeepcmd, NULL); 87159243Sobrien } 87259243Sobrien beepcmd_active = 0; 873167465Smp cleanup_until(&pintr_disabled); 87459243Sobrien} 87559243Sobrien 87659243Sobrien 87759243Sobrien/* 87859243Sobrien * Karl Kleinpaste, 18 Jan 1984. 87959243Sobrien * Added period_cmd(), which executes the alias "periodic" every 88059243Sobrien * $tperiod minutes. Useful for occasional checking of msgs and such. 88159243Sobrien */ 88259243Sobrienvoid 883167465Smpperiod_cmd(void) 88459243Sobrien{ 885145479Smp Char *vp; 88659243Sobrien time_t t, interval; 88759243Sobrien 888167465Smp pintr_disabled++; 889167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 89059243Sobrien if (periodic_active) { /* an error must have been caught */ 89159243Sobrien aliasrun(2, STRunalias, STRperiodic); 892195609Smp xprintf("%s", CGETS(22, 6, "Faulty alias 'periodic' removed.\n")); 89359243Sobrien goto leave; 89459243Sobrien } 89559243Sobrien periodic_active = 1; 89659243Sobrien if (!whyles && adrof1(STRperiodic, &aliases)) { 89759243Sobrien vp = varval(STRtperiod); 89859243Sobrien if (vp == STRNULL) { 89959243Sobrien aliasrun(1, STRperiodic, NULL); 90059243Sobrien goto leave; 90159243Sobrien } 90259243Sobrien interval = getn(vp); 90359243Sobrien (void) time(&t); 90459243Sobrien if (t - t_period >= interval * 60) { 90559243Sobrien t_period = t; 90659243Sobrien aliasrun(1, STRperiodic, NULL); 90759243Sobrien } 90859243Sobrien } 90959243Sobrienleave: 91059243Sobrien periodic_active = 0; 911167465Smp cleanup_until(&pintr_disabled); 91259243Sobrien} 91359243Sobrien 91483098Smp 91583098Smp/* 91683098Smp * GrP Greg Parker May 2001 91783098Smp * Added job_cmd(), which is run every time a job is started or 91883098Smp * foregrounded. The command is passed a single argument, the string 91983098Smp * used to start the job originally. With precmd, useful for setting 92083098Smp * xterm titles. 92183098Smp * Cloned from cwd_cmd(). 92283098Smp */ 92383098Smpvoid 924167465Smpjob_cmd(Char *args) 92583098Smp{ 926167465Smp pintr_disabled++; 927167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 92883098Smp if (jobcmd_active) { /* an error must have been caught */ 92983098Smp aliasrun(2, STRunalias, STRjobcmd); 930195609Smp xprintf("%s", CGETS(22, 14, "Faulty alias 'jobcmd' removed.\n")); 93183098Smp goto leave; 93283098Smp } 93383098Smp jobcmd_active = 1; 934100616Smp if (!whyles && adrof1(STRjobcmd, &aliases)) { 935100616Smp struct process *pp = pcurrjob; /* put things back after the hook */ 93683098Smp aliasrun(2, STRjobcmd, args); 937100616Smp pcurrjob = pp; 938100616Smp } 93983098Smpleave: 94083098Smp jobcmd_active = 0; 941167465Smp cleanup_until(&pintr_disabled); 94283098Smp} 94383098Smp 94483098Smp 94559243Sobrien/* 94659243Sobrien * Karl Kleinpaste, 21oct1983. 94759243Sobrien * Set up a one-word alias command, for use for special things. 94859243Sobrien * This code is based on the mainline of process(). 94959243Sobrien */ 95059243Sobrienvoid 951167465Smpaliasrun(int cnt, Char *s1, Char *s2) 95259243Sobrien{ 95359243Sobrien struct wordent w, *new1, *new2; /* for holding alias name */ 95459243Sobrien struct command *t = NULL; 95559243Sobrien jmp_buf_t osetexit; 95659243Sobrien int status; 957167465Smp size_t omark; 95859243Sobrien 95959243Sobrien getexit(osetexit); 96059243Sobrien if (seterr) { 961167465Smp xfree(seterr); 96259243Sobrien seterr = NULL; /* don't repeatedly print err msg. */ 96359243Sobrien } 96459243Sobrien w.word = STRNULL; 965167465Smp new1 = xcalloc(1, sizeof w); 96659243Sobrien new1->word = Strsave(s1); 96759243Sobrien if (cnt == 1) { 96859243Sobrien /* build a lex list with one word. */ 96959243Sobrien w.next = w.prev = new1; 97059243Sobrien new1->next = new1->prev = &w; 97159243Sobrien } 97259243Sobrien else { 97359243Sobrien /* build a lex list with two words. */ 974167465Smp new2 = xcalloc(1, sizeof w); 97559243Sobrien new2->word = Strsave(s2); 97659243Sobrien w.next = new2->prev = new1; 97759243Sobrien new1->next = w.prev = new2; 97859243Sobrien new1->prev = new2->next = &w; 97959243Sobrien } 980167465Smp cleanup_push(&w, lex_cleanup); 98159243Sobrien 98259243Sobrien /* Save the old status */ 98359243Sobrien status = getn(varval(STRstatus)); 98459243Sobrien 98559243Sobrien /* expand aliases like process() does. */ 98659243Sobrien alias(&w); 98759243Sobrien /* build a syntax tree for the command. */ 98859243Sobrien t = syntax(w.next, &w, 0); 989167465Smp cleanup_push(t, syntax_cleanup); 99059243Sobrien if (seterr) 99159243Sobrien stderror(ERR_OLD); 99259243Sobrien 99359243Sobrien psavejob(); 994167465Smp cleanup_push(&cnt, psavejob_cleanup); /* cnt is used only as a marker */ 99559243Sobrien 99659243Sobrien /* catch any errors here */ 997167465Smp omark = cleanup_push_mark(); 99859243Sobrien if (setexit() == 0) 99959243Sobrien /* execute the parse tree. */ 100059243Sobrien /* 100159243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 100259243Sobrien * was execute(t, tpgrp); 100359243Sobrien */ 1004100616Smp execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL, TRUE); 1005167465Smp /* reset the error catcher to the old place */ 1006167465Smp cleanup_pop_mark(omark); 1007167465Smp resexit(osetexit); 100859243Sobrien if (haderr) { 100959243Sobrien haderr = 0; 101059243Sobrien /* 101159243Sobrien * Either precmd, or cwdcmd, or periodic had an error. Call it again so 101259243Sobrien * that it is removed 101359243Sobrien */ 101459243Sobrien if (precmd_active) 101559243Sobrien precmd(); 101659243Sobrien if (postcmd_active) 101759243Sobrien postcmd(); 101859243Sobrien#ifdef notdef 101959243Sobrien /* 102059243Sobrien * XXX: On the other hand, just interrupting them causes an error too. 102159243Sobrien * So if we hit ^C in the middle of cwdcmd or periodic the alias gets 102259243Sobrien * removed. We don't want that. Note that we want to remove precmd 102359243Sobrien * though, cause that could lead into an infinite loop. This should be 102459243Sobrien * fixed correctly, but then haderr should give us the whole exit 102559243Sobrien * status not just true or false. 102659243Sobrien */ 102759243Sobrien else if (cwdcmd_active) 102859243Sobrien cwd_cmd(); 102959243Sobrien else if (beepcmd_active) 103059243Sobrien beep_cmd(); 103159243Sobrien else if (periodic_active) 103259243Sobrien period_cmd(); 103359243Sobrien#endif /* notdef */ 103459243Sobrien } 1035167465Smp cleanup_until(&w); 103659243Sobrien pendjob(); 103759243Sobrien /* Restore status */ 1038167465Smp setv(STRstatus, putn(status), VAR_READWRITE); 103959243Sobrien} 104059243Sobrien 104159243Sobrienvoid 1042167465Smpsetalarm(int lck) 104359243Sobrien{ 104459243Sobrien struct varent *vp; 104559243Sobrien Char *cp; 104659243Sobrien unsigned alrm_time = 0, logout_time, lock_time; 104759243Sobrien time_t cl, nl, sched_dif; 104859243Sobrien 1049100616Smp if ((vp = adrof(STRautologout)) != NULL && vp->vec != NULL) { 105059243Sobrien if ((cp = vp->vec[0]) != 0) { 105159243Sobrien if ((logout_time = (unsigned) atoi(short2str(cp)) * 60) > 0) { 1052145479Smp#ifdef SOLARIS2 1053145479Smp /* 1054145479Smp * Solaris alarm(2) uses a timer based in clock ticks 1055145479Smp * internally so it multiplies our value with CLK_TCK... 1056145479Smp * Of course that can overflow leading to unexpected 1057145479Smp * results, so we clip it here. Grr. Where is that 1058145479Smp * documented folks? 1059145479Smp */ 1060145479Smp if (logout_time >= 0x7fffffff / CLK_TCK) 1061145479Smp logout_time = 0x7fffffff / CLK_TCK; 1062145479Smp#endif /* SOLARIS2 */ 106359243Sobrien alrm_time = logout_time; 106459243Sobrien alm_fun = auto_logout; 106559243Sobrien } 106659243Sobrien } 106759243Sobrien if ((cp = vp->vec[1]) != 0) { 106859243Sobrien if ((lock_time = (unsigned) atoi(short2str(cp)) * 60) > 0) { 106959243Sobrien if (lck) { 107059243Sobrien if (alrm_time == 0 || lock_time < alrm_time) { 107159243Sobrien alrm_time = lock_time; 107259243Sobrien alm_fun = auto_lock; 107359243Sobrien } 107459243Sobrien } 107559243Sobrien else /* lock_time always < alrm_time */ 107659243Sobrien if (alrm_time) 107759243Sobrien alrm_time -= lock_time; 107859243Sobrien } 107959243Sobrien } 108059243Sobrien } 108159243Sobrien if ((nl = sched_next()) != -1) { 108259243Sobrien (void) time(&cl); 108359243Sobrien sched_dif = nl > cl ? nl - cl : 0; 108459243Sobrien if ((alrm_time == 0) || ((unsigned) sched_dif < alrm_time)) { 108559243Sobrien alrm_time = ((unsigned) sched_dif) + 1; 108659243Sobrien alm_fun = sched_run; 108759243Sobrien } 108859243Sobrien } 1089167465Smp alrmcatch_disabled = 0; 109059243Sobrien (void) alarm(alrm_time); /* Autologout ON */ 109159243Sobrien} 109259243Sobrien 109359243Sobrien#undef RMDEBUG /* For now... */ 109459243Sobrien 109559243Sobrienvoid 1096167465Smprmstar(struct wordent *cp) 109759243Sobrien{ 109859243Sobrien struct wordent *we, *args; 1099145479Smp struct wordent *tmp, *del; 110059243Sobrien 110159243Sobrien#ifdef RMDEBUG 110259243Sobrien static Char STRrmdebug[] = {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'}; 110359243Sobrien Char *tag; 110459243Sobrien#endif /* RMDEBUG */ 110559243Sobrien Char *charac; 110659243Sobrien char c; 110759243Sobrien int ask, doit, star = 0, silent = 0; 110859243Sobrien 110959243Sobrien if (!adrof(STRrmstar)) 111059243Sobrien return; 111159243Sobrien#ifdef RMDEBUG 111259243Sobrien tag = varval(STRrmdebug); 111359243Sobrien#endif /* RMDEBUG */ 111459243Sobrien we = cp->next; 111559243Sobrien while (*we->word == ';' && we != cp) 111659243Sobrien we = we->next; 111759243Sobrien while (we != cp) { 111859243Sobrien#ifdef RMDEBUG 111959243Sobrien if (*tag) 112059243Sobrien xprintf(CGETS(22, 7, "parsing command line\n")); 112159243Sobrien#endif /* RMDEBUG */ 112259243Sobrien if (!Strcmp(we->word, STRrm)) { 112359243Sobrien args = we->next; 112459243Sobrien ask = (*args->word != '-'); 112559243Sobrien while (*args->word == '-' && !silent) { /* check options */ 112659243Sobrien for (charac = (args->word + 1); *charac && !silent; charac++) 112759243Sobrien silent = (*charac == 'i' || *charac == 'f'); 112859243Sobrien args = args->next; 112959243Sobrien } 113059243Sobrien ask = (ask || (!ask && !silent)); 113159243Sobrien if (ask) { 113259243Sobrien for (; !star && *args->word != ';' 113359243Sobrien && args != cp; args = args->next) 113459243Sobrien if (!Strcmp(args->word, STRstar)) 113559243Sobrien star = 1; 113659243Sobrien if (ask && star) { 1137195609Smp xprintf("%s", CGETS(22, 8, 113859243Sobrien "Do you really want to delete all files? [n/y] ")); 113959243Sobrien flush(); 114059243Sobrien (void) force_read(SHIN, &c, 1); 114159243Sobrien /* 114259243Sobrien * Perhaps we should use the yesexpr from the 114359243Sobrien * actual locale 114459243Sobrien */ 114559243Sobrien doit = (strchr(CGETS(22, 14, "Yy"), c) != NULL); 114659243Sobrien while (c != '\n' && force_read(SHIN, &c, 1) == 1) 114759243Sobrien continue; 114859243Sobrien if (!doit) { 114959243Sobrien /* remove the command instead */ 115059243Sobrien#ifdef RMDEBUG 115159243Sobrien if (*tag) 115259243Sobrien xprintf(CGETS(22, 9, 115359243Sobrien "skipping deletion of files!\n")); 115459243Sobrien#endif /* RMDEBUG */ 115559243Sobrien for (tmp = we; 115659243Sobrien *tmp->word != '\n' && 115759243Sobrien *tmp->word != ';' && tmp != cp;) { 115859243Sobrien tmp->prev->next = tmp->next; 115959243Sobrien tmp->next->prev = tmp->prev; 1160167465Smp xfree(tmp->word); 116159243Sobrien del = tmp; 116259243Sobrien tmp = tmp->next; 1163167465Smp xfree(del); 116459243Sobrien } 116559243Sobrien if (*tmp->word == ';') { 116659243Sobrien tmp->prev->next = tmp->next; 116759243Sobrien tmp->next->prev = tmp->prev; 1168167465Smp xfree(tmp->word); 116959243Sobrien del = tmp; 117083098Smp tmp = tmp->next; 1171167465Smp xfree(del); 117259243Sobrien } 117383098Smp we = tmp; 117483098Smp continue; 117559243Sobrien } 117659243Sobrien } 117759243Sobrien } 117859243Sobrien } 117959243Sobrien for (we = we->next; 118059243Sobrien *we->word != ';' && we != cp; 118159243Sobrien we = we->next) 118259243Sobrien continue; 118359243Sobrien if (*we->word == ';') 118459243Sobrien we = we->next; 118559243Sobrien } 118659243Sobrien#ifdef RMDEBUG 118759243Sobrien if (*tag) { 118859243Sobrien xprintf(CGETS(22, 10, "command line now is:\n")); 118959243Sobrien for (we = cp->next; we != cp; we = we->next) 119059243Sobrien xprintf("%S ", we->word); 119159243Sobrien } 119259243Sobrien#endif /* RMDEBUG */ 119359243Sobrien return; 119459243Sobrien} 119559243Sobrien 119659243Sobrien#ifdef BSDJOBS 119759243Sobrien/* Check if command is in continue list 119859243Sobrien and do a "aliasing" if it exists as a job in background */ 119959243Sobrien 120059243Sobrien#undef CNDEBUG /* For now */ 120159243Sobrienvoid 1202167465Smpcontinue_jobs(struct wordent *cp) 120359243Sobrien{ 120459243Sobrien struct wordent *we; 1205145479Smp struct process *pp, *np; 120659243Sobrien Char *cmd, *continue_list, *continue_args_list; 120759243Sobrien 120859243Sobrien#ifdef CNDEBUG 120959243Sobrien Char *tag; 121059243Sobrien static Char STRcndebug[] = 121159243Sobrien {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'}; 121259243Sobrien#endif /* CNDEBUG */ 1213145479Smp int in_cont_list, in_cont_arg_list; 121459243Sobrien 121559243Sobrien 121659243Sobrien#ifdef CNDEBUG 121759243Sobrien tag = varval(STRcndebug); 121859243Sobrien#endif /* CNDEBUG */ 121959243Sobrien continue_list = varval(STRcontinue); 122059243Sobrien continue_args_list = varval(STRcontinue_args); 122159243Sobrien if (*continue_list == '\0' && *continue_args_list == '\0') 122259243Sobrien return; 122359243Sobrien 122459243Sobrien we = cp->next; 122559243Sobrien while (*we->word == ';' && we != cp) 122659243Sobrien we = we->next; 122759243Sobrien while (we != cp) { 122859243Sobrien#ifdef CNDEBUG 122959243Sobrien if (*tag) 123059243Sobrien xprintf(CGETS(22, 11, "parsing command line\n")); 123159243Sobrien#endif /* CNDEBUG */ 123259243Sobrien cmd = we->word; 123359243Sobrien in_cont_list = inlist(continue_list, cmd); 123459243Sobrien in_cont_arg_list = inlist(continue_args_list, cmd); 123559243Sobrien if (in_cont_list || in_cont_arg_list) { 123659243Sobrien#ifdef CNDEBUG 123759243Sobrien if (*tag) 123859243Sobrien xprintf(CGETS(22, 12, "in one of the lists\n")); 123959243Sobrien#endif /* CNDEBUG */ 124059243Sobrien np = NULL; 124159243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 124259243Sobrien if (prefix(cmd, pp->p_command)) { 124359243Sobrien if (pp->p_index) { 124459243Sobrien np = pp; 124559243Sobrien break; 124659243Sobrien } 124759243Sobrien } 124859243Sobrien } 124959243Sobrien if (np) { 125059243Sobrien insert(we, in_cont_arg_list); 125159243Sobrien } 125259243Sobrien } 125359243Sobrien for (we = we->next; 125459243Sobrien *we->word != ';' && we != cp; 125559243Sobrien we = we->next) 125659243Sobrien continue; 125759243Sobrien if (*we->word == ';') 125859243Sobrien we = we->next; 125959243Sobrien } 126059243Sobrien#ifdef CNDEBUG 126159243Sobrien if (*tag) { 126259243Sobrien xprintf(CGETS(22, 13, "command line now is:\n")); 126359243Sobrien for (we = cp->next; we != cp; we = we->next) 126459243Sobrien xprintf("%S ", we->word); 126559243Sobrien } 126659243Sobrien#endif /* CNDEBUG */ 126759243Sobrien return; 126859243Sobrien} 126959243Sobrien 127059243Sobrien/* The actual "aliasing" of for backgrounds() is done here 127159243Sobrien with the aid of insert_we(). */ 127259243Sobrienstatic void 1273167465Smpinsert(struct wordent *pl, int file_args) 127459243Sobrien{ 127559243Sobrien struct wordent *now, *last; 127659243Sobrien Char *cmd, *bcmd, *cp1, *cp2; 1277167465Smp size_t cmd_len; 1278145479Smp Char *upause = STRunderpause; 1279167465Smp size_t p_len = Strlen(upause); 128059243Sobrien 1281167465Smp cmd_len = Strlen(pl->word); 1282167465Smp cmd = xcalloc(1, (cmd_len + 1) * sizeof(Char)); 128359243Sobrien (void) Strcpy(cmd, pl->word); 128459243Sobrien/* Do insertions at beginning, first replace command word */ 128559243Sobrien 128659243Sobrien if (file_args) { 128759243Sobrien now = pl; 1288167465Smp xfree(now->word); 1289167465Smp now->word = xcalloc(1, 5 * sizeof(Char)); 129059243Sobrien (void) Strcpy(now->word, STRecho); 129159243Sobrien 1292167465Smp now = xcalloc(1, sizeof(struct wordent)); 1293167465Smp now->word = xcalloc(1, 6 * sizeof(Char)); 129459243Sobrien (void) Strcpy(now->word, STRbackqpwd); 129559243Sobrien insert_we(now, pl); 129659243Sobrien 129759243Sobrien for (last = now; *last->word != '\n' && *last->word != ';'; 129859243Sobrien last = last->next) 129959243Sobrien continue; 130059243Sobrien 1301167465Smp now = xcalloc(1, sizeof(struct wordent)); 1302167465Smp now->word = xcalloc(1, 2 * sizeof(Char)); 130359243Sobrien (void) Strcpy(now->word, STRgt); 130459243Sobrien insert_we(now, last->prev); 130559243Sobrien 1306167465Smp now = xcalloc(1, sizeof(struct wordent)); 1307167465Smp now->word = xcalloc(1, 2 * sizeof(Char)); 130859243Sobrien (void) Strcpy(now->word, STRbang); 130959243Sobrien insert_we(now, last->prev); 131059243Sobrien 1311167465Smp now = xcalloc(1, sizeof(struct wordent)); 1312167465Smp now->word = xcalloc(1, (cmd_len + p_len + 4) * sizeof(Char)); 131359243Sobrien cp1 = now->word; 131459243Sobrien cp2 = cmd; 131559243Sobrien *cp1++ = '~'; 131659243Sobrien *cp1++ = '/'; 131759243Sobrien *cp1++ = '.'; 131859243Sobrien while ((*cp1++ = *cp2++) != '\0') 131959243Sobrien continue; 132059243Sobrien cp1--; 1321145479Smp cp2 = upause; 132259243Sobrien while ((*cp1++ = *cp2++) != '\0') 132359243Sobrien continue; 132459243Sobrien insert_we(now, last->prev); 132559243Sobrien 1326167465Smp now = xcalloc(1, sizeof(struct wordent)); 1327167465Smp now->word = xcalloc(1, 2 * sizeof(Char)); 132859243Sobrien (void) Strcpy(now->word, STRsemi); 132959243Sobrien insert_we(now, last->prev); 1330167465Smp bcmd = xcalloc(1, (cmd_len + 2) * sizeof(Char)); 1331167465Smp *bcmd = '%'; 1332167465Smp Strcpy(bcmd + 1, cmd); 1333167465Smp now = xcalloc(1, sizeof(struct wordent)); 133459243Sobrien now->word = bcmd; 133559243Sobrien insert_we(now, last->prev); 133659243Sobrien } 133759243Sobrien else { 133859243Sobrien struct wordent *del; 133959243Sobrien 134059243Sobrien now = pl; 1341167465Smp xfree(now->word); 1342167465Smp now->word = xcalloc(1, (cmd_len + 2) * sizeof(Char)); 1343167465Smp *now->word = '%'; 1344167465Smp Strcpy(now->word + 1, cmd); 134559243Sobrien for (now = now->next; 134659243Sobrien *now->word != '\n' && *now->word != ';' && now != pl;) { 134759243Sobrien now->prev->next = now->next; 134859243Sobrien now->next->prev = now->prev; 1349167465Smp xfree(now->word); 135059243Sobrien del = now; 135159243Sobrien now = now->next; 1352167465Smp xfree(del); 135359243Sobrien } 135459243Sobrien } 135559243Sobrien} 135659243Sobrien 135759243Sobrienstatic void 1358167465Smpinsert_we(struct wordent *new, struct wordent *where) 135959243Sobrien{ 136059243Sobrien 136159243Sobrien new->prev = where; 136259243Sobrien new->next = where->next; 136359243Sobrien where->next = new; 136459243Sobrien new->next->prev = new; 136559243Sobrien} 136659243Sobrien 136759243Sobrienstatic int 1368167465Smpinlist(Char *list, Char *name) 136959243Sobrien{ 1370145479Smp Char *l, *n; 137159243Sobrien 137259243Sobrien l = list; 137359243Sobrien n = name; 137459243Sobrien 137559243Sobrien while (*l && *n) { 137659243Sobrien if (*l == *n) { 137759243Sobrien l++; 137859243Sobrien n++; 137959243Sobrien if (*n == '\0' && (*l == ' ' || *l == '\0')) 138059243Sobrien return (1); 138159243Sobrien else 138259243Sobrien continue; 138359243Sobrien } 138459243Sobrien else { 138559243Sobrien while (*l && *l != ' ') 138659243Sobrien l++; /* skip to blank */ 138759243Sobrien while (*l && *l == ' ') 138859243Sobrien l++; /* and find first nonblank character */ 138959243Sobrien n = name; 139059243Sobrien } 139159243Sobrien } 139259243Sobrien return (0); 139359243Sobrien} 139459243Sobrien 139559243Sobrien#endif /* BSDJOBS */ 139659243Sobrien 139759243Sobrien 139859243Sobrien/* 139959243Sobrien * Implement a small cache for tilde names. This is used primarily 140059243Sobrien * to expand tilde names to directories, but also 140159243Sobrien * we can find users from their home directories for the tilde 140259243Sobrien * prompt, on machines where yp lookup is slow this can be a big win... 140359243Sobrien * As with any cache this can run out of sync, rehash can sync it again. 140459243Sobrien */ 140559243Sobrienstatic struct tildecache { 140659243Sobrien Char *user; 140759243Sobrien Char *home; 1408167465Smp size_t hlen; 140959243Sobrien} *tcache = NULL; 141059243Sobrien 141159243Sobrien#define TILINCR 10 1412167465Smpsize_t tlength = 0; 1413167465Smpstatic size_t tsize = TILINCR; 141459243Sobrien 141559243Sobrienstatic int 1416167465Smptildecompare(const void *xp1, const void *xp2) 141759243Sobrien{ 1418167465Smp const struct tildecache *p1, *p2; 1419167465Smp 1420167465Smp p1 = xp1; 1421167465Smp p2 = xp2; 142259243Sobrien return Strcmp(p1->user, p2->user); 142359243Sobrien} 142459243Sobrien 142559243Sobrienstatic Char * 1426167465Smpgethomedir(const Char *us) 142759243Sobrien{ 1428145479Smp struct passwd *pp; 142959243Sobrien#ifdef HESIOD 143059243Sobrien char **res, **res1, *cp; 143159243Sobrien Char *rp; 143259243Sobrien#endif /* HESIOD */ 143359243Sobrien 1434167465Smp pp = xgetpwnam(short2str(us)); 143559243Sobrien#ifdef YPBUGS 143659243Sobrien fix_yp_bugs(); 143759243Sobrien#endif /* YPBUGS */ 143883098Smp if (pp != NULL) { 1439100616Smp#if 0 144083098Smp /* Don't return if root */ 144183098Smp if (pp->pw_dir[0] == '/' && pp->pw_dir[1] == '\0') 144283098Smp return NULL; 144383098Smp else 1444100616Smp#endif 144583098Smp return Strsave(str2short(pp->pw_dir)); 144683098Smp } 144759243Sobrien#ifdef HESIOD 144859243Sobrien res = hes_resolve(short2str(us), "filsys"); 144983098Smp rp = NULL; 145083098Smp if (res != NULL) { 145183098Smp if ((*res) != NULL) { 145259243Sobrien /* 145359243Sobrien * Look at the first token to determine how to interpret 145459243Sobrien * the rest of it. 145559243Sobrien * Yes, strtok is evil (it's not thread-safe), but it's also 145659243Sobrien * easy to use. 145759243Sobrien */ 145859243Sobrien cp = strtok(*res, " "); 145959243Sobrien if (strcmp(cp, "AFS") == 0) { 146059243Sobrien /* next token is AFS pathname.. */ 146159243Sobrien cp = strtok(NULL, " "); 146259243Sobrien if (cp != NULL) 146359243Sobrien rp = Strsave(str2short(cp)); 146459243Sobrien } else if (strcmp(cp, "NFS") == 0) { 146559243Sobrien cp = NULL; 146659243Sobrien if ((strtok(NULL, " ")) && /* skip remote pathname */ 146759243Sobrien (strtok(NULL, " ")) && /* skip host */ 146859243Sobrien (strtok(NULL, " ")) && /* skip mode */ 146959243Sobrien (cp = strtok(NULL, " "))) { 147059243Sobrien rp = Strsave(str2short(cp)); 147159243Sobrien } 147259243Sobrien } 147359243Sobrien } 147459243Sobrien for (res1 = res; *res1; res1++) 147559243Sobrien free(*res1); 1476100616Smp#if 0 1477100616Smp /* Don't return if root */ 147883098Smp if (rp != NULL && rp[0] == '/' && rp[1] == '\0') { 1479167465Smp xfree(rp); 148083098Smp rp = NULL; 148183098Smp } 1482100616Smp#endif 148359243Sobrien return rp; 148459243Sobrien } 148559243Sobrien#endif /* HESIOD */ 148659243Sobrien return NULL; 148759243Sobrien} 148859243Sobrien 148959243SobrienChar * 1490167465Smpgettilde(const Char *us) 149159243Sobrien{ 149259243Sobrien struct tildecache *bp1, *bp2, *bp; 149359243Sobrien Char *hd; 149459243Sobrien 149559243Sobrien /* Ignore NIS special names */ 149659243Sobrien if (*us == '+' || *us == '-') 149759243Sobrien return NULL; 149859243Sobrien 149959243Sobrien if (tcache == NULL) 1500167465Smp tcache = xmalloc(TILINCR * sizeof(struct tildecache)); 150159243Sobrien /* 150259243Sobrien * Binary search 150359243Sobrien */ 150459243Sobrien for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) { 1505145479Smp int i; 150659243Sobrien 150759243Sobrien bp = bp1 + ((bp2 - bp1) >> 1); 150859243Sobrien if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0) 150959243Sobrien return (bp->home); 151059243Sobrien if (i < 0) 151159243Sobrien bp2 = bp; 151259243Sobrien else 151359243Sobrien bp1 = bp + 1; 151459243Sobrien } 151559243Sobrien /* 151659243Sobrien * Not in the cache, try to get it from the passwd file 151759243Sobrien */ 151859243Sobrien hd = gethomedir(us); 151959243Sobrien if (hd == NULL) 152059243Sobrien return NULL; 152159243Sobrien 152259243Sobrien /* 152359243Sobrien * Update the cache 152459243Sobrien */ 152559243Sobrien tcache[tlength].user = Strsave(us); 152659243Sobrien tcache[tlength].home = hd; 1527167465Smp tcache[tlength++].hlen = Strlen(hd); 152859243Sobrien 1529167465Smp qsort(tcache, tlength, sizeof(struct tildecache), tildecompare); 153059243Sobrien 153159243Sobrien if (tlength == tsize) { 153259243Sobrien tsize += TILINCR; 1533167465Smp tcache = xrealloc(tcache, tsize * sizeof(struct tildecache)); 153459243Sobrien } 153559243Sobrien return (hd); 153659243Sobrien} 153759243Sobrien 153859243Sobrien/* 153959243Sobrien * Return the username if the directory path passed contains a 154059243Sobrien * user's home directory in the tilde cache, otherwise return NULL 154159243Sobrien * hm points to the place where the path became different. 154259243Sobrien * Special case: Our own home directory. 154359243Sobrien * If we are passed a null pointer, then we flush the cache. 154459243Sobrien */ 154559243SobrienChar * 1546167465Smpgetusername(Char **hm) 154759243Sobrien{ 154859243Sobrien Char *h, *p; 1549167465Smp size_t i, j; 155059243Sobrien 155159243Sobrien if (hm == NULL) { 155259243Sobrien for (i = 0; i < tlength; i++) { 1553167465Smp xfree(tcache[i].home); 1554167465Smp xfree(tcache[i].user); 155559243Sobrien } 1556167465Smp xfree(tcache); 155759243Sobrien tlength = 0; 155859243Sobrien tsize = TILINCR; 155959243Sobrien tcache = NULL; 156059243Sobrien return NULL; 156159243Sobrien } 1562167465Smp p = *hm; 156359243Sobrien if (((h = varval(STRhome)) != STRNULL) && 1564167465Smp (Strncmp(p, h, j = Strlen(h)) == 0) && 156559243Sobrien (p[j] == '/' || p[j] == '\0')) { 156659243Sobrien *hm = &p[j]; 156759243Sobrien return STRNULL; 156859243Sobrien } 156959243Sobrien for (i = 0; i < tlength; i++) 1570167465Smp if ((Strncmp(p, tcache[i].home, (j = tcache[i].hlen)) == 0) && 1571167465Smp (p[j] == '/' || p[j] == '\0')) { 157259243Sobrien *hm = &p[j]; 157359243Sobrien return tcache[i].user; 157459243Sobrien } 157559243Sobrien return NULL; 157659243Sobrien} 157759243Sobrien 157859243Sobrien 157959243Sobrien/* 158059243Sobrien * set the shell-level var to 1 or apply change to it. 158159243Sobrien */ 158259243Sobrienvoid 1583167465Smpshlvl(int val) 158459243Sobrien{ 158559243Sobrien char *cp; 158659243Sobrien 158759243Sobrien if ((cp = getenv("SHLVL")) != NULL) { 158859243Sobrien 158959243Sobrien if (loginsh) 159059243Sobrien val = 1; 159159243Sobrien else 159259243Sobrien val += atoi(cp); 159359243Sobrien 159459243Sobrien if (val <= 0) { 159559243Sobrien if (adrof(STRshlvl) != NULL) 159659243Sobrien unsetv(STRshlvl); 159759243Sobrien Unsetenv(STRKSHLVL); 159859243Sobrien } 159959243Sobrien else { 1600167465Smp Char *p; 160159243Sobrien 1602167465Smp p = Itoa(val, 0, 0); 1603167465Smp cleanup_push(p, xfree); 1604167465Smp setv(STRshlvl, p, VAR_READWRITE); 1605167465Smp cleanup_ignore(p); 1606167465Smp cleanup_until(p); 1607167465Smp tsetenv(STRKSHLVL, p); 160859243Sobrien } 160959243Sobrien } 161059243Sobrien else { 1611167465Smp setcopy(STRshlvl, STR1, VAR_READWRITE); 1612167465Smp tsetenv(STRKSHLVL, STR1); 161359243Sobrien } 161459243Sobrien} 161559243Sobrien 161659243Sobrien 161759243Sobrien/* fixio(): 161859243Sobrien * Try to recover from a read error 161959243Sobrien */ 162059243Sobrienint 1621167465Smpfixio(int fd, int e) 162259243Sobrien{ 162359243Sobrien switch (e) { 162459243Sobrien case -1: /* Make sure that the code is reachable */ 162559243Sobrien 162659243Sobrien#ifdef EWOULDBLOCK 162759243Sobrien case EWOULDBLOCK: 162859243Sobrien# define FDRETRY 162959243Sobrien#endif /* EWOULDBLOCK */ 163059243Sobrien 163159243Sobrien#if defined(POSIX) && defined(EAGAIN) 163259243Sobrien# if !defined(EWOULDBLOCK) || EWOULDBLOCK != EAGAIN 163359243Sobrien case EAGAIN: 163459243Sobrien# define FDRETRY 163559243Sobrien# endif /* !EWOULDBLOCK || EWOULDBLOCK != EAGAIN */ 163659243Sobrien#endif /* POSIX && EAGAIN */ 163759243Sobrien 163859243Sobrien e = 0; 163959243Sobrien#ifdef FDRETRY 164059243Sobrien# ifdef F_SETFL 164159243Sobrien/* 164259243Sobrien * Great! we have on suns 3 flavors and 5 names... 164359243Sobrien * I hope that will cover everything. 164459243Sobrien * I added some more defines... many systems have different defines. 164559243Sobrien * Rather than dealing with getting the right includes, we'll just 164659243Sobrien * cover all the known possibilities here. -- sterling@netcom.com 164759243Sobrien */ 164859243Sobrien# ifndef O_NONBLOCK 164959243Sobrien# define O_NONBLOCK 0 165059243Sobrien# endif /* O_NONBLOCK */ 165159243Sobrien# ifndef O_NDELAY 165259243Sobrien# define O_NDELAY 0 165359243Sobrien# endif /* O_NDELAY */ 165459243Sobrien# ifndef FNBIO 165559243Sobrien# define FNBIO 0 165659243Sobrien# endif /* FNBIO */ 165759243Sobrien# ifndef _FNBIO 165859243Sobrien# define _FNBIO 0 165959243Sobrien# endif /* _FNBIO */ 166059243Sobrien# ifndef FNONBIO 166159243Sobrien# define FNONBIO 0 166259243Sobrien# endif /* FNONBIO */ 166359243Sobrien# ifndef FNONBLOCK 166459243Sobrien# define FNONBLOCK 0 166559243Sobrien# endif /* FNONBLOCK */ 166659243Sobrien# ifndef _FNONBLOCK 166759243Sobrien# define _FNONBLOCK 0 166859243Sobrien# endif /* _FNONBLOCK */ 166959243Sobrien# ifndef FNDELAY 167059243Sobrien# define FNDELAY 0 167159243Sobrien# endif /* FNDELAY */ 167259243Sobrien# ifndef _FNDELAY 167359243Sobrien# define _FNDELAY 0 167459243Sobrien# endif /* _FNDELAY */ 167559243Sobrien# ifndef FNDLEAY /* Some linux versions have this typo */ 167659243Sobrien# define FNDLEAY 0 167759243Sobrien# endif /* FNDLEAY */ 167859243Sobrien if ((e = fcntl(fd, F_GETFL, 0)) == -1) 167959243Sobrien return -1; 168059243Sobrien 168159243Sobrien e &= ~(O_NDELAY|O_NONBLOCK|FNBIO|_FNBIO|FNONBIO|FNONBLOCK|_FNONBLOCK| 168259243Sobrien FNDELAY|_FNDELAY|FNDLEAY); /* whew! */ 168359243Sobrien if (fcntl(fd, F_SETFL, e) == -1) 168459243Sobrien return -1; 168559243Sobrien else 168659243Sobrien e = 1; 168759243Sobrien# endif /* F_SETFL */ 168859243Sobrien 168959243Sobrien# ifdef FIONBIO 169059243Sobrien e = 0; 169159243Sobrien if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1) 169259243Sobrien return -1; 169359243Sobrien else 169459243Sobrien e = 1; 169559243Sobrien# endif /* FIONBIO */ 169659243Sobrien 169759243Sobrien#endif /* FDRETRY */ 169859243Sobrien return e ? 0 : -1; 169959243Sobrien 170059243Sobrien case EINTR: 170159243Sobrien return 0; 170259243Sobrien 170359243Sobrien default: 170459243Sobrien return -1; 170559243Sobrien } 170659243Sobrien} 170759243Sobrien 170859243Sobrien/* collate(): 170959243Sobrien * String collation 171059243Sobrien */ 171159243Sobrienint 1712167465Smpcollate(const Char *a, const Char *b) 171359243Sobrien{ 171459243Sobrien int rv; 171559243Sobrien#ifdef SHORT_STRINGS 171659243Sobrien /* This strips the quote bit as a side effect */ 171759243Sobrien char *sa = strsave(short2str(a)); 171859243Sobrien char *sb = strsave(short2str(b)); 171959243Sobrien#else 172059243Sobrien char *sa = strip(strsave(a)); 172159243Sobrien char *sb = strip(strsave(b)); 172259243Sobrien#endif /* SHORT_STRINGS */ 172359243Sobrien 1724167465Smp#if defined(NLS) && defined(HAVE_STRCOLL) 172559243Sobrien errno = 0; /* strcoll sets errno, another brain-damage */ 172659243Sobrien 172759243Sobrien rv = strcoll(sa, sb); 172859243Sobrien 172959243Sobrien /* 173059243Sobrien * We should be checking for errno != 0, but some systems 173159243Sobrien * forget to reset errno to 0. So we only check for the 173259243Sobrien * only documented valid errno value for strcoll [EINVAL] 173359243Sobrien */ 173459243Sobrien if (errno == EINVAL) { 1735167465Smp xfree(sa); 1736167465Smp xfree(sb); 173759243Sobrien stderror(ERR_SYSTEM, "strcoll", strerror(errno)); 173859243Sobrien } 173959243Sobrien#else 174059243Sobrien rv = strcmp(sa, sb); 1741167465Smp#endif /* NLS && HAVE_STRCOLL */ 174259243Sobrien 1743167465Smp xfree(sa); 1744167465Smp xfree(sb); 174559243Sobrien 174659243Sobrien return rv; 174759243Sobrien} 174859243Sobrien 174959243Sobrien#ifdef HASHBANG 175059243Sobrien/* 175159243Sobrien * From: peter@zeus.dialix.oz.au (Peter Wemm) 175259243Sobrien * If exec() fails look first for a #! [word] [word] .... 175359243Sobrien * If it is, splice the header into the argument list and retry. 175459243Sobrien */ 175559243Sobrien#define HACKBUFSZ 1024 /* Max chars in #! vector */ 175659243Sobrienint 1757167465Smphashbang(int fd, Char ***vp) 175859243Sobrien{ 1759167465Smp struct blk_buf sarg = BLK_BUF_INIT; 1760167465Smp char lbuf[HACKBUFSZ], *p, *ws; 176169408Sache#ifdef WINNT_NATIVE 176259243Sobrien int fw = 0; /* found at least one word */ 1763167465Smp int first_word = 1; 1764167465Smp char *real; 176569408Sache#endif /* WINNT_NATIVE */ 176659243Sobrien 1767167465Smp if (xread(fd, lbuf, HACKBUFSZ) <= 0) 176859243Sobrien return -1; 176959243Sobrien 177059243Sobrien ws = 0; /* word started = 0 */ 177159243Sobrien 1772167465Smp for (p = lbuf; p < &lbuf[HACKBUFSZ]; ) { 177359243Sobrien switch (*p) { 177459243Sobrien case ' ': 177559243Sobrien case '\t': 1776195609Smp#if defined(WINNT_NATIVE) || defined (__CYGWIN__) 177759243Sobrien case '\r': 1778195609Smp#endif /* WINNT_NATIVE || __CYGWIN__ */ 177959243Sobrien if (ws) { /* a blank after a word.. save it */ 178059243Sobrien *p = '\0'; 1781167465Smp#ifdef WINNT_NATIVE 1782167465Smp if (first_word) { 1783167465Smp real = hb_subst(ws); 1784167465Smp if (real != NULL) 1785167465Smp ws = real; 178659243Sobrien } 178759243Sobrien fw = 1; 1788167465Smp first_word = 0; 178969408Sache#endif /* WINNT_NATIVE */ 1790167465Smp bb_append(&sarg, SAVE(ws)); 1791167465Smp ws = NULL; 179259243Sobrien } 179359243Sobrien p++; 179459243Sobrien continue; 179559243Sobrien 179659243Sobrien case '\0': /* Whoa!! what the hell happened */ 1797167465Smp goto err; 179859243Sobrien 179959243Sobrien case '\n': /* The end of the line. */ 180059243Sobrien if ( 180169408Sache#ifdef WINNT_NATIVE 180259243Sobrien fw || 180369408Sache#endif /* WINNT_NATIVE */ 180459243Sobrien ws) { /* terminate the last word */ 180559243Sobrien *p = '\0'; 1806167465Smp#ifdef WINNT_NATIVE 1807167465Smp /* deal with the 1-word case */ 1808167465Smp if (first_word) { 1809167465Smp real = hb_subst(ws); 1810167465Smp if (real != NULL) 1811167465Smp ws = real; 181259243Sobrien } 181369408Sache#endif /* !WINNT_NATIVE */ 1814167465Smp if (ws) 1815167465Smp bb_append(&sarg, SAVE(ws)); 181659243Sobrien } 1817167465Smp if (sarg.len > 0) { 1818167465Smp *vp = bb_finish(&sarg); 181959243Sobrien return 0; 182059243Sobrien } 182159243Sobrien else 1822167465Smp goto err; 182359243Sobrien 182459243Sobrien default: 182559243Sobrien if (!ws) /* Start a new word? */ 182659243Sobrien ws = p; 182759243Sobrien p++; 182859243Sobrien break; 182959243Sobrien } 1830167465Smp } 1831167465Smp err: 1832167465Smp bb_cleanup(&sarg); 183359243Sobrien return -1; 183459243Sobrien} 183559243Sobrien#endif /* HASHBANG */ 183659243Sobrien 183759243Sobrien#ifdef REMOTEHOST 183859243Sobrien 1839167465Smpstatic void 1840167465Smppalarm(int snum) 184159243Sobrien{ 184259243Sobrien USE(snum); 1843167465Smp _exit(1); 184459243Sobrien} 184559243Sobrien 184659243Sobrienstatic void 1847167465Smpgetremotehost(int dest_fd) 184859243Sobrien{ 184959243Sobrien const char *host = NULL; 185069408Sache#ifdef INET6 185169408Sache struct sockaddr_storage saddr; 185269408Sache static char hbuf[NI_MAXHOST]; 185369408Sache#else 185459243Sobrien struct hostent* hp; 185559243Sobrien struct sockaddr_in saddr; 185669408Sache#endif 1857167465Smp socklen_t len = sizeof(saddr); 185859243Sobrien 185969408Sache#ifdef INET6 1860100616Smp if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 1861100616Smp (saddr.ss_family == AF_INET6 || saddr.ss_family == AF_INET)) { 186269408Sache int flag = NI_NUMERICHOST; 186369408Sache 186469408Sache#ifdef NI_WITHSCOPEID 186569408Sache flag |= NI_WITHSCOPEID; 186669408Sache#endif 186769408Sache getnameinfo((struct sockaddr *)&saddr, len, hbuf, sizeof(hbuf), 186869408Sache NULL, 0, flag); 186969408Sache host = hbuf; 187069408Sache#else 1871100616Smp if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 1872100616Smp saddr.sin_family == AF_INET) { 187369408Sache#if 0 187459243Sobrien if ((hp = gethostbyaddr((char *)&saddr.sin_addr, sizeof(struct in_addr), 187559243Sobrien AF_INET)) != NULL) 187659243Sobrien host = hp->h_name; 187759243Sobrien else 187859243Sobrien#endif 187959243Sobrien host = inet_ntoa(saddr.sin_addr); 188069408Sache#endif 188159243Sobrien } 1882145479Smp#ifdef HAVE_STRUCT_UTMP_UT_HOST 188359243Sobrien else { 188459243Sobrien char *ptr; 188559243Sobrien char *name = utmphost(); 188659243Sobrien /* Avoid empty names and local X displays */ 188759243Sobrien if (name != NULL && *name != '\0' && *name != ':') { 188869408Sache struct in_addr addr; 1889167465Smp char *sptr; 189069408Sache 189159243Sobrien /* Look for host:display.screen */ 189269408Sache /* 189369408Sache * There is conflict with IPv6 address and X DISPLAY. So, 189469408Sache * we assume there is no IPv6 address in utmp and don't 189569408Sache * touch here. 189669408Sache */ 189759243Sobrien if ((sptr = strchr(name, ':')) != NULL) 189859243Sobrien *sptr = '\0'; 189969408Sache /* Leave IPv4 address as is */ 190069408Sache /* 190169408Sache * we use inet_addr here, not inet_aton because many systems 190269408Sache * have not caught up yet. 190369408Sache */ 190469408Sache addr.s_addr = inet_addr(name); 1905131962Smp if (addr.s_addr != (unsigned int)~0) 190659243Sobrien host = name; 190759243Sobrien else { 190859243Sobrien if (sptr != name) { 190969408Sache#ifdef INET6 191069408Sache char *s, *domain; 1911167465Smp char dbuf[MAXHOSTNAMELEN]; 191269408Sache struct addrinfo hints, *res = NULL; 191369408Sache 191469408Sache memset(&hints, 0, sizeof(hints)); 191569408Sache hints.ai_family = PF_UNSPEC; 191669408Sache hints.ai_socktype = SOCK_STREAM; 191769408Sache hints.ai_flags = AI_PASSIVE | AI_CANONNAME; 191869408Sache if (strlen(name) < utmphostsize()) 191969408Sache { 192069408Sache if (getaddrinfo(name, NULL, &hints, &res) != 0) 192169408Sache res = NULL; 1922167465Smp } else if (gethostname(dbuf, sizeof(dbuf)) == 0 && 1923167465Smp (dbuf[sizeof(dbuf)-1] = '\0', /*FIXME: ugly*/ 1924167465Smp (domain = strchr(dbuf, '.')) != NULL)) { 192569408Sache for (s = strchr(name, '.'); 192669408Sache s != NULL; s = strchr(s + 1, '.')) { 192769408Sache if (*(s + 1) != '\0' && 192869408Sache (ptr = strstr(domain, s)) != NULL) { 1929167465Smp char *cbuf; 1930167465Smp 1931167465Smp cbuf = strspl(name, ptr); 193269408Sache if (getaddrinfo(cbuf, NULL, &hints, &res) != 0) 193369408Sache res = NULL; 1934167465Smp xfree(cbuf); 193569408Sache break; 193669408Sache } 193769408Sache } 193869408Sache } 193969408Sache if (res != NULL) { 194069408Sache if (res->ai_canonname != NULL) { 194169408Sache strncpy(hbuf, res->ai_canonname, sizeof(hbuf)); 194269408Sache host = hbuf; 194369408Sache } 194469408Sache freeaddrinfo(res); 194569408Sache } 194669408Sache#else 194759243Sobrien if ((hp = gethostbyname(name)) == NULL) { 194859243Sobrien /* Try again eliminating the trailing domain */ 194959243Sobrien if ((ptr = strchr(name, '.')) != NULL) { 195059243Sobrien *ptr = '\0'; 195159243Sobrien if ((hp = gethostbyname(name)) != NULL) 195259243Sobrien host = hp->h_name; 195359243Sobrien *ptr = '.'; 195459243Sobrien } 195559243Sobrien } 195659243Sobrien else 195759243Sobrien host = hp->h_name; 195869408Sache#endif 195959243Sobrien } 196059243Sobrien } 196159243Sobrien } 196259243Sobrien } 196359243Sobrien#endif 196459243Sobrien 1965167465Smp if (host) { 1966167465Smp size_t left; 196759243Sobrien 1968167465Smp left = strlen(host); 1969167465Smp while (left != 0) { 1970167465Smp ssize_t res; 1971167465Smp 1972167465Smp res = xwrite(dest_fd, host, left); 1973167465Smp if (res < 0) 1974167465Smp _exit(1); 1975167465Smp host += res; 1976167465Smp left -= res; 1977167465Smp } 1978167465Smp } 1979167465Smp _exit(0); 198059243Sobrien} 198159243Sobrien 198259243Sobrien/* 198359243Sobrien * From: <lesv@ppvku.ericsson.se> (Lennart Svensson) 198459243Sobrien */ 1985167465Smpvoid 1986167465Smpremotehost(void) 198759243Sobrien{ 1988167465Smp struct sigaction sa; 1989167465Smp struct strbuf hostname = strbuf_INIT; 1990167465Smp int fds[2], wait_options, status; 1991167465Smp pid_t pid, wait_res; 199259243Sobrien 1993167465Smp sa.sa_handler = SIG_DFL; /* Make sure a zombie is created */ 1994167465Smp sigemptyset(&sa.sa_mask); 1995167465Smp sa.sa_flags = 0; 1996167465Smp sigaction(SIGCHLD, &sa, NULL); 1997167465Smp mypipe(fds); 1998167465Smp pid = fork(); 1999167465Smp if (pid == 0) { 2000167465Smp sigset_t set; 2001167465Smp xclose(fds[0]); 2002167465Smp /* Don't get stuck if the resolver does not work! */ 2003167465Smp signal(SIGALRM, palarm); 2004167465Smp sigemptyset(&set); 2005167465Smp sigaddset(&set, SIGALRM); 2006167465Smp (void)sigprocmask(SIG_UNBLOCK, &set, NULL); 2007167465Smp (void)alarm(2); 2008167465Smp getremotehost(fds[1]); 2009167465Smp /*NOTREACHED*/ 2010167465Smp } 2011167465Smp xclose(fds[1]); 2012167465Smp for (;;) { 2013167465Smp char buf[BUFSIZE]; 2014167465Smp ssize_t res; 201559243Sobrien 2016167465Smp res = xread(fds[0], buf, sizeof(buf)); 2017167465Smp if (res == -1) { 2018167465Smp hostname.len = 0; 2019167465Smp wait_options = WNOHANG; 2020167465Smp goto done; 2021167465Smp } 2022167465Smp if (res == 0) 2023167465Smp break; 2024167465Smp strbuf_appendn(&hostname, buf, res); 2025167465Smp } 2026167465Smp wait_options = 0; 2027167465Smp done: 2028167465Smp xclose(fds[0]); 2029167465Smp while ((wait_res = waitpid(pid, &status, wait_options)) == -1 2030167465Smp && errno == EINTR) 2031167465Smp handle_pending_signals(); 2032167465Smp cleanup_push(&hostname, strbuf_cleanup); 2033167465Smp if (wait_res == pid && WIFEXITED(status) && WEXITSTATUS(status) == 0) { 2034167465Smp strbuf_terminate(&hostname); 2035167465Smp tsetenv(STRREMOTEHOST, str2short(hostname.s)); 2036167465Smp } 2037167465Smp cleanup_until(&hostname); 203859243Sobrien 203959243Sobrien#ifdef YPBUGS 204059243Sobrien /* From: casper@fwi.uva.nl (Casper H.S. Dik), for Solaris 2.3 */ 204159243Sobrien fix_yp_bugs(); 204259243Sobrien#endif /* YPBUGS */ 204359243Sobrien 204459243Sobrien} 204559243Sobrien#endif /* REMOTEHOST */ 2046145479Smp 2047145479Smp#ifndef WINNT_NATIVE 2048145479Smp/* 2049145479Smp * indicate if a terminal type is defined in terminfo/termcap 2050145479Smp * (by default the current term type). This allows ppl to look 2051145479Smp * for a working term type automatically in their login scripts 2052145479Smp * when using a terminal known as different things on different 2053145479Smp * platforms 2054145479Smp */ 2055145479Smpvoid 2056167465Smpdotermname(Char **v, struct command *c) 2057145479Smp{ 2058145479Smp char *termtype; 2059145479Smp /* 2060145479Smp * Maximum size of a termcap record. We make it twice as large. 2061145479Smp */ 2062145479Smp char termcap_buffer[2048]; 2063145479Smp 2064145479Smp USE(c); 2065145479Smp /* try to find which entry we should be looking for */ 2066145479Smp termtype = (v[1] == NULL ? getenv("TERM") : short2str(v[1])); 2067145479Smp if (termtype == NULL) { 2068145479Smp /* no luck - the user didn't provide one and none is 2069145479Smp * specified in the environment 2070145479Smp */ 2071167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 2072145479Smp return; 2073145479Smp } 2074145479Smp 2075145479Smp /* 2076145479Smp * we use the termcap function - if we are using terminfo we 2077145479Smp * will end up with it's compatibility function 2078145479Smp * terminfo/termcap will be initialized with the new 2079145479Smp * type but we don't care because tcsh has cached all the things 2080145479Smp * it needs. 2081145479Smp */ 2082145479Smp if (tgetent(termcap_buffer, termtype) == 1) { 2083145479Smp xprintf("%s\n", termtype); 2084167465Smp setcopy(STRstatus, STR0, VAR_READWRITE); 2085167465Smp } else 2086167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 2087145479Smp} 2088145479Smp#endif /* WINNT_NATIVE */ 2089