tc.func.c revision 83098
183098Smp/* $Header: /src/pub/tcsh/tc.func.c,v 3.97 2001/08/28 23:13:44 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.
1759243Sobrien * 3. All advertising materials mentioning features or use of this software
1859243Sobrien *    must display the following acknowledgement:
1959243Sobrien *	This product includes software developed by the University of
2059243Sobrien *	California, Berkeley and its contributors.
2159243Sobrien * 4. Neither the name of the University nor the names of its contributors
2259243Sobrien *    may be used to endorse or promote products derived from this software
2359243Sobrien *    without specific prior written permission.
2459243Sobrien *
2559243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2659243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2759243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2859243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2959243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3059243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3159243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3259243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3359243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3459243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3559243Sobrien * SUCH DAMAGE.
3659243Sobrien */
3759243Sobrien#include "sh.h"
3859243Sobrien
3983098SmpRCSID("$Id: tc.func.c,v 3.97 2001/08/28 23:13:44 christos Exp $")
4059243Sobrien
4159243Sobrien#include "ed.h"
4259243Sobrien#include "ed.defns.h"		/* for the function names */
4359243Sobrien#include "tw.h"
4459243Sobrien#include "tc.h"
4569408Sache#ifdef WINNT_NATIVE
4659243Sobrien#include "nt.const.h"
4769408Sache#endif /* WINNT_NATIVE */
4859243Sobrien
4959243Sobrien#ifdef AFS
5059243Sobrien#define PASSMAX 16
5159243Sobrien#include <afs/stds.h>
5259243Sobrien#include <afs/kautils.h>
5359243Sobrienlong ka_UserAuthenticateGeneral();
5459243Sobrien#else
5559243Sobrien#ifndef PASSMAX
5659243Sobrien#define PASSMAX 8
5759243Sobrien#endif
5859243Sobrien#endif /* AFS */
5959243Sobrien
6059243Sobrien#ifdef TESLA
6159243Sobrienextern int do_logout;
6259243Sobrien#endif /* TESLA */
6359243Sobrienextern time_t t_period;
6459243Sobrienextern int just_signaled;
6559243Sobrienstatic bool precmd_active = 0;
6683098Smpstatic bool jobcmd_active = 0; /* GrP */
6759243Sobrienstatic bool postcmd_active = 0;
6859243Sobrienstatic bool periodic_active = 0;
6959243Sobrienstatic bool cwdcmd_active = 0;	/* PWP: for cwd_cmd */
7059243Sobrienstatic bool beepcmd_active = 0;
7159243Sobrienstatic signalfun_t alm_fun = NULL;
7259243Sobrien
7359243Sobrienstatic	void	 auto_logout	__P((int));
7459243Sobrienstatic	char	*xgetpass	__P((char *));
7559243Sobrienstatic	void	 auto_lock	__P((int));
7659243Sobrien#ifdef BSDJOBS
7759243Sobrienstatic	void	 insert		__P((struct wordent *, bool));
7859243Sobrienstatic	void	 insert_we	__P((struct wordent *, struct wordent *));
7959243Sobrienstatic	int	 inlist		__P((Char *, Char *));
8059243Sobrien#endif /* BSDJOBS */
8159243Sobrienstruct tildecache;
8259243Sobrienstatic	int	 tildecompare	__P((struct tildecache *, struct tildecache *));
8359243Sobrienstatic  Char    *gethomedir	__P((Char *));
8459243Sobrien#ifdef REMOTEHOST
8559243Sobrienstatic	sigret_t palarm		__P((int));
8659243Sobrienstatic	void	 getremotehost	__P((void));
8759243Sobrien#endif /* REMOTEHOST */
8859243Sobrien
8959243Sobrien/*
9059243Sobrien * Tops-C shell
9159243Sobrien */
9259243Sobrien
9359243Sobrien/*
9461524Sobrien * expand_lex: Take the given lex and put an expanded version of it in
9561524Sobrien * the string buf. First guy in lex list is ignored; last guy is ^J
9661524Sobrien * which we ignore. Only take lex'es from position 'from' to position
9761524Sobrien * 'to' inclusive
9861524Sobrien *
9961524Sobrien * Note: csh sometimes sets bit 8 in characters which causes all kinds
10061524Sobrien * of problems if we don't mask it here. Note: excl's in lexes have been
10161524Sobrien * un-back-slashed and must be re-back-slashed
10261524Sobrien *
10359243Sobrien * (PWP: NOTE: this returns a pointer to the END of the string expanded
10459243Sobrien *             (in other words, where the NUL is).)
10559243Sobrien */
10659243Sobrien/* PWP: this is a combination of the old sprlex() and the expand_lex from
10759243Sobrien   the magic-space stuff */
10859243Sobrien
10959243SobrienChar   *
11059243Sobrienexpand_lex(buf, bufsiz, sp0, from, to)
11159243Sobrien    Char   *buf;
11259243Sobrien    size_t  bufsiz;
11359243Sobrien    struct  wordent *sp0;
11459243Sobrien    int     from, to;
11559243Sobrien{
11659243Sobrien    register struct wordent *sp;
11759243Sobrien    register Char *s, *d, *e;
11859243Sobrien    register Char prev_c;
11959243Sobrien    register int i;
12059243Sobrien
12169408Sache    /*
12269408Sache     * Make sure we have enough space to expand into.  E.g. we may have
12369408Sache     * "a|b" turn to "a | b" (from 3 to 5 characters) which is the worst
12469408Sache     * case scenario (even "a>&! b" turns into "a > & ! b", i.e. 6 to 9
12569408Sache     * characters -- am I missing any other cases?).
12669408Sache     */
12769408Sache    bufsiz = bufsiz / 2;
12869408Sache
12959243Sobrien    buf[0] = '\0';
13059243Sobrien    prev_c = '\0';
13159243Sobrien    d = buf;
13259243Sobrien    e = &buf[bufsiz];		/* for bounds checking */
13359243Sobrien
13459243Sobrien    if (!sp0)
13559243Sobrien	return (buf);		/* null lex */
13659243Sobrien    if ((sp = sp0->next) == sp0)
13759243Sobrien	return (buf);		/* nada */
13859243Sobrien    if (sp == (sp0 = sp0->prev))
13959243Sobrien	return (buf);		/* nada */
14059243Sobrien
14159243Sobrien    for (i = 0; i < NCARGS; i++) {
14259243Sobrien	if ((i >= from) && (i <= to)) {	/* if in range */
14359243Sobrien	    for (s = sp->word; *s && d < e; s++) {
14459243Sobrien		/*
14559243Sobrien		 * bugfix by Michael Bloom: anything but the current history
14659243Sobrien		 * character {(PWP) and backslash} seem to be dealt with
14759243Sobrien		 * elsewhere.
14859243Sobrien		 */
14959243Sobrien		if ((*s & QUOTE)
15059243Sobrien		    && (((*s & TRIM) == HIST) ||
15159243Sobrien			(((*s & TRIM) == '\'') && (prev_c != '\\')) ||
15259243Sobrien			(((*s & TRIM) == '\"') && (prev_c != '\\')) ||
15359243Sobrien			(((*s & TRIM) == '\\') && (prev_c != '\\')))) {
15459243Sobrien		    *d++ = '\\';
15559243Sobrien		}
15659243Sobrien		if (d < e)
15759243Sobrien		    *d++ = (*s & TRIM);
15859243Sobrien		prev_c = *s;
15959243Sobrien	    }
16059243Sobrien	    if (d < e)
16159243Sobrien		*d++ = ' ';
16259243Sobrien	}
16359243Sobrien	sp = sp->next;
16459243Sobrien	if (sp == sp0)
16559243Sobrien	    break;
16659243Sobrien    }
16759243Sobrien    if (d > buf)
16859243Sobrien	d--;			/* get rid of trailing space */
16959243Sobrien
17059243Sobrien    return (d);
17159243Sobrien}
17259243Sobrien
17359243SobrienChar   *
17459243Sobriensprlex(buf, bufsiz, sp0)
17559243Sobrien    Char   *buf;
17659243Sobrien    size_t  bufsiz;
17759243Sobrien    struct wordent *sp0;
17859243Sobrien{
17959243Sobrien    Char   *cp;
18059243Sobrien
18159243Sobrien    cp = expand_lex(buf, bufsiz, sp0, 0, NCARGS);
18259243Sobrien    *cp = '\0';
18359243Sobrien    return (buf);
18459243Sobrien}
18559243Sobrien
18659243Sobrien
18759243SobrienChar *
18859243SobrienItoa(n, s, min_digits, attributes)
18959243Sobrien    int n;
19059243Sobrien    Char *s;
19159243Sobrien    int min_digits, attributes;
19259243Sobrien{
19359243Sobrien    /*
19459243Sobrien     * The array size here is derived from
19559243Sobrien     *	log8(UINT_MAX)
19659243Sobrien     * which is guaranteed to be enough for a decimal
19759243Sobrien     * representation.  We add 1 because integer divide
19859243Sobrien     * rounds down.
19959243Sobrien     */
20059243Sobrien#ifndef CHAR_BIT
20159243Sobrien# define CHAR_BIT 8
20259243Sobrien#endif
20359243Sobrien    Char buf[CHAR_BIT * sizeof(int) / 3 + 1];
20459243Sobrien    Char *p;
20559243Sobrien    unsigned int un;	/* handle most negative # too */
20659243Sobrien    int pad = (min_digits != 0);
20759243Sobrien
20859243Sobrien    if (sizeof(buf) - 1 < min_digits)
20959243Sobrien	min_digits = sizeof(buf) - 1;
21059243Sobrien
21159243Sobrien    un = n;
21259243Sobrien    if (n < 0) {
21359243Sobrien	un = -n;
21459243Sobrien	*s++ = '-';
21559243Sobrien    }
21659243Sobrien
21759243Sobrien    p = buf;
21859243Sobrien    do {
21959243Sobrien	*p++ = un % 10 + '0';
22059243Sobrien	un /= 10;
22159243Sobrien    } while ((pad && --min_digits > 0) || un != 0);
22259243Sobrien
22359243Sobrien    while (p > buf)
22459243Sobrien	*s++ = *--p | attributes;
22559243Sobrien
22659243Sobrien    *s = '\0';
22759243Sobrien    return s;
22859243Sobrien}
22959243Sobrien
23059243Sobrien
23159243Sobrien/*ARGSUSED*/
23259243Sobrienvoid
23359243Sobriendolist(v, c)
23459243Sobrien    register Char **v;
23559243Sobrien    struct command *c;
23659243Sobrien{
23759243Sobrien    int     i, k;
23859243Sobrien    struct stat st;
23959243Sobrien#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
24059243Sobrien    extern bool dspmbyte_ls;
24159243Sobrien#endif
24259243Sobrien#ifdef COLOR_LS_F
24359243Sobrien    extern bool color_context_ls;
24459243Sobrien#endif /* COLOR_LS_F */
24559243Sobrien
24659243Sobrien    USE(c);
24759243Sobrien    if (*++v == NULL) {
24859243Sobrien	(void) t_search(STRNULL, NULL, LIST, 0, TW_ZERO, 0, STRNULL, 0);
24959243Sobrien	return;
25059243Sobrien    }
25159243Sobrien    gflag = 0;
25259243Sobrien    tglob(v);
25359243Sobrien    if (gflag) {
25459243Sobrien	v = globall(v);
25559243Sobrien	if (v == 0)
25659243Sobrien	    stderror(ERR_NAME | ERR_NOMATCH);
25759243Sobrien    }
25859243Sobrien    else
25959243Sobrien	v = gargv = saveblk(v);
26059243Sobrien    trim(v);
26159243Sobrien    for (k = 0; v[k] != NULL && v[k][0] != '-'; k++)
26259243Sobrien	continue;
26359243Sobrien    if (v[k]) {
26459243Sobrien	/*
26559243Sobrien	 * We cannot process a flag therefore we let ls do it right.
26659243Sobrien	 */
26759243Sobrien	static Char STRls[] = {'l', 's', '\0'};
26859243Sobrien	static Char STRmCF[] = {'-', 'C', 'F', '\0', '\0' };
26959243Sobrien	Char *lspath;
27059243Sobrien	struct command *t;
27159243Sobrien	struct wordent cmd, *nextword, *lastword;
27259243Sobrien	Char   *cp;
27359243Sobrien	struct varent *vp;
27459243Sobrien
27559243Sobrien#ifdef BSDSIGS
27659243Sobrien	sigmask_t omask = 0;
27759243Sobrien
27859243Sobrien	if (setintr)
27959243Sobrien	    omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT);
28059243Sobrien#else /* !BSDSIGS */
28159243Sobrien	(void) sighold(SIGINT);
28259243Sobrien#endif /* BSDSIGS */
28359243Sobrien	if (seterr) {
28459243Sobrien	    xfree((ptr_t) seterr);
28559243Sobrien	    seterr = NULL;
28659243Sobrien	}
28759243Sobrien
28859243Sobrien	lspath = STRls;
28959243Sobrien	STRmCF[1] = 'C';
29059243Sobrien	STRmCF[3] = '\0';
29159243Sobrien	/* Look at listflags, to add -A to the flags, to get a path
29259243Sobrien	   of ls if necessary */
29359243Sobrien	if ((vp = adrof(STRlistflags)) != NULL && vp->vec[0] != STRNULL) {
29459243Sobrien	    if (vp->vec[1] != NULL && vp->vec[1][0] != '\0')
29559243Sobrien		lspath = vp->vec[1];
29659243Sobrien	    for (cp = vp->vec[0]; *cp; cp++)
29759243Sobrien		switch (*cp) {
29859243Sobrien		case 'x':
29959243Sobrien		    STRmCF[1] = 'x';
30059243Sobrien		    break;
30159243Sobrien		case 'a':
30259243Sobrien		    STRmCF[3] = 'a';
30359243Sobrien		    break;
30459243Sobrien		case 'A':
30559243Sobrien		    STRmCF[3] = 'A';
30659243Sobrien		    break;
30759243Sobrien		default:
30859243Sobrien		    break;
30959243Sobrien		}
31059243Sobrien	}
31159243Sobrien
31259243Sobrien	cmd.word = STRNULL;
31359243Sobrien	lastword = &cmd;
31459243Sobrien	nextword = (struct wordent *) xcalloc(1, sizeof cmd);
31559243Sobrien	nextword->word = Strsave(lspath);
31659243Sobrien	lastword->next = nextword;
31759243Sobrien	nextword->prev = lastword;
31859243Sobrien	lastword = nextword;
31959243Sobrien	nextword = (struct wordent *) xcalloc(1, sizeof cmd);
32059243Sobrien	nextword->word = Strsave(STRmCF);
32159243Sobrien	lastword->next = nextword;
32259243Sobrien	nextword->prev = lastword;
32359243Sobrien#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE)
32459243Sobrien	if (dspmbyte_ls) {
32559243Sobrien	    lastword = nextword;
32659243Sobrien	    nextword = (struct wordent *) xcalloc(1, sizeof cmd);
32759243Sobrien	    nextword->word = Strsave(STRmmliteral);
32859243Sobrien	    lastword->next = nextword;
32959243Sobrien	    nextword->prev = lastword;
33059243Sobrien	}
33159243Sobrien#endif
33259243Sobrien#ifdef COLOR_LS_F
33359243Sobrien	if (color_context_ls) {
33459243Sobrien	    lastword = nextword;
33559243Sobrien	    nextword = (struct wordent *) xcalloc(1, sizeof cmd);
33659243Sobrien	    nextword->word = Strsave(STRmmcolormauto);
33759243Sobrien	    lastword->next = nextword;
33859243Sobrien	    nextword->prev = lastword;
33959243Sobrien	}
34059243Sobrien#endif /* COLOR_LS_F */
34159243Sobrien	lastword = nextword;
34259243Sobrien	for (cp = *v; cp; cp = *++v) {
34359243Sobrien	    nextword = (struct wordent *) xcalloc(1, sizeof cmd);
34459243Sobrien	    nextword->word = Strsave(cp);
34559243Sobrien	    lastword->next = nextword;
34659243Sobrien	    nextword->prev = lastword;
34759243Sobrien	    lastword = nextword;
34859243Sobrien	}
34959243Sobrien	lastword->next = &cmd;
35059243Sobrien	cmd.prev = lastword;
35159243Sobrien
35259243Sobrien	/* build a syntax tree for the command. */
35359243Sobrien	t = syntax(cmd.next, &cmd, 0);
35459243Sobrien	if (seterr)
35559243Sobrien	    stderror(ERR_OLD);
35659243Sobrien	/* expand aliases like process() does */
35759243Sobrien	/* alias(&cmd); */
35859243Sobrien	/* execute the parse tree. */
35959243Sobrien	execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL);
36059243Sobrien	/* done. free the lex list and parse tree. */
36159243Sobrien	freelex(&cmd), freesyn(t);
36259243Sobrien	if (setintr)
36359243Sobrien#ifdef BSDSIGS
36459243Sobrien	    (void) sigsetmask(omask);
36559243Sobrien#else /* !BSDSIGS */
36659243Sobrien	    (void) sigrelse(SIGINT);
36759243Sobrien#endif /* BSDSIGS */
36859243Sobrien    }
36959243Sobrien    else {
37059243Sobrien	Char   *dp, *tmp, buf[MAXPATHLEN];
37159243Sobrien
37259243Sobrien	for (k = 0, i = 0; v[k] != NULL; k++) {
37359243Sobrien	    tmp = dnormalize(v[k], symlinks == SYM_IGNORE);
37459243Sobrien	    dp = &tmp[Strlen(tmp) - 1];
37559243Sobrien	    if (*dp == '/' && dp != tmp)
37659243Sobrien#ifdef apollo
37759243Sobrien		if (dp != &tmp[1])
37859243Sobrien#endif /* apollo */
37959243Sobrien		*dp = '\0';
38059243Sobrien		if (stat(short2str(tmp), &st) == -1) {
38159243Sobrien		if (k != i) {
38259243Sobrien		    if (i != 0)
38359243Sobrien			xputchar('\n');
38459243Sobrien		    print_by_column(STRNULL, &v[i], k - i, FALSE);
38559243Sobrien		}
38659243Sobrien		xprintf("%S: %s.\n", tmp, strerror(errno));
38759243Sobrien		i = k + 1;
38859243Sobrien	    }
38959243Sobrien	    else if (S_ISDIR(st.st_mode)) {
39059243Sobrien		Char   *cp;
39159243Sobrien
39259243Sobrien		if (k != i) {
39359243Sobrien		    if (i != 0)
39459243Sobrien			xputchar('\n');
39559243Sobrien		    print_by_column(STRNULL, &v[i], k - i, FALSE);
39659243Sobrien		}
39759243Sobrien		if (k != 0 && v[1] != NULL)
39859243Sobrien		    xputchar('\n');
39959243Sobrien		xprintf("%S:\n", tmp);
40059243Sobrien		for (cp = tmp, dp = buf; *cp; *dp++ = (*cp++ | QUOTE))
40159243Sobrien		    continue;
40259243Sobrien		if (
40369408Sache#ifdef WINNT_NATIVE
40459243Sobrien		    (dp[-1] != (Char) (':' | QUOTE)) &&
40569408Sache#endif /* WINNT_NATIVE */
40659243Sobrien		    (dp[-1] != (Char) ('/' | QUOTE)))
40759243Sobrien		    *dp++ = '/';
40859243Sobrien		else
40959243Sobrien		    dp[-1] &= TRIM;
41059243Sobrien		*dp = '\0';
41159243Sobrien		(void) t_search(buf, NULL, LIST, 0, TW_ZERO, 0, STRNULL, 0);
41259243Sobrien		i = k + 1;
41359243Sobrien	    }
41459243Sobrien	    xfree((ptr_t) tmp);
41559243Sobrien	}
41659243Sobrien	if (k != i) {
41759243Sobrien	    if (i != 0)
41859243Sobrien		xputchar('\n');
41959243Sobrien	    print_by_column(STRNULL, &v[i], k - i, FALSE);
42059243Sobrien	}
42159243Sobrien    }
42259243Sobrien
42359243Sobrien    if (gargv) {
42459243Sobrien	blkfree(gargv);
42559243Sobrien	gargv = 0;
42659243Sobrien    }
42759243Sobrien}
42859243Sobrien
42959243Sobrienstatic char *defaulttell = "ALL";
43059243Sobrienextern bool GotTermCaps;
43159243Sobrien
43259243Sobrien/*ARGSUSED*/
43359243Sobrienvoid
43459243Sobriendotelltc(v, c)
43559243Sobrien    register Char **v;
43659243Sobrien    struct command *c;
43759243Sobrien{
43859243Sobrien    USE(c);
43959243Sobrien    if (!GotTermCaps)
44059243Sobrien	GetTermCaps();
44159243Sobrien
44259243Sobrien    /*
44359243Sobrien     * Avoid a compiler bug on hpux 9.05
44459243Sobrien     * Writing the following as func(a ? b : c) breaks
44559243Sobrien     */
44659243Sobrien    if (v[1])
44759243Sobrien	TellTC(short2str(v[1]));
44859243Sobrien    else
44959243Sobrien	TellTC(defaulttell);
45059243Sobrien}
45159243Sobrien
45259243Sobrien/*ARGSUSED*/
45359243Sobrienvoid
45459243Sobriendoechotc(v, c)
45559243Sobrien    register Char **v;
45659243Sobrien    struct command *c;
45759243Sobrien{
45859243Sobrien    if (!GotTermCaps)
45959243Sobrien	GetTermCaps();
46059243Sobrien    EchoTC(++v);
46159243Sobrien}
46259243Sobrien
46359243Sobrien/*ARGSUSED*/
46459243Sobrienvoid
46559243Sobriendosettc(v, c)
46659243Sobrien    Char  **v;
46759243Sobrien    struct command *c;
46859243Sobrien{
46959243Sobrien    char    tv[2][BUFSIZE];
47059243Sobrien
47159243Sobrien    if (!GotTermCaps)
47259243Sobrien	GetTermCaps();
47359243Sobrien
47459243Sobrien    (void) strcpy(tv[0], short2str(v[1]));
47559243Sobrien    (void) strcpy(tv[1], short2str(v[2]));
47659243Sobrien    SetTC(tv[0], tv[1]);
47759243Sobrien}
47859243Sobrien
47959243Sobrien/* The dowhich() is by:
48059243Sobrien *  Andreas Luik <luik@isaak.isa.de>
48159243Sobrien *  I S A  GmbH - Informationssysteme fuer computerintegrierte Automatisierung
48259243Sobrien *  Azenberstr. 35
48359243Sobrien *  D-7000 Stuttgart 1
48459243Sobrien *  West-Germany
48559243Sobrien * Thanks!!
48659243Sobrien */
48759243Sobrienint
48859243Sobriencmd_expand(cmd, str)
48959243Sobrien    Char *cmd;
49059243Sobrien    Char *str;
49159243Sobrien{
49259243Sobrien    struct wordent lexp[3];
49359243Sobrien    struct varent *vp;
49459243Sobrien    int rv = TRUE;
49559243Sobrien
49659243Sobrien    lexp[0].next = &lexp[1];
49759243Sobrien    lexp[1].next = &lexp[2];
49859243Sobrien    lexp[2].next = &lexp[0];
49959243Sobrien
50059243Sobrien    lexp[0].prev = &lexp[2];
50159243Sobrien    lexp[1].prev = &lexp[0];
50259243Sobrien    lexp[2].prev = &lexp[1];
50359243Sobrien
50459243Sobrien    lexp[0].word = STRNULL;
50559243Sobrien    lexp[2].word = STRret;
50659243Sobrien
50759243Sobrien    if ((vp = adrof1(cmd, &aliases)) != NULL) {
50859243Sobrien	if (str == NULL) {
50959243Sobrien	    xprintf(CGETS(22, 1, "%S: \t aliased to "), cmd);
51059243Sobrien	    blkpr(vp->vec);
51159243Sobrien	    xputchar('\n');
51259243Sobrien	}
51359243Sobrien	else
51459243Sobrien	    blkexpand(vp->vec, str);
51559243Sobrien    }
51659243Sobrien    else {
51759243Sobrien	lexp[1].word = cmd;
51859243Sobrien	rv = tellmewhat(lexp, str);
51959243Sobrien    }
52059243Sobrien    return rv;
52159243Sobrien}
52259243Sobrien
52359243Sobrien
52459243Sobrien/*ARGSUSED*/
52559243Sobrienvoid
52659243Sobriendowhich(v, c)
52759243Sobrien    register Char **v;
52859243Sobrien    struct command *c;
52959243Sobrien{
53059243Sobrien    int rv = TRUE;
53159243Sobrien    USE(c);
53259243Sobrien
53359243Sobrien#ifdef notdef
53459243Sobrien    /*
53559243Sobrien     * We don't want to glob dowhich args because we lose quoteing
53659243Sobrien     * E.g. which \ls if ls is aliased will not work correctly if
53759243Sobrien     * we glob here.
53859243Sobrien     */
53959243Sobrien    gflag = 0, tglob(v);
54059243Sobrien    if (gflag) {
54159243Sobrien	v = globall(v);
54259243Sobrien	if (v == 0)
54359243Sobrien	    stderror(ERR_NAME | ERR_NOMATCH);
54459243Sobrien    }
54559243Sobrien    else {
54659243Sobrien	v = gargv = saveblk(v);
54759243Sobrien	trim(v);
54859243Sobrien    }
54959243Sobrien#endif
55059243Sobrien
55159243Sobrien    while (*++v)
55259243Sobrien	rv &= cmd_expand(*v, NULL);
55359243Sobrien
55459243Sobrien    if (!rv)
55559243Sobrien	set(STRstatus, Strsave(STR1), VAR_READWRITE);
55659243Sobrien
55759243Sobrien#ifdef notdef
55859243Sobrien    /* Again look at the comment above; since we don't glob, we don't free */
55959243Sobrien    if (gargv)
56059243Sobrien	blkfree(gargv), gargv = 0;
56159243Sobrien#endif
56259243Sobrien}
56359243Sobrien
56459243Sobrien/* PWP: a hack to start up your stopped editor on a single keystroke */
56559243Sobrien/* jbs - fixed hack so it worked :-) 3/28/89 */
56659243Sobrien
56759243Sobrienstruct process *
56859243Sobrienfind_stop_ed()
56959243Sobrien{
57059243Sobrien    register struct process *pp, *retp;
57159243Sobrien    register char *ep, *vp, *cp, *p;
57259243Sobrien    int     epl, vpl, pstatus;
57359243Sobrien
57459243Sobrien    if ((ep = getenv("EDITOR")) != NULL) {	/* if we have a value */
57559243Sobrien	if ((p = strrchr(ep, '/')) != NULL) 	/* if it has a path */
57659243Sobrien	    ep = p + 1;		/* then we want only the last part */
57759243Sobrien    }
57859243Sobrien    else
57959243Sobrien	ep = "ed";
58059243Sobrien
58159243Sobrien    if ((vp = getenv("VISUAL")) != NULL) {	/* if we have a value */
58259243Sobrien	if ((p = strrchr(vp, '/')) != NULL) 	/* and it has a path */
58359243Sobrien	    vp = p + 1;		/* then we want only the last part */
58459243Sobrien    }
58559243Sobrien    else
58659243Sobrien	vp = "vi";
58759243Sobrien
58859243Sobrien    for (vpl = 0; vp[vpl] && !Isspace(vp[vpl]); vpl++)
58959243Sobrien	continue;
59059243Sobrien    for (epl = 0; ep[epl] && !Isspace(ep[epl]); epl++)
59159243Sobrien	continue;
59259243Sobrien
59359243Sobrien    if (pcurrent == NULL)	/* see if we have any jobs */
59459243Sobrien	return NULL;		/* nope */
59559243Sobrien
59659243Sobrien    retp = NULL;
59759243Sobrien    for (pp = proclist.p_next; pp; pp = pp->p_next)
59859243Sobrien	if (pp->p_procid == pp->p_jobid) {
59959243Sobrien
60059243Sobrien	    /*
60159243Sobrien	     * Only foreground an edit session if it is suspended.  Some GUI
60259243Sobrien	     * editors have may be happily running in a separate window, no
60359243Sobrien	     * point in foregrounding these if they're already running - webb
60459243Sobrien	     */
60559243Sobrien	    pstatus = (int) (pp->p_flags & PALLSTATES);
60659243Sobrien	    if (pstatus != PINTERRUPTED && pstatus != PSTOPPED &&
60759243Sobrien		pstatus != PSIGNALED)
60859243Sobrien		continue;
60959243Sobrien
61059243Sobrien	    p = short2str(pp->p_command);
61159243Sobrien	    /* get the first word */
61259243Sobrien	    for (cp = p; *cp && !isspace((unsigned char) *cp); cp++)
61359243Sobrien		continue;
61459243Sobrien	    *cp = '\0';
61559243Sobrien
61659243Sobrien	    if ((cp = strrchr(p, '/')) != NULL)	/* and it has a path */
61759243Sobrien		cp = cp + 1;		/* then we want only the last part */
61859243Sobrien	    else
61959243Sobrien		cp = p;			/* else we get all of it */
62059243Sobrien
62159243Sobrien	    /* if we find either in the current name, fg it */
62259243Sobrien	    if (strncmp(ep, cp, (size_t) epl) == 0 ||
62359243Sobrien		strncmp(vp, cp, (size_t) vpl) == 0) {
62459243Sobrien
62559243Sobrien		/*
62659243Sobrien		 * If there is a choice, then choose the current process if
62759243Sobrien		 * available, or the previous process otherwise, or else
62859243Sobrien		 * anything will do - Robert Webb (robertw@mulga.cs.mu.oz.au).
62959243Sobrien		 */
63059243Sobrien		if (pp == pcurrent)
63159243Sobrien		    return pp;
63259243Sobrien		else if (retp == NULL || pp == pprevious)
63359243Sobrien		    retp = pp;
63459243Sobrien	    }
63559243Sobrien	}
63659243Sobrien
63759243Sobrien    return retp;		/* Will be NULL if we didn't find a job */
63859243Sobrien}
63959243Sobrien
64059243Sobrienvoid
64159243Sobrienfg_proc_entry(pp)
64259243Sobrien    register struct process *pp;
64359243Sobrien{
64459243Sobrien#ifdef BSDSIGS
64559243Sobrien    sigmask_t omask;
64659243Sobrien#endif
64759243Sobrien    jmp_buf_t osetexit;
64859243Sobrien    bool    ohaderr;
64959243Sobrien    Char    oGettingInput;
65059243Sobrien
65159243Sobrien    getexit(osetexit);
65259243Sobrien
65359243Sobrien#ifdef BSDSIGS
65459243Sobrien    omask = sigblock(sigmask(SIGINT));
65559243Sobrien#else
65659243Sobrien    (void) sighold(SIGINT);
65759243Sobrien#endif
65859243Sobrien    oGettingInput = GettingInput;
65959243Sobrien    GettingInput = 0;
66059243Sobrien
66159243Sobrien    ohaderr = haderr;		/* we need to ignore setting of haderr due to
66259243Sobrien				 * process getting stopped by a signal */
66359243Sobrien    if (setexit() == 0) {	/* come back here after pjwait */
66459243Sobrien	pendjob();
66559243Sobrien	(void) alarm(0);	/* No autologout */
66659243Sobrien	if (!pstart(pp, 1)) {
66759243Sobrien	    pp->p_procid = 0;
66859243Sobrien	    stderror(ERR_BADJOB, pp->p_command, strerror(errno));
66959243Sobrien	}
67059243Sobrien	pjwait(pp);
67159243Sobrien    }
67259243Sobrien    setalarm(1);		/* Autologout back on */
67359243Sobrien    resexit(osetexit);
67459243Sobrien    haderr = ohaderr;
67559243Sobrien    GettingInput = oGettingInput;
67659243Sobrien
67759243Sobrien#ifdef BSDSIGS
67859243Sobrien    (void) sigsetmask(omask);
67959243Sobrien#else /* !BSDSIGS */
68059243Sobrien    (void) sigrelse(SIGINT);
68159243Sobrien#endif /* BSDSIGS */
68259243Sobrien
68359243Sobrien}
68459243Sobrien
68559243Sobrienstatic char *
68659243Sobrienxgetpass(prm)
68759243Sobrien    char *prm;
68859243Sobrien{
68959243Sobrien    static char pass[PASSMAX + 1];
69059243Sobrien    int fd, i;
69159243Sobrien    signalfun_t sigint;
69259243Sobrien
69359243Sobrien    sigint = (signalfun_t) sigset(SIGINT, SIG_IGN);
69459243Sobrien    (void) Rawmode();	/* Make sure, cause we want echo off */
69559243Sobrien    if ((fd = open("/dev/tty", O_RDWR)) == -1)
69659243Sobrien	fd = SHIN;
69759243Sobrien
69859243Sobrien    xprintf("%s", prm); flush();
69959243Sobrien    for (i = 0;;)  {
70059243Sobrien	if (read(fd, &pass[i], 1) < 1 || pass[i] == '\n')
70159243Sobrien	    break;
70259243Sobrien	if (i < PASSMAX)
70359243Sobrien	    i++;
70459243Sobrien    }
70559243Sobrien
70659243Sobrien    pass[i] = '\0';
70759243Sobrien
70859243Sobrien    if (fd != SHIN)
70959243Sobrien	(void) close(fd);
71059243Sobrien    (void) sigset(SIGINT, sigint);
71159243Sobrien
71259243Sobrien    return(pass);
71359243Sobrien}
71459243Sobrien
71559243Sobrien/*
71659243Sobrien * Ask the user for his login password to continue working
71759243Sobrien * On systems that have a shadow password, this will only
71859243Sobrien * work for root, but what can we do?
71959243Sobrien *
72059243Sobrien * If we fail to get the password, then we log the user out
72159243Sobrien * immediately
72259243Sobrien */
72359243Sobrien/*ARGSUSED*/
72459243Sobrienstatic void
72559243Sobrienauto_lock(n)
72659243Sobrien	int n;
72759243Sobrien{
72859243Sobrien#ifndef NO_CRYPT
72959243Sobrien
73059243Sobrien    int i;
73159243Sobrien    char *srpp = NULL;
73259243Sobrien    struct passwd *pw;
73359243Sobrien#ifdef POSIX
73459243Sobrien    extern char *crypt __P((const char *, const char *));
73559243Sobrien#else
73659243Sobrien    extern char *crypt __P(());
73759243Sobrien#endif
73859243Sobrien
73959243Sobrien#undef XCRYPT
74059243Sobrien
74159243Sobrien#if defined(PW_AUTH) && !defined(XCRYPT)
74259243Sobrien
74359243Sobrien    struct authorization *apw;
74459243Sobrien    extern char *crypt16 __P((const char *, const char *));
74559243Sobrien
74659243Sobrien# define XCRYPT(a, b) crypt16(a, b)
74759243Sobrien
74859243Sobrien    if ((pw = getpwuid(euid)) != NULL &&	/* effective user passwd  */
74959243Sobrien        (apw = getauthuid(euid)) != NULL) 	/* enhanced ultrix passwd */
75059243Sobrien	srpp = apw->a_password;
75159243Sobrien
75259243Sobrien#endif /* PW_AUTH && !XCRYPT */
75359243Sobrien
75459243Sobrien#if defined(PW_SHADOW) && !defined(XCRYPT)
75559243Sobrien
75659243Sobrien    struct spwd *spw;
75759243Sobrien
75859243Sobrien# define XCRYPT(a, b) crypt(a, b)
75959243Sobrien
76059243Sobrien    if ((pw = getpwuid(euid)) != NULL &&	/* effective user passwd  */
76159243Sobrien	(spw = getspnam(pw->pw_name)) != NULL)	/* shadowed passwd	  */
76259243Sobrien	srpp = spw->sp_pwdp;
76359243Sobrien
76459243Sobrien#endif /* PW_SHADOW && !XCRYPT */
76559243Sobrien
76659243Sobrien#ifndef XCRYPT
76759243Sobrien
76859243Sobrien#define XCRYPT(a, b) crypt(a, b)
76959243Sobrien
77069408Sache#if !defined(__MVS__)
77159243Sobrien    if ((pw = getpwuid(euid)) != NULL)	/* effective user passwd  */
77259243Sobrien	srpp = pw->pw_passwd;
77369408Sache#endif /* !MVS */
77459243Sobrien
77559243Sobrien#endif /* !XCRYPT */
77659243Sobrien
77759243Sobrien    if (srpp == NULL) {
77859243Sobrien	auto_logout(0);
77959243Sobrien	/*NOTREACHED*/
78059243Sobrien	return;
78159243Sobrien    }
78259243Sobrien
78359243Sobrien    setalarm(0);		/* Not for locking any more */
78459243Sobrien#ifdef BSDSIGS
78559243Sobrien    (void) sigsetmask(sigblock(0) & ~(sigmask(SIGALRM)));
78659243Sobrien#else /* !BSDSIGS */
78759243Sobrien    (void) sigrelse(SIGALRM);
78859243Sobrien#endif /* BSDSIGS */
78959243Sobrien    xputchar('\n');
79059243Sobrien    for (i = 0; i < 5; i++) {
79159243Sobrien	const char *crpp;
79259243Sobrien	char *pp;
79359243Sobrien#ifdef AFS
79459243Sobrien	char *afsname;
79559243Sobrien	Char *safs;
79659243Sobrien
79759243Sobrien	if ((safs = varval(STRafsuser)) != STRNULL)
79859243Sobrien	    afsname = short2str(safs);
79959243Sobrien	else
80059243Sobrien	    if ((afsname = getenv("AFSUSER")) == NULL)
80159243Sobrien	        afsname = pw->pw_name;
80259243Sobrien#endif
80359243Sobrien	pp = xgetpass("Password:");
80459243Sobrien
80559243Sobrien	crpp = XCRYPT(pp, srpp);
80659243Sobrien	if ((strcmp(crpp, srpp) == 0)
80759243Sobrien#ifdef AFS
80859243Sobrien	    || (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION,
80959243Sobrien					   afsname,     /* name */
81059243Sobrien					   NULL,        /* instance */
81159243Sobrien					   NULL,        /* realm */
81259243Sobrien					   pp,          /* password */
81359243Sobrien					   0,           /* lifetime */
81459243Sobrien					   0, 0,         /* spare */
81559243Sobrien					   NULL)        /* reason */
81659243Sobrien	    == 0)
81759243Sobrien#endif /* AFS */
81859243Sobrien	    ) {
81959243Sobrien	    (void) memset(pp, 0, PASSMAX);
82059243Sobrien	    if (GettingInput && !just_signaled) {
82159243Sobrien		(void) Rawmode();
82259243Sobrien		ClearLines();
82359243Sobrien		ClearDisp();
82459243Sobrien		Refresh();
82559243Sobrien	    }
82659243Sobrien	    just_signaled = 0;
82759243Sobrien	    return;
82859243Sobrien	}
82959243Sobrien	xprintf(CGETS(22, 2, "\nIncorrect passwd for %s\n"), pw->pw_name);
83059243Sobrien    }
83159243Sobrien#endif /* NO_CRYPT */
83259243Sobrien    auto_logout(0);
83359243Sobrien    USE(n);
83459243Sobrien}
83559243Sobrien
83659243Sobrien
83759243Sobrienstatic void
83859243Sobrienauto_logout(n)
83959243Sobrien    int n;
84059243Sobrien{
84159243Sobrien    USE(n);
84259243Sobrien    xprintf("auto-logout\n");
84359243Sobrien    /* Don't leave the tty in raw mode */
84459243Sobrien    if (editing)
84559243Sobrien	(void) Cookedmode();
84659243Sobrien    (void) close(SHIN);
84759243Sobrien    set(STRlogout, Strsave(STRautomatic), VAR_READWRITE);
84859243Sobrien    child = 1;
84959243Sobrien#ifdef TESLA
85059243Sobrien    do_logout = 1;
85159243Sobrien#endif /* TESLA */
85259243Sobrien    GettingInput = FALSE; /* make flush() work to write hist files. Huber*/
85359243Sobrien    goodbye(NULL, NULL);
85459243Sobrien}
85559243Sobrien
85659243Sobriensigret_t
85759243Sobrien/*ARGSUSED*/
85859243Sobrienalrmcatch(snum)
85959243Sobrienint snum;
86059243Sobrien{
86159243Sobrien#ifdef UNRELSIGS
86259243Sobrien    if (snum)
86359243Sobrien	(void) sigset(SIGALRM, alrmcatch);
86459243Sobrien#endif /* UNRELSIGS */
86559243Sobrien
86659243Sobrien    (*alm_fun)(0);
86759243Sobrien
86859243Sobrien    setalarm(1);
86959243Sobrien#ifndef SIGVOID
87059243Sobrien    return (snum);
87159243Sobrien#endif /* !SIGVOID */
87259243Sobrien}
87359243Sobrien
87459243Sobrien/*
87559243Sobrien * Karl Kleinpaste, 21oct1983.
87659243Sobrien * Added precmd(), which checks for the alias
87759243Sobrien * precmd in aliases.  If it's there, the alias
87859243Sobrien * is executed as a command.  This is done
87959243Sobrien * after mailchk() and just before print-
88059243Sobrien * ing the prompt.  Useful for things like printing
88159243Sobrien * one's current directory just before each command.
88259243Sobrien */
88359243Sobrienvoid
88459243Sobrienprecmd()
88559243Sobrien{
88659243Sobrien#ifdef BSDSIGS
88759243Sobrien    sigmask_t omask;
88859243Sobrien
88959243Sobrien    omask = sigblock(sigmask(SIGINT));
89059243Sobrien#else /* !BSDSIGS */
89159243Sobrien    (void) sighold(SIGINT);
89259243Sobrien#endif /* BSDSIGS */
89359243Sobrien    if (precmd_active) {	/* an error must have been caught */
89459243Sobrien	aliasrun(2, STRunalias, STRprecmd);
89559243Sobrien	xprintf(CGETS(22, 3, "Faulty alias 'precmd' removed.\n"));
89659243Sobrien	goto leave;
89759243Sobrien    }
89859243Sobrien    precmd_active = 1;
89959243Sobrien    if (!whyles && adrof1(STRprecmd, &aliases))
90059243Sobrien	aliasrun(1, STRprecmd, NULL);
90159243Sobrienleave:
90259243Sobrien    precmd_active = 0;
90359243Sobrien#ifdef BSDSIGS
90459243Sobrien    (void) sigsetmask(omask);
90559243Sobrien#else /* !BSDSIGS */
90659243Sobrien    (void) sigrelse(SIGINT);
90759243Sobrien#endif /* BSDSIGS */
90859243Sobrien}
90959243Sobrien
91059243Sobrienvoid
91159243Sobrienpostcmd()
91259243Sobrien{
91359243Sobrien#ifdef BSDSIGS
91459243Sobrien    sigmask_t omask;
91559243Sobrien
91659243Sobrien    omask = sigblock(sigmask(SIGINT));
91759243Sobrien#else /* !BSDSIGS */
91859243Sobrien    (void) sighold(SIGINT);
91959243Sobrien#endif /* BSDSIGS */
92059243Sobrien    if (postcmd_active) {	/* an error must have been caught */
92159243Sobrien	aliasrun(2, STRunalias, STRpostcmd);
92259243Sobrien	xprintf(CGETS(22, 3, "Faulty alias 'postcmd' removed.\n"));
92359243Sobrien	goto leave;
92459243Sobrien    }
92559243Sobrien    postcmd_active = 1;
92659243Sobrien    if (!whyles && adrof1(STRpostcmd, &aliases))
92759243Sobrien	aliasrun(1, STRpostcmd, NULL);
92859243Sobrienleave:
92959243Sobrien    postcmd_active = 0;
93059243Sobrien#ifdef BSDSIGS
93159243Sobrien    (void) sigsetmask(omask);
93259243Sobrien#else /* !BSDSIGS */
93359243Sobrien    (void) sigrelse(SIGINT);
93459243Sobrien#endif /* BSDSIGS */
93559243Sobrien}
93659243Sobrien
93759243Sobrien/*
93859243Sobrien * Paul Placeway  11/24/87  Added cwd_cmd by hacking precmd() into
93959243Sobrien * submission...  Run every time $cwd is set (after it is set).  Useful
94059243Sobrien * for putting your machine and cwd (or anything else) in an xterm title
94159243Sobrien * space.
94259243Sobrien */
94359243Sobrienvoid
94459243Sobriencwd_cmd()
94559243Sobrien{
94659243Sobrien#ifdef BSDSIGS
94759243Sobrien    sigmask_t omask;
94859243Sobrien
94959243Sobrien    omask = sigblock(sigmask(SIGINT));
95059243Sobrien#else /* !BSDSIGS */
95159243Sobrien    (void) sighold(SIGINT);
95259243Sobrien#endif /* BSDSIGS */
95359243Sobrien    if (cwdcmd_active) {	/* an error must have been caught */
95459243Sobrien	aliasrun(2, STRunalias, STRcwdcmd);
95559243Sobrien	xprintf(CGETS(22, 4, "Faulty alias 'cwdcmd' removed.\n"));
95659243Sobrien	goto leave;
95759243Sobrien    }
95859243Sobrien    cwdcmd_active = 1;
95959243Sobrien    if (!whyles && adrof1(STRcwdcmd, &aliases))
96059243Sobrien	aliasrun(1, STRcwdcmd, NULL);
96159243Sobrienleave:
96259243Sobrien    cwdcmd_active = 0;
96359243Sobrien#ifdef BSDSIGS
96459243Sobrien    (void) sigsetmask(omask);
96559243Sobrien#else /* !BSDSIGS */
96659243Sobrien    (void) sigrelse(SIGINT);
96759243Sobrien#endif /* BSDSIGS */
96859243Sobrien}
96959243Sobrien
97059243Sobrien/*
97159243Sobrien * Joachim Hoenig  07/16/91  Added beep_cmd, run every time tcsh wishes
97259243Sobrien * to beep the terminal bell. Useful for playing nice sounds instead.
97359243Sobrien */
97459243Sobrienvoid
97559243Sobrienbeep_cmd()
97659243Sobrien{
97759243Sobrien#ifdef BSDSIGS
97859243Sobrien    sigmask_t omask;
97959243Sobrien
98059243Sobrien    omask = sigblock(sigmask(SIGINT));
98159243Sobrien#else /* !BSDSIGS */
98259243Sobrien    (void) sighold(SIGINT);
98359243Sobrien#endif /* BSDSIGS */
98459243Sobrien    if (beepcmd_active) {	/* an error must have been caught */
98559243Sobrien	aliasrun(2, STRunalias, STRbeepcmd);
98659243Sobrien	xprintf(CGETS(22, 5, "Faulty alias 'beepcmd' removed.\n"));
98759243Sobrien    }
98859243Sobrien    else {
98959243Sobrien	beepcmd_active = 1;
99059243Sobrien	if (!whyles && adrof1(STRbeepcmd, &aliases))
99159243Sobrien	    aliasrun(1, STRbeepcmd, NULL);
99259243Sobrien    }
99359243Sobrien    beepcmd_active = 0;
99459243Sobrien#ifdef BSDSIGS
99559243Sobrien    (void) sigsetmask(omask);
99659243Sobrien#else /* !BSDSIGS */
99759243Sobrien    (void) sigrelse(SIGINT);
99859243Sobrien#endif /* BSDSIGS */
99959243Sobrien}
100059243Sobrien
100159243Sobrien
100259243Sobrien/*
100359243Sobrien * Karl Kleinpaste, 18 Jan 1984.
100459243Sobrien * Added period_cmd(), which executes the alias "periodic" every
100559243Sobrien * $tperiod minutes.  Useful for occasional checking of msgs and such.
100659243Sobrien */
100759243Sobrienvoid
100859243Sobrienperiod_cmd()
100959243Sobrien{
101059243Sobrien    register Char *vp;
101159243Sobrien    time_t  t, interval;
101259243Sobrien#ifdef BSDSIGS
101359243Sobrien    sigmask_t omask;
101459243Sobrien
101559243Sobrien    omask = sigblock(sigmask(SIGINT));
101659243Sobrien#else /* !BSDSIGS */
101759243Sobrien    (void) sighold(SIGINT);
101859243Sobrien#endif /* BSDSIGS */
101959243Sobrien    if (periodic_active) {	/* an error must have been caught */
102059243Sobrien	aliasrun(2, STRunalias, STRperiodic);
102159243Sobrien	xprintf(CGETS(22, 6, "Faulty alias 'periodic' removed.\n"));
102259243Sobrien	goto leave;
102359243Sobrien    }
102459243Sobrien    periodic_active = 1;
102559243Sobrien    if (!whyles && adrof1(STRperiodic, &aliases)) {
102659243Sobrien	vp = varval(STRtperiod);
102759243Sobrien	if (vp == STRNULL) {
102859243Sobrien	    aliasrun(1, STRperiodic, NULL);
102959243Sobrien	    goto leave;
103059243Sobrien	}
103159243Sobrien	interval = getn(vp);
103259243Sobrien	(void) time(&t);
103359243Sobrien	if (t - t_period >= interval * 60) {
103459243Sobrien	    t_period = t;
103559243Sobrien	    aliasrun(1, STRperiodic, NULL);
103659243Sobrien	}
103759243Sobrien    }
103859243Sobrienleave:
103959243Sobrien    periodic_active = 0;
104059243Sobrien#ifdef BSDSIGS
104159243Sobrien    (void) sigsetmask(omask);
104259243Sobrien#else /* !BSDSIGS */
104359243Sobrien    (void) sigrelse(SIGINT);
104459243Sobrien#endif /* BSDSIGS */
104559243Sobrien}
104659243Sobrien
104783098Smp
104883098Smp/*
104983098Smp * GrP Greg Parker May 2001
105083098Smp * Added job_cmd(), which is run every time a job is started or
105183098Smp * foregrounded. The command is passed a single argument, the string
105283098Smp * used to start the job originally. With precmd, useful for setting
105383098Smp * xterm titles.
105483098Smp * Cloned from cwd_cmd().
105583098Smp */
105683098Smpvoid
105783098Smpjob_cmd(args)
105883098Smp    Char *args;
105983098Smp{
106083098Smp#ifdef BSDSIGS
106183098Smp    sigmask_t omask;
106283098Smp
106383098Smp    omask = sigblock(sigmask(SIGINT));
106483098Smp#else /* !BSDSIGS */
106583098Smp    (void) sighold(SIGINT);
106683098Smp#endif /* BSDSIGS */
106783098Smp    if (jobcmd_active) {	/* an error must have been caught */
106883098Smp	aliasrun(2, STRunalias, STRjobcmd);
106983098Smp	xprintf(CGETS(22, 14, "Faulty alias 'jobcmd' removed.\n"));
107083098Smp	goto leave;
107183098Smp    }
107283098Smp    jobcmd_active = 1;
107383098Smp    if (!whyles && adrof1(STRjobcmd, &aliases))
107483098Smp	aliasrun(2, STRjobcmd, args);
107583098Smpleave:
107683098Smp    jobcmd_active = 0;
107783098Smp#ifdef BSDSIGS
107883098Smp    (void) sigsetmask(omask);
107983098Smp#else /* !BSDSIGS */
108083098Smp    (void) sigrelse(SIGINT);
108183098Smp#endif /* BSDSIGS */
108283098Smp}
108383098Smp
108483098Smp
108559243Sobrien/*
108659243Sobrien * Karl Kleinpaste, 21oct1983.
108759243Sobrien * Set up a one-word alias command, for use for special things.
108859243Sobrien * This code is based on the mainline of process().
108959243Sobrien */
109059243Sobrienvoid
109159243Sobrienaliasrun(cnt, s1, s2)
109259243Sobrien    int     cnt;
109359243Sobrien    Char   *s1, *s2;
109459243Sobrien{
109559243Sobrien    struct wordent w, *new1, *new2;	/* for holding alias name */
109659243Sobrien    struct command *t = NULL;
109759243Sobrien    jmp_buf_t osetexit;
109859243Sobrien    int status;
109959243Sobrien
110059243Sobrien    getexit(osetexit);
110159243Sobrien    if (seterr) {
110259243Sobrien	xfree((ptr_t) seterr);
110359243Sobrien	seterr = NULL;	/* don't repeatedly print err msg. */
110459243Sobrien    }
110559243Sobrien    w.word = STRNULL;
110659243Sobrien    new1 = (struct wordent *) xcalloc(1, sizeof w);
110759243Sobrien    new1->word = Strsave(s1);
110859243Sobrien    if (cnt == 1) {
110959243Sobrien	/* build a lex list with one word. */
111059243Sobrien	w.next = w.prev = new1;
111159243Sobrien	new1->next = new1->prev = &w;
111259243Sobrien    }
111359243Sobrien    else {
111459243Sobrien	/* build a lex list with two words. */
111559243Sobrien	new2 = (struct wordent *) xcalloc(1, sizeof w);
111659243Sobrien	new2->word = Strsave(s2);
111759243Sobrien	w.next = new2->prev = new1;
111859243Sobrien	new1->next = w.prev = new2;
111959243Sobrien	new1->prev = new2->next = &w;
112059243Sobrien    }
112159243Sobrien
112259243Sobrien    /* Save the old status */
112359243Sobrien    status = getn(varval(STRstatus));
112459243Sobrien
112559243Sobrien    /* expand aliases like process() does. */
112659243Sobrien    alias(&w);
112759243Sobrien    /* build a syntax tree for the command. */
112859243Sobrien    t = syntax(w.next, &w, 0);
112959243Sobrien    if (seterr)
113059243Sobrien	stderror(ERR_OLD);
113159243Sobrien
113259243Sobrien    psavejob();
113359243Sobrien
113459243Sobrien
113559243Sobrien    /* catch any errors here */
113659243Sobrien    if (setexit() == 0)
113759243Sobrien	/* execute the parse tree. */
113859243Sobrien	/*
113959243Sobrien	 * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de>
114059243Sobrien	 * was execute(t, tpgrp);
114159243Sobrien	 */
114259243Sobrien	execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL);
114359243Sobrien    /* done. free the lex list and parse tree. */
114459243Sobrien    freelex(&w), freesyn(t);
114559243Sobrien    if (haderr) {
114659243Sobrien	haderr = 0;
114759243Sobrien	/*
114859243Sobrien	 * Either precmd, or cwdcmd, or periodic had an error. Call it again so
114959243Sobrien	 * that it is removed
115059243Sobrien	 */
115159243Sobrien	if (precmd_active)
115259243Sobrien	    precmd();
115359243Sobrien	if (postcmd_active)
115459243Sobrien	    postcmd();
115559243Sobrien#ifdef notdef
115659243Sobrien	/*
115759243Sobrien	 * XXX: On the other hand, just interrupting them causes an error too.
115859243Sobrien	 * So if we hit ^C in the middle of cwdcmd or periodic the alias gets
115959243Sobrien	 * removed. We don't want that. Note that we want to remove precmd
116059243Sobrien	 * though, cause that could lead into an infinite loop. This should be
116159243Sobrien	 * fixed correctly, but then haderr should give us the whole exit
116259243Sobrien	 * status not just true or false.
116359243Sobrien	 */
116459243Sobrien	else if (cwdcmd_active)
116559243Sobrien	    cwd_cmd();
116659243Sobrien	else if (beepcmd_active)
116759243Sobrien	    beep_cmd();
116859243Sobrien	else if (periodic_active)
116959243Sobrien	    period_cmd();
117059243Sobrien#endif /* notdef */
117159243Sobrien    }
117259243Sobrien    /* reset the error catcher to the old place */
117359243Sobrien    resexit(osetexit);
117459243Sobrien    prestjob();
117559243Sobrien    pendjob();
117659243Sobrien    /* Restore status */
117759243Sobrien    set(STRstatus, putn(status), VAR_READWRITE);
117859243Sobrien}
117959243Sobrien
118059243Sobrienvoid
118159243Sobriensetalarm(lck)
118259243Sobrien    int lck;
118359243Sobrien{
118459243Sobrien    struct varent *vp;
118559243Sobrien    Char   *cp;
118659243Sobrien    unsigned alrm_time = 0, logout_time, lock_time;
118759243Sobrien    time_t cl, nl, sched_dif;
118859243Sobrien
118959243Sobrien    if ((vp = adrof(STRautologout)) != NULL) {
119059243Sobrien	if ((cp = vp->vec[0]) != 0) {
119159243Sobrien	    if ((logout_time = (unsigned) atoi(short2str(cp)) * 60) > 0) {
119259243Sobrien		alrm_time = logout_time;
119359243Sobrien		alm_fun = auto_logout;
119459243Sobrien	    }
119559243Sobrien	}
119659243Sobrien	if ((cp = vp->vec[1]) != 0) {
119759243Sobrien	    if ((lock_time = (unsigned) atoi(short2str(cp)) * 60) > 0) {
119859243Sobrien		if (lck) {
119959243Sobrien		    if (alrm_time == 0 || lock_time < alrm_time) {
120059243Sobrien			alrm_time = lock_time;
120159243Sobrien			alm_fun = auto_lock;
120259243Sobrien		    }
120359243Sobrien		}
120459243Sobrien		else /* lock_time always < alrm_time */
120559243Sobrien		    if (alrm_time)
120659243Sobrien			alrm_time -= lock_time;
120759243Sobrien	    }
120859243Sobrien	}
120959243Sobrien    }
121059243Sobrien    if ((nl = sched_next()) != -1) {
121159243Sobrien	(void) time(&cl);
121259243Sobrien	sched_dif = nl > cl ? nl - cl : 0;
121359243Sobrien	if ((alrm_time == 0) || ((unsigned) sched_dif < alrm_time)) {
121459243Sobrien	    alrm_time = ((unsigned) sched_dif) + 1;
121559243Sobrien	    alm_fun = sched_run;
121659243Sobrien	}
121759243Sobrien    }
121859243Sobrien    (void) alarm(alrm_time);	/* Autologout ON */
121959243Sobrien}
122059243Sobrien
122159243Sobrien#undef RMDEBUG			/* For now... */
122259243Sobrien
122359243Sobrienvoid
122459243Sobrienrmstar(cp)
122559243Sobrien    struct wordent *cp;
122659243Sobrien{
122759243Sobrien    struct wordent *we, *args;
122859243Sobrien    register struct wordent *tmp, *del;
122959243Sobrien
123059243Sobrien#ifdef RMDEBUG
123159243Sobrien    static Char STRrmdebug[] = {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'};
123259243Sobrien    Char   *tag;
123359243Sobrien#endif /* RMDEBUG */
123459243Sobrien    Char   *charac;
123559243Sobrien    char    c;
123659243Sobrien    int     ask, doit, star = 0, silent = 0;
123759243Sobrien
123859243Sobrien    if (!adrof(STRrmstar))
123959243Sobrien	return;
124059243Sobrien#ifdef RMDEBUG
124159243Sobrien    tag = varval(STRrmdebug);
124259243Sobrien#endif /* RMDEBUG */
124359243Sobrien    we = cp->next;
124459243Sobrien    while (*we->word == ';' && we != cp)
124559243Sobrien	we = we->next;
124659243Sobrien    while (we != cp) {
124759243Sobrien#ifdef RMDEBUG
124859243Sobrien	if (*tag)
124959243Sobrien	    xprintf(CGETS(22, 7, "parsing command line\n"));
125059243Sobrien#endif /* RMDEBUG */
125159243Sobrien	if (!Strcmp(we->word, STRrm)) {
125259243Sobrien	    args = we->next;
125359243Sobrien	    ask = (*args->word != '-');
125459243Sobrien	    while (*args->word == '-' && !silent) {	/* check options */
125559243Sobrien		for (charac = (args->word + 1); *charac && !silent; charac++)
125659243Sobrien		    silent = (*charac == 'i' || *charac == 'f');
125759243Sobrien		args = args->next;
125859243Sobrien	    }
125959243Sobrien	    ask = (ask || (!ask && !silent));
126059243Sobrien	    if (ask) {
126159243Sobrien		for (; !star && *args->word != ';'
126259243Sobrien		     && args != cp; args = args->next)
126359243Sobrien		    if (!Strcmp(args->word, STRstar))
126459243Sobrien			star = 1;
126559243Sobrien		if (ask && star) {
126659243Sobrien		    xprintf(CGETS(22, 8,
126759243Sobrien			    "Do you really want to delete all files? [n/y] "));
126859243Sobrien		    flush();
126959243Sobrien		    (void) force_read(SHIN, &c, 1);
127059243Sobrien		    /*
127159243Sobrien		     * Perhaps we should use the yesexpr from the
127259243Sobrien		     * actual locale
127359243Sobrien		     */
127459243Sobrien		    doit = (strchr(CGETS(22, 14, "Yy"), c) != NULL);
127559243Sobrien		    while (c != '\n' && force_read(SHIN, &c, 1) == 1)
127659243Sobrien			continue;
127759243Sobrien		    if (!doit) {
127859243Sobrien			/* remove the command instead */
127959243Sobrien#ifdef RMDEBUG
128059243Sobrien			if (*tag)
128159243Sobrien			    xprintf(CGETS(22, 9,
128259243Sobrien				    "skipping deletion of files!\n"));
128359243Sobrien#endif /* RMDEBUG */
128459243Sobrien			for (tmp = we;
128559243Sobrien			     *tmp->word != '\n' &&
128659243Sobrien			     *tmp->word != ';' && tmp != cp;) {
128759243Sobrien			    tmp->prev->next = tmp->next;
128859243Sobrien			    tmp->next->prev = tmp->prev;
128959243Sobrien			    xfree((ptr_t) tmp->word);
129059243Sobrien			    del = tmp;
129159243Sobrien			    tmp = tmp->next;
129259243Sobrien			    xfree((ptr_t) del);
129359243Sobrien			}
129459243Sobrien			if (*tmp->word == ';') {
129559243Sobrien			    tmp->prev->next = tmp->next;
129659243Sobrien			    tmp->next->prev = tmp->prev;
129759243Sobrien			    xfree((ptr_t) tmp->word);
129859243Sobrien			    del = tmp;
129983098Smp			    tmp = tmp->next;
130059243Sobrien			    xfree((ptr_t) del);
130159243Sobrien			}
130283098Smp			we = tmp;
130383098Smp			continue;
130459243Sobrien		    }
130559243Sobrien		}
130659243Sobrien	    }
130759243Sobrien	}
130859243Sobrien	for (we = we->next;
130959243Sobrien	     *we->word != ';' && we != cp;
131059243Sobrien	     we = we->next)
131159243Sobrien	    continue;
131259243Sobrien	if (*we->word == ';')
131359243Sobrien	    we = we->next;
131459243Sobrien    }
131559243Sobrien#ifdef RMDEBUG
131659243Sobrien    if (*tag) {
131759243Sobrien	xprintf(CGETS(22, 10, "command line now is:\n"));
131859243Sobrien	for (we = cp->next; we != cp; we = we->next)
131959243Sobrien	    xprintf("%S ", we->word);
132059243Sobrien    }
132159243Sobrien#endif /* RMDEBUG */
132259243Sobrien    return;
132359243Sobrien}
132459243Sobrien
132559243Sobrien#ifdef BSDJOBS
132659243Sobrien/* Check if command is in continue list
132759243Sobrien   and do a "aliasing" if it exists as a job in background */
132859243Sobrien
132959243Sobrien#undef CNDEBUG			/* For now */
133059243Sobrienvoid
133159243Sobriencontinue_jobs(cp)
133259243Sobrien    struct wordent *cp;
133359243Sobrien{
133459243Sobrien    struct wordent *we;
133559243Sobrien    register struct process *pp, *np;
133659243Sobrien    Char   *cmd, *continue_list, *continue_args_list;
133759243Sobrien
133859243Sobrien#ifdef CNDEBUG
133959243Sobrien    Char   *tag;
134059243Sobrien    static Char STRcndebug[] =
134159243Sobrien    {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'};
134259243Sobrien#endif /* CNDEBUG */
134359243Sobrien    bool    in_cont_list, in_cont_arg_list;
134459243Sobrien
134559243Sobrien
134659243Sobrien#ifdef CNDEBUG
134759243Sobrien    tag = varval(STRcndebug);
134859243Sobrien#endif /* CNDEBUG */
134959243Sobrien    continue_list = varval(STRcontinue);
135059243Sobrien    continue_args_list = varval(STRcontinue_args);
135159243Sobrien    if (*continue_list == '\0' && *continue_args_list == '\0')
135259243Sobrien	return;
135359243Sobrien
135459243Sobrien    we = cp->next;
135559243Sobrien    while (*we->word == ';' && we != cp)
135659243Sobrien	we = we->next;
135759243Sobrien    while (we != cp) {
135859243Sobrien#ifdef CNDEBUG
135959243Sobrien	if (*tag)
136059243Sobrien	    xprintf(CGETS(22, 11, "parsing command line\n"));
136159243Sobrien#endif /* CNDEBUG */
136259243Sobrien	cmd = we->word;
136359243Sobrien	in_cont_list = inlist(continue_list, cmd);
136459243Sobrien	in_cont_arg_list = inlist(continue_args_list, cmd);
136559243Sobrien	if (in_cont_list || in_cont_arg_list) {
136659243Sobrien#ifdef CNDEBUG
136759243Sobrien	    if (*tag)
136859243Sobrien		xprintf(CGETS(22, 12, "in one of the lists\n"));
136959243Sobrien#endif /* CNDEBUG */
137059243Sobrien	    np = NULL;
137159243Sobrien	    for (pp = proclist.p_next; pp; pp = pp->p_next) {
137259243Sobrien		if (prefix(cmd, pp->p_command)) {
137359243Sobrien		    if (pp->p_index) {
137459243Sobrien			np = pp;
137559243Sobrien			break;
137659243Sobrien		    }
137759243Sobrien		}
137859243Sobrien	    }
137959243Sobrien	    if (np) {
138059243Sobrien		insert(we, in_cont_arg_list);
138159243Sobrien	    }
138259243Sobrien	}
138359243Sobrien	for (we = we->next;
138459243Sobrien	     *we->word != ';' && we != cp;
138559243Sobrien	     we = we->next)
138659243Sobrien	    continue;
138759243Sobrien	if (*we->word == ';')
138859243Sobrien	    we = we->next;
138959243Sobrien    }
139059243Sobrien#ifdef CNDEBUG
139159243Sobrien    if (*tag) {
139259243Sobrien	xprintf(CGETS(22, 13, "command line now is:\n"));
139359243Sobrien	for (we = cp->next; we != cp; we = we->next)
139459243Sobrien	    xprintf("%S ", we->word);
139559243Sobrien    }
139659243Sobrien#endif /* CNDEBUG */
139759243Sobrien    return;
139859243Sobrien}
139959243Sobrien
140059243Sobrien/* The actual "aliasing" of for backgrounds() is done here
140159243Sobrien   with the aid of insert_we().   */
140259243Sobrienstatic void
140359243Sobrieninsert(pl, file_args)
140459243Sobrien    struct wordent *pl;
140559243Sobrien    bool    file_args;
140659243Sobrien{
140759243Sobrien    struct wordent *now, *last;
140859243Sobrien    Char   *cmd, *bcmd, *cp1, *cp2;
140959243Sobrien    int     cmd_len;
141059243Sobrien    Char   *pause = STRunderpause;
141159243Sobrien    int     p_len = (int) Strlen(pause);
141259243Sobrien
141359243Sobrien    cmd_len = (int) Strlen(pl->word);
141459243Sobrien    cmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 1) * sizeof(Char)));
141559243Sobrien    (void) Strcpy(cmd, pl->word);
141659243Sobrien/* Do insertions at beginning, first replace command word */
141759243Sobrien
141859243Sobrien    if (file_args) {
141959243Sobrien	now = pl;
142059243Sobrien	xfree((ptr_t) now->word);
142159243Sobrien	now->word = (Char *) xcalloc(1, (size_t) (5 * sizeof(Char)));
142259243Sobrien	(void) Strcpy(now->word, STRecho);
142359243Sobrien
142459243Sobrien	now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
142559243Sobrien	now->word = (Char *) xcalloc(1, (size_t) (6 * sizeof(Char)));
142659243Sobrien	(void) Strcpy(now->word, STRbackqpwd);
142759243Sobrien	insert_we(now, pl);
142859243Sobrien
142959243Sobrien	for (last = now; *last->word != '\n' && *last->word != ';';
143059243Sobrien	     last = last->next)
143159243Sobrien	    continue;
143259243Sobrien
143359243Sobrien	now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
143459243Sobrien	now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
143559243Sobrien	(void) Strcpy(now->word, STRgt);
143659243Sobrien	insert_we(now, last->prev);
143759243Sobrien
143859243Sobrien	now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
143959243Sobrien	now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
144059243Sobrien	(void) Strcpy(now->word, STRbang);
144159243Sobrien	insert_we(now, last->prev);
144259243Sobrien
144359243Sobrien	now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
144459243Sobrien	now->word = (Char *) xcalloc(1, (size_t) cmd_len + p_len + 4);
144559243Sobrien	cp1 = now->word;
144659243Sobrien	cp2 = cmd;
144759243Sobrien	*cp1++ = '~';
144859243Sobrien	*cp1++ = '/';
144959243Sobrien	*cp1++ = '.';
145059243Sobrien	while ((*cp1++ = *cp2++) != '\0')
145159243Sobrien	    continue;
145259243Sobrien	cp1--;
145359243Sobrien	cp2 = pause;
145459243Sobrien	while ((*cp1++ = *cp2++) != '\0')
145559243Sobrien	    continue;
145659243Sobrien	insert_we(now, last->prev);
145759243Sobrien
145859243Sobrien	now = (struct wordent *) xcalloc(1, (size_t) sizeof(struct wordent));
145959243Sobrien	now->word = (Char *) xcalloc(1, (size_t) (2 * sizeof(Char)));
146059243Sobrien	(void) Strcpy(now->word, STRsemi);
146159243Sobrien	insert_we(now, last->prev);
146259243Sobrien	bcmd = (Char *) xcalloc(1, (size_t) ((cmd_len + 2) * sizeof(Char)));
146359243Sobrien	cp1 = bcmd;
146459243Sobrien	cp2 = cmd;
146559243Sobrien	*cp1++ = '%';
146659243Sobrien	while ((*cp1++ = *cp2++) != '\0')
146759243Sobrien	    continue;
146859243Sobrien	now = (struct wordent *) xcalloc(1, (size_t) (sizeof(struct wordent)));
146959243Sobrien	now->word = bcmd;
147059243Sobrien	insert_we(now, last->prev);
147159243Sobrien    }
147259243Sobrien    else {
147359243Sobrien	struct wordent *del;
147459243Sobrien
147559243Sobrien	now = pl;
147659243Sobrien	xfree((ptr_t) now->word);
147759243Sobrien	now->word = (Char *) xcalloc(1,
147859243Sobrien				     (size_t) ((cmd_len + 2) * sizeof(Char)));
147959243Sobrien	cp1 = now->word;
148059243Sobrien	cp2 = cmd;
148159243Sobrien	*cp1++ = '%';
148259243Sobrien	while ((*cp1++ = *cp2++) != '\0')
148359243Sobrien	    continue;
148459243Sobrien	for (now = now->next;
148559243Sobrien	     *now->word != '\n' && *now->word != ';' && now != pl;) {
148659243Sobrien	    now->prev->next = now->next;
148759243Sobrien	    now->next->prev = now->prev;
148859243Sobrien	    xfree((ptr_t) now->word);
148959243Sobrien	    del = now;
149059243Sobrien	    now = now->next;
149159243Sobrien	    xfree((ptr_t) del);
149259243Sobrien	}
149359243Sobrien    }
149459243Sobrien}
149559243Sobrien
149659243Sobrienstatic void
149759243Sobrieninsert_we(new, where)
149859243Sobrien    struct wordent *new, *where;
149959243Sobrien{
150059243Sobrien
150159243Sobrien    new->prev = where;
150259243Sobrien    new->next = where->next;
150359243Sobrien    where->next = new;
150459243Sobrien    new->next->prev = new;
150559243Sobrien}
150659243Sobrien
150759243Sobrienstatic int
150859243Sobrieninlist(list, name)
150959243Sobrien    Char   *list, *name;
151059243Sobrien{
151159243Sobrien    register Char *l, *n;
151259243Sobrien
151359243Sobrien    l = list;
151459243Sobrien    n = name;
151559243Sobrien
151659243Sobrien    while (*l && *n) {
151759243Sobrien	if (*l == *n) {
151859243Sobrien	    l++;
151959243Sobrien	    n++;
152059243Sobrien	    if (*n == '\0' && (*l == ' ' || *l == '\0'))
152159243Sobrien		return (1);
152259243Sobrien	    else
152359243Sobrien		continue;
152459243Sobrien	}
152559243Sobrien	else {
152659243Sobrien	    while (*l && *l != ' ')
152759243Sobrien		l++;		/* skip to blank */
152859243Sobrien	    while (*l && *l == ' ')
152959243Sobrien		l++;		/* and find first nonblank character */
153059243Sobrien	    n = name;
153159243Sobrien	}
153259243Sobrien    }
153359243Sobrien    return (0);
153459243Sobrien}
153559243Sobrien
153659243Sobrien#endif /* BSDJOBS */
153759243Sobrien
153859243Sobrien
153959243Sobrien/*
154059243Sobrien * Implement a small cache for tilde names. This is used primarily
154159243Sobrien * to expand tilde names to directories, but also
154259243Sobrien * we can find users from their home directories for the tilde
154359243Sobrien * prompt, on machines where yp lookup is slow this can be a big win...
154459243Sobrien * As with any cache this can run out of sync, rehash can sync it again.
154559243Sobrien */
154659243Sobrienstatic struct tildecache {
154759243Sobrien    Char   *user;
154859243Sobrien    Char   *home;
154959243Sobrien    int     hlen;
155059243Sobrien}      *tcache = NULL;
155159243Sobrien
155259243Sobrien#define TILINCR 10
155359243Sobrienint tlength = 0;
155459243Sobrienstatic int tsize = TILINCR;
155559243Sobrien
155659243Sobrienstatic int
155759243Sobrientildecompare(p1, p2)
155859243Sobrien    struct tildecache *p1, *p2;
155959243Sobrien{
156059243Sobrien    return Strcmp(p1->user, p2->user);
156159243Sobrien}
156259243Sobrien
156359243Sobrienstatic Char *
156459243Sobriengethomedir(us)
156559243Sobrien    Char   *us;
156659243Sobrien{
156759243Sobrien    register struct passwd *pp;
156859243Sobrien#ifdef HESIOD
156959243Sobrien    char **res, **res1, *cp;
157059243Sobrien    Char *rp;
157159243Sobrien#endif /* HESIOD */
157259243Sobrien
157359243Sobrien    pp = getpwnam(short2str(us));
157459243Sobrien#ifdef YPBUGS
157559243Sobrien    fix_yp_bugs();
157659243Sobrien#endif /* YPBUGS */
157783098Smp    if (pp != NULL) {
157883098Smp	/* Don't return if root */
157983098Smp	if (pp->pw_dir[0] == '/' && pp->pw_dir[1] == '\0')
158083098Smp	    return NULL;
158183098Smp	else
158283098Smp	    return Strsave(str2short(pp->pw_dir));
158383098Smp    }
158459243Sobrien#ifdef HESIOD
158559243Sobrien    res = hes_resolve(short2str(us), "filsys");
158683098Smp    rp = NULL;
158783098Smp    if (res != NULL) {
158883098Smp	if ((*res) != NULL) {
158959243Sobrien	    /*
159059243Sobrien	     * Look at the first token to determine how to interpret
159159243Sobrien	     * the rest of it.
159259243Sobrien	     * Yes, strtok is evil (it's not thread-safe), but it's also
159359243Sobrien	     * easy to use.
159459243Sobrien	     */
159559243Sobrien	    cp = strtok(*res, " ");
159659243Sobrien	    if (strcmp(cp, "AFS") == 0) {
159759243Sobrien		/* next token is AFS pathname.. */
159859243Sobrien		cp = strtok(NULL, " ");
159959243Sobrien		if (cp != NULL)
160059243Sobrien		    rp = Strsave(str2short(cp));
160159243Sobrien	    } else if (strcmp(cp, "NFS") == 0) {
160259243Sobrien		cp = NULL;
160359243Sobrien		if ((strtok(NULL, " ")) && /* skip remote pathname */
160459243Sobrien		    (strtok(NULL, " ")) && /* skip host */
160559243Sobrien		    (strtok(NULL, " ")) && /* skip mode */
160659243Sobrien		    (cp = strtok(NULL, " "))) {
160759243Sobrien		    rp = Strsave(str2short(cp));
160859243Sobrien		}
160959243Sobrien	    }
161059243Sobrien	}
161159243Sobrien	for (res1 = res; *res1; res1++)
161259243Sobrien	    free(*res1);
161383098Smp	if (rp != NULL && rp[0] == '/' && rp[1] == '\0') {
161483098Smp	    xfree((ptr_t)rp);
161583098Smp	    rp = NULL;
161683098Smp	}
161759243Sobrien	return rp;
161859243Sobrien    }
161959243Sobrien#endif /* HESIOD */
162059243Sobrien    return NULL;
162159243Sobrien}
162259243Sobrien
162359243SobrienChar   *
162459243Sobriengettilde(us)
162559243Sobrien    Char   *us;
162659243Sobrien{
162759243Sobrien    struct tildecache *bp1, *bp2, *bp;
162859243Sobrien    Char *hd;
162959243Sobrien
163059243Sobrien    /* Ignore NIS special names */
163159243Sobrien    if (*us == '+' || *us == '-')
163259243Sobrien	return NULL;
163359243Sobrien
163459243Sobrien    if (tcache == NULL)
163559243Sobrien	tcache = (struct tildecache *) xmalloc((size_t) (TILINCR *
163659243Sobrien						  sizeof(struct tildecache)));
163759243Sobrien    /*
163859243Sobrien     * Binary search
163959243Sobrien     */
164059243Sobrien    for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) {
164159243Sobrien	register int i;
164259243Sobrien
164359243Sobrien	bp = bp1 + ((bp2 - bp1) >> 1);
164459243Sobrien	if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0)
164559243Sobrien	    return (bp->home);
164659243Sobrien	if (i < 0)
164759243Sobrien	    bp2 = bp;
164859243Sobrien	else
164959243Sobrien	    bp1 = bp + 1;
165059243Sobrien    }
165159243Sobrien    /*
165259243Sobrien     * Not in the cache, try to get it from the passwd file
165359243Sobrien     */
165459243Sobrien    hd = gethomedir(us);
165559243Sobrien    if (hd == NULL)
165659243Sobrien	return NULL;
165759243Sobrien
165859243Sobrien    /*
165959243Sobrien     * Update the cache
166059243Sobrien     */
166159243Sobrien    tcache[tlength].user = Strsave(us);
166259243Sobrien    tcache[tlength].home = hd;
166359243Sobrien    tcache[tlength++].hlen = (int) Strlen(hd);
166459243Sobrien
166559243Sobrien    qsort((ptr_t) tcache, (size_t) tlength, sizeof(struct tildecache),
166659243Sobrien	  (int (*) __P((const void *, const void *))) tildecompare);
166759243Sobrien
166859243Sobrien    if (tlength == tsize) {
166959243Sobrien	tsize += TILINCR;
167059243Sobrien	tcache = (struct tildecache *) xrealloc((ptr_t) tcache,
167159243Sobrien						(size_t) (tsize *
167259243Sobrien						  sizeof(struct tildecache)));
167359243Sobrien    }
167459243Sobrien    return (hd);
167559243Sobrien}
167659243Sobrien
167759243Sobrien/*
167859243Sobrien * Return the username if the directory path passed contains a
167959243Sobrien * user's home directory in the tilde cache, otherwise return NULL
168059243Sobrien * hm points to the place where the path became different.
168159243Sobrien * Special case: Our own home directory.
168259243Sobrien * If we are passed a null pointer, then we flush the cache.
168359243Sobrien */
168459243SobrienChar   *
168559243Sobriengetusername(hm)
168659243Sobrien    Char  **hm;
168759243Sobrien{
168859243Sobrien    Char   *h, *p;
168959243Sobrien    int     i, j;
169059243Sobrien
169159243Sobrien    if (hm == NULL) {
169259243Sobrien	for (i = 0; i < tlength; i++) {
169359243Sobrien	    xfree((ptr_t) tcache[i].home);
169459243Sobrien	    xfree((ptr_t) tcache[i].user);
169559243Sobrien	}
169659243Sobrien	xfree((ptr_t) tcache);
169759243Sobrien	tlength = 0;
169859243Sobrien	tsize = TILINCR;
169959243Sobrien	tcache = NULL;
170059243Sobrien	return NULL;
170159243Sobrien    }
170259243Sobrien    if (((h = varval(STRhome)) != STRNULL) &&
170359243Sobrien	(Strncmp(p = *hm, h, (size_t) (j = (int) Strlen(h))) == 0) &&
170459243Sobrien	(p[j] == '/' || p[j] == '\0')) {
170559243Sobrien	*hm = &p[j];
170659243Sobrien	return STRNULL;
170759243Sobrien    }
170859243Sobrien    for (i = 0; i < tlength; i++)
170959243Sobrien	if ((Strncmp(p = *hm, tcache[i].home, (size_t)
171059243Sobrien	    (j = tcache[i].hlen)) == 0) && (p[j] == '/' || p[j] == '\0')) {
171159243Sobrien	    *hm = &p[j];
171259243Sobrien	    return tcache[i].user;
171359243Sobrien	}
171459243Sobrien    return NULL;
171559243Sobrien}
171659243Sobrien
171759243Sobrien#ifdef OBSOLETE
171859243Sobrien/*
171959243Sobrien * PWP: read a bunch of aliases out of a file QUICKLY.  The format
172059243Sobrien *  is almost the same as the result of saying "alias > FILE", except
172159243Sobrien *  that saying "aliases > FILE" does not expand non-letters to printable
172259243Sobrien *  sequences.
172359243Sobrien */
172459243Sobrien/*ARGSUSED*/
172559243Sobrienvoid
172659243Sobriendoaliases(v, c)
172759243Sobrien    Char  **v;
172859243Sobrien    struct command *c;
172959243Sobrien{
173059243Sobrien    jmp_buf_t oldexit;
173159243Sobrien    Char  **vec, *lp;
173259243Sobrien    int     fd;
173359243Sobrien    Char    buf[BUFSIZE], line[BUFSIZE];
173459243Sobrien    char    tbuf[BUFSIZE + 1], *tmp;
173559243Sobrien    extern bool output_raw;	/* PWP: in sh.print.c */
173659243Sobrien
173759243Sobrien    USE(c);
173859243Sobrien    v++;
173959243Sobrien    if (*v == 0) {
174059243Sobrien	output_raw = 1;
174159243Sobrien	plist(&aliases, VAR_ALL);
174259243Sobrien	output_raw = 0;
174359243Sobrien	return;
174459243Sobrien    }
174559243Sobrien
174659243Sobrien    gflag = 0, tglob(v);
174759243Sobrien    if (gflag) {
174859243Sobrien	v = globall(v);
174959243Sobrien	if (v == 0)
175059243Sobrien	    stderror(ERR_NAME | ERR_NOMATCH);
175159243Sobrien    }
175259243Sobrien    else {
175359243Sobrien	v = gargv = saveblk(v);
175459243Sobrien	trim(v);
175559243Sobrien    }
175659243Sobrien
175759243Sobrien    if ((fd = open(tmp = short2str(*v), O_RDONLY)) < 0)
175859243Sobrien	stderror(ERR_NAME | ERR_SYSTEM, tmp, strerror(errno));
175959243Sobrien
176059243Sobrien    getexit(oldexit);
176159243Sobrien    if (setexit() == 0) {
176259243Sobrien	for (;;) {
176359243Sobrien	    Char   *p = NULL;
176459243Sobrien	    int     n = 0;
176559243Sobrien	    lp = line;
176659243Sobrien	    for (;;) {
176759243Sobrien		if (n <= 0) {
176859243Sobrien		    int     i;
176959243Sobrien
177059243Sobrien		    if ((n = read(fd, tbuf, BUFSIZE)) <= 0) {
177159243Sobrien#ifdef convex
177259243Sobrien			stderror(ERR_SYSTEM, progname, strerror(errno));
177359243Sobrien#endif /* convex */
177459243Sobrien			goto eof;
177559243Sobrien		    }
177659243Sobrien		    for (i = 0; i < n; i++)
177759243Sobrien  			buf[i] = (Char) tbuf[i];
177859243Sobrien		    p = buf;
177959243Sobrien		}
178059243Sobrien		n--;
178159243Sobrien		if ((*lp++ = *p++) == '\n') {
178259243Sobrien		    lp[-1] = '\0';
178359243Sobrien		    break;
178459243Sobrien		}
178559243Sobrien	    }
178659243Sobrien	    for (lp = line; *lp; lp++) {
178759243Sobrien		if (isspc(*lp)) {
178859243Sobrien		    *lp++ = '\0';
178959243Sobrien		    while (isspc(*lp))
179059243Sobrien			lp++;
179159243Sobrien		    vec = (Char **) xmalloc((size_t)
179259243Sobrien					    (2 * sizeof(Char **)));
179359243Sobrien		    vec[0] = Strsave(lp);
179459243Sobrien		    vec[1] = NULL;
179559243Sobrien		    setq(strip(line), vec, &aliases, VAR_READWRITE);
179659243Sobrien		    break;
179759243Sobrien		}
179859243Sobrien	    }
179959243Sobrien	}
180059243Sobrien    }
180159243Sobrien
180259243Sobrieneof:
180359243Sobrien    (void) close(fd);
180459243Sobrien    tw_cmd_free();
180559243Sobrien    if (gargv)
180659243Sobrien	blkfree(gargv), gargv = 0;
180759243Sobrien    resexit(oldexit);
180859243Sobrien}
180959243Sobrien#endif /* OBSOLETE */
181059243Sobrien
181159243Sobrien
181259243Sobrien/*
181359243Sobrien * set the shell-level var to 1 or apply change to it.
181459243Sobrien */
181559243Sobrienvoid
181659243Sobrienshlvl(val)
181759243Sobrien    int val;
181859243Sobrien{
181959243Sobrien    char *cp;
182059243Sobrien
182159243Sobrien    if ((cp = getenv("SHLVL")) != NULL) {
182259243Sobrien
182359243Sobrien	if (loginsh)
182459243Sobrien	    val = 1;
182559243Sobrien	else
182659243Sobrien	    val += atoi(cp);
182759243Sobrien
182859243Sobrien	if (val <= 0) {
182959243Sobrien	    if (adrof(STRshlvl) != NULL)
183059243Sobrien		unsetv(STRshlvl);
183159243Sobrien	    Unsetenv(STRKSHLVL);
183259243Sobrien	}
183359243Sobrien	else {
183459243Sobrien	    Char    buff[BUFSIZE];
183559243Sobrien
183659243Sobrien	    (void) Itoa(val, buff, 0, 0);
183759243Sobrien	    set(STRshlvl, Strsave(buff), VAR_READWRITE);
183859243Sobrien	    tsetenv(STRKSHLVL, buff);
183959243Sobrien	}
184059243Sobrien    }
184159243Sobrien    else {
184259243Sobrien	set(STRshlvl, SAVE("1"), VAR_READWRITE);
184359243Sobrien	tsetenv(STRKSHLVL, str2short("1"));
184459243Sobrien    }
184559243Sobrien}
184659243Sobrien
184759243Sobrien
184859243Sobrien/* fixio():
184959243Sobrien *	Try to recover from a read error
185059243Sobrien */
185159243Sobrienint
185259243Sobrienfixio(fd, e)
185359243Sobrien    int fd, e;
185459243Sobrien{
185559243Sobrien    switch (e) {
185659243Sobrien    case -1:	/* Make sure that the code is reachable */
185759243Sobrien
185859243Sobrien#ifdef EWOULDBLOCK
185959243Sobrien    case EWOULDBLOCK:
186059243Sobrien# define FDRETRY
186159243Sobrien#endif /* EWOULDBLOCK */
186259243Sobrien
186359243Sobrien#if defined(POSIX) && defined(EAGAIN)
186459243Sobrien# if !defined(EWOULDBLOCK) || EWOULDBLOCK != EAGAIN
186559243Sobrien    case EAGAIN:
186659243Sobrien#  define FDRETRY
186759243Sobrien# endif /* !EWOULDBLOCK || EWOULDBLOCK != EAGAIN */
186859243Sobrien#endif /* POSIX && EAGAIN */
186959243Sobrien
187059243Sobrien	e = 0;
187159243Sobrien#ifdef FDRETRY
187259243Sobrien# ifdef F_SETFL
187359243Sobrien/*
187459243Sobrien * Great! we have on suns 3 flavors and 5 names...
187559243Sobrien * I hope that will cover everything.
187659243Sobrien * I added some more defines... many systems have different defines.
187759243Sobrien * Rather than dealing with getting the right includes, we'll just
187859243Sobrien * cover all the known possibilities here.  -- sterling@netcom.com
187959243Sobrien */
188059243Sobrien#  ifndef O_NONBLOCK
188159243Sobrien#   define O_NONBLOCK 0
188259243Sobrien#  endif /* O_NONBLOCK */
188359243Sobrien#  ifndef O_NDELAY
188459243Sobrien#   define O_NDELAY 0
188559243Sobrien#  endif /* O_NDELAY */
188659243Sobrien#  ifndef FNBIO
188759243Sobrien#   define FNBIO 0
188859243Sobrien#  endif /* FNBIO */
188959243Sobrien#  ifndef _FNBIO
189059243Sobrien#   define _FNBIO 0
189159243Sobrien#  endif /* _FNBIO */
189259243Sobrien#  ifndef FNONBIO
189359243Sobrien#   define FNONBIO 0
189459243Sobrien#  endif /* FNONBIO */
189559243Sobrien#  ifndef FNONBLOCK
189659243Sobrien#   define FNONBLOCK 0
189759243Sobrien#  endif /* FNONBLOCK */
189859243Sobrien#  ifndef _FNONBLOCK
189959243Sobrien#   define _FNONBLOCK 0
190059243Sobrien#  endif /* _FNONBLOCK */
190159243Sobrien#  ifndef FNDELAY
190259243Sobrien#   define FNDELAY 0
190359243Sobrien#  endif /* FNDELAY */
190459243Sobrien#  ifndef _FNDELAY
190559243Sobrien#   define _FNDELAY 0
190659243Sobrien#  endif /* _FNDELAY */
190759243Sobrien#  ifndef FNDLEAY	/* Some linux versions have this typo */
190859243Sobrien#   define FNDLEAY 0
190959243Sobrien#  endif /* FNDLEAY */
191059243Sobrien	if ((e = fcntl(fd, F_GETFL, 0)) == -1)
191159243Sobrien	    return -1;
191259243Sobrien
191359243Sobrien	e &= ~(O_NDELAY|O_NONBLOCK|FNBIO|_FNBIO|FNONBIO|FNONBLOCK|_FNONBLOCK|
191459243Sobrien	       FNDELAY|_FNDELAY|FNDLEAY);	/* whew! */
191559243Sobrien	if (fcntl(fd, F_SETFL, e) == -1)
191659243Sobrien	    return -1;
191759243Sobrien	else
191859243Sobrien	    e = 1;
191959243Sobrien# endif /* F_SETFL */
192059243Sobrien
192159243Sobrien# ifdef FIONBIO
192259243Sobrien	e = 0;
192359243Sobrien	if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1)
192459243Sobrien	    return -1;
192559243Sobrien	else
192659243Sobrien	    e = 1;
192759243Sobrien# endif	/* FIONBIO */
192859243Sobrien
192959243Sobrien#endif /* FDRETRY */
193059243Sobrien	return e ? 0 : -1;
193159243Sobrien
193259243Sobrien    case EINTR:
193359243Sobrien	return 0;
193459243Sobrien
193559243Sobrien    default:
193659243Sobrien	return -1;
193759243Sobrien    }
193859243Sobrien}
193959243Sobrien
194059243Sobrien/* collate():
194159243Sobrien *	String collation
194259243Sobrien */
194359243Sobrienint
194459243Sobriencollate(a, b)
194559243Sobrien    const Char *a;
194659243Sobrien    const Char *b;
194759243Sobrien{
194859243Sobrien    int rv;
194959243Sobrien#ifdef SHORT_STRINGS
195059243Sobrien    /* This strips the quote bit as a side effect */
195159243Sobrien    char *sa = strsave(short2str(a));
195259243Sobrien    char *sb = strsave(short2str(b));
195359243Sobrien#else
195459243Sobrien    char *sa = strip(strsave(a));
195559243Sobrien    char *sb = strip(strsave(b));
195659243Sobrien#endif /* SHORT_STRINGS */
195759243Sobrien
195859243Sobrien#if defined(NLS) && !defined(NOSTRCOLL)
195959243Sobrien    errno = 0;	/* strcoll sets errno, another brain-damage */
196059243Sobrien
196159243Sobrien    rv = strcoll(sa, sb);
196259243Sobrien
196359243Sobrien    /*
196459243Sobrien     * We should be checking for errno != 0, but some systems
196559243Sobrien     * forget to reset errno to 0. So we only check for the
196659243Sobrien     * only documented valid errno value for strcoll [EINVAL]
196759243Sobrien     */
196859243Sobrien    if (errno == EINVAL) {
196959243Sobrien	xfree((ptr_t) sa);
197059243Sobrien	xfree((ptr_t) sb);
197159243Sobrien	stderror(ERR_SYSTEM, "strcoll", strerror(errno));
197259243Sobrien    }
197359243Sobrien#else
197459243Sobrien    rv = strcmp(sa, sb);
197559243Sobrien#endif /* NLS && !NOSTRCOLL */
197659243Sobrien
197759243Sobrien    xfree((ptr_t) sa);
197859243Sobrien    xfree((ptr_t) sb);
197959243Sobrien
198059243Sobrien    return rv;
198159243Sobrien}
198259243Sobrien
198359243Sobrien#ifdef HASHBANG
198459243Sobrien/*
198559243Sobrien * From: peter@zeus.dialix.oz.au (Peter Wemm)
198659243Sobrien * If exec() fails look first for a #! [word] [word] ....
198759243Sobrien * If it is, splice the header into the argument list and retry.
198859243Sobrien */
198959243Sobrien#define HACKBUFSZ 1024		/* Max chars in #! vector */
199059243Sobrien#define HACKVECSZ 128		/* Max words in #! vector */
199159243Sobrienint
199259243Sobrienhashbang(fd, vp)
199359243Sobrien    int fd;
199459243Sobrien    Char ***vp;
199559243Sobrien{
199659243Sobrien    unsigned char lbuf[HACKBUFSZ];
199759243Sobrien    char *sargv[HACKVECSZ];
199859243Sobrien    unsigned char *p, *ws;
199959243Sobrien    int sargc = 0;
200069408Sache#ifdef WINNT_NATIVE
200159243Sobrien    int fw = 0; 	/* found at least one word */
200259243Sobrien    int first_word = 0;
200369408Sache#endif /* WINNT_NATIVE */
200459243Sobrien
200559243Sobrien    if (read(fd, (char *) lbuf, HACKBUFSZ) <= 0)
200659243Sobrien	return -1;
200759243Sobrien
200859243Sobrien    ws = 0;	/* word started = 0 */
200959243Sobrien
201059243Sobrien    for (p = lbuf; p < &lbuf[HACKBUFSZ]; )
201159243Sobrien	switch (*p) {
201259243Sobrien	case ' ':
201359243Sobrien	case '\t':
201469408Sache#ifdef WINNT_NATIVE
201559243Sobrien	case '\r':
201669408Sache#endif /* WINNT_NATIVE */
201759243Sobrien	    if (ws) {	/* a blank after a word.. save it */
201859243Sobrien		*p = '\0';
201969408Sache#ifndef WINNT_NATIVE
202059243Sobrien		if (sargc < HACKVECSZ - 1)
202159243Sobrien		    sargv[sargc++] = ws;
202259243Sobrien		ws = NULL;
202369408Sache#else /* WINNT_NATIVE */
202459243Sobrien		if (sargc < HACKVECSZ - 1) {
202559243Sobrien		    sargv[sargc] = first_word ? NULL: hb_subst(ws);
202659243Sobrien		    if (sargv[sargc] == NULL)
202759243Sobrien			sargv[sargc] = ws;
202859243Sobrien		    sargc++;
202959243Sobrien		}
203059243Sobrien		ws = NULL;
203159243Sobrien	    	fw = 1;
203259243Sobrien		first_word = 1;
203369408Sache#endif /* WINNT_NATIVE */
203459243Sobrien	    }
203559243Sobrien	    p++;
203659243Sobrien	    continue;
203759243Sobrien
203859243Sobrien	case '\0':	/* Whoa!! what the hell happened */
203959243Sobrien	    return -1;
204059243Sobrien
204159243Sobrien	case '\n':	/* The end of the line. */
204259243Sobrien	    if (
204369408Sache#ifdef WINNT_NATIVE
204459243Sobrien		fw ||
204569408Sache#endif /* WINNT_NATIVE */
204659243Sobrien		ws) {	/* terminate the last word */
204759243Sobrien		*p = '\0';
204869408Sache#ifndef WINNT_NATIVE
204959243Sobrien		if (sargc < HACKVECSZ - 1)
205059243Sobrien		    sargv[sargc++] = ws;
205169408Sache#else /* WINNT_NATIVE */
205259243Sobrien		if (sargc < HACKVECSZ - 1) { /* deal with the 1-word case */
205359243Sobrien		    sargv[sargc] = first_word? NULL : hb_subst(ws);
205459243Sobrien		    if (sargv[sargc] == NULL)
205559243Sobrien			sargv[sargc] = ws;
205659243Sobrien		    sargc++;
205759243Sobrien		}
205869408Sache#endif /* !WINNT_NATIVE */
205959243Sobrien	    }
206059243Sobrien	    sargv[sargc] = NULL;
206159243Sobrien	    ws = NULL;
206259243Sobrien	    if (sargc > 0) {
206359243Sobrien		*vp = blk2short(sargv);
206459243Sobrien		return 0;
206559243Sobrien	    }
206659243Sobrien	    else
206759243Sobrien		return -1;
206859243Sobrien
206959243Sobrien	default:
207059243Sobrien	    if (!ws)	/* Start a new word? */
207159243Sobrien		ws = p;
207259243Sobrien	    p++;
207359243Sobrien	    break;
207459243Sobrien	}
207559243Sobrien    return -1;
207659243Sobrien}
207759243Sobrien#endif /* HASHBANG */
207859243Sobrien
207959243Sobrien#ifdef REMOTEHOST
208059243Sobrien
208159243Sobrienstatic sigret_t
208259243Sobrienpalarm(snum)
208359243Sobrien    int snum;
208459243Sobrien{
208559243Sobrien    USE(snum);
208659243Sobrien#ifdef UNRELSIGS
208759243Sobrien    if (snum)
208859243Sobrien	(void) sigset(snum, SIG_IGN);
208959243Sobrien#endif /* UNRELSIGS */
209059243Sobrien    (void) alarm(0);
209159243Sobrien    reset();
209259243Sobrien
209359243Sobrien#ifndef SIGVOID
209459243Sobrien    return (snum);
209559243Sobrien#endif
209659243Sobrien}
209759243Sobrien
209859243Sobrien
209959243Sobrienstatic void
210059243Sobriengetremotehost()
210159243Sobrien{
210259243Sobrien    const char *host = NULL;
210369408Sache#ifdef INET6
210469408Sache    struct sockaddr_storage saddr;
210569408Sache    int len = sizeof(struct sockaddr_storage);
210669408Sache    static char hbuf[NI_MAXHOST];
210769408Sache#else
210859243Sobrien    struct hostent* hp;
210959243Sobrien    struct sockaddr_in saddr;
211059243Sobrien    int len = sizeof(struct sockaddr_in);
211169408Sache#endif
211259243Sobrien#if defined(UTHOST) && !defined(HAVENOUTMP)
211359243Sobrien    char *sptr = NULL;
211459243Sobrien#endif
211559243Sobrien
211659243Sobrien    if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1) {
211769408Sache#ifdef INET6
211859243Sobrien#if 0
211969408Sache	int flag = 0;
212069408Sache#else
212169408Sache	int flag = NI_NUMERICHOST;
212269408Sache#endif
212369408Sache
212469408Sache#ifdef NI_WITHSCOPEID
212569408Sache	flag |= NI_WITHSCOPEID;
212669408Sache#endif
212769408Sache	getnameinfo((struct sockaddr *)&saddr, len, hbuf, sizeof(hbuf),
212869408Sache		    NULL, 0, flag);
212969408Sache	host = hbuf;
213069408Sache#else
213169408Sache#if 0
213259243Sobrien	if ((hp = gethostbyaddr((char *)&saddr.sin_addr, sizeof(struct in_addr),
213359243Sobrien				AF_INET)) != NULL)
213459243Sobrien	    host = hp->h_name;
213559243Sobrien	else
213659243Sobrien#endif
213759243Sobrien	    host = inet_ntoa(saddr.sin_addr);
213869408Sache#endif
213959243Sobrien    }
214059243Sobrien#if defined(UTHOST) && !defined(HAVENOUTMP)
214159243Sobrien    else {
214259243Sobrien	char *ptr;
214359243Sobrien	char *name = utmphost();
214459243Sobrien	/* Avoid empty names and local X displays */
214559243Sobrien	if (name != NULL && *name != '\0' && *name != ':') {
214669408Sache	    struct in_addr addr;
214769408Sache
214859243Sobrien	    /* Look for host:display.screen */
214969408Sache	    /*
215069408Sache	     * There is conflict with IPv6 address and X DISPLAY.  So,
215169408Sache	     * we assume there is no IPv6 address in utmp and don't
215269408Sache	     * touch here.
215369408Sache	     */
215459243Sobrien	    if ((sptr = strchr(name, ':')) != NULL)
215559243Sobrien		*sptr = '\0';
215669408Sache	    /* Leave IPv4 address as is */
215769408Sache	    /*
215869408Sache	     * we use inet_addr here, not inet_aton because many systems
215969408Sache	     * have not caught up yet.
216069408Sache	     */
216169408Sache	    addr.s_addr = inet_addr(name);
216269408Sache	    if (addr.s_addr != (unsigned long)~0)
216359243Sobrien		host = name;
216459243Sobrien	    else {
216559243Sobrien		if (sptr != name) {
216669408Sache#ifdef INET6
216769408Sache		    char *s, *domain;
216869408Sache		    char dbuf[MAXHOSTNAMELEN], cbuf[MAXHOSTNAMELEN];
216969408Sache		    struct addrinfo hints, *res = NULL;
217069408Sache
217169408Sache		    memset(&hints, 0, sizeof(hints));
217269408Sache		    hints.ai_family = PF_UNSPEC;
217369408Sache		    hints.ai_socktype = SOCK_STREAM;
217469408Sache		    hints.ai_flags = AI_PASSIVE | AI_CANONNAME;
217569408Sache#if defined(UTHOST) && !defined(HAVENOUTMP)
217669408Sache		    if (strlen(name) < utmphostsize())
217769408Sache#else
217869408Sache		    if (name != NULL)
217969408Sache#endif
218069408Sache		    {
218169408Sache			if (getaddrinfo(name, NULL, &hints, &res) != 0)
218269408Sache			    res = NULL;
218369408Sache		    } else if (gethostname(dbuf, sizeof(dbuf) - 1) == 0 &&
218469408Sache			       (domain = strchr(dbuf, '.')) != NULL) {
218569408Sache			for (s = strchr(name, '.');
218669408Sache			     s != NULL; s = strchr(s + 1, '.')) {
218769408Sache			    if (*(s + 1) != '\0' &&
218869408Sache				(ptr = strstr(domain, s)) != NULL) {
218969408Sache				len = s - name;
219069408Sache				if (len + strlen(ptr) >= sizeof(cbuf))
219169408Sache				    break;
219269408Sache				strncpy(cbuf, name, len);
219369408Sache				strcpy(cbuf + len, ptr);
219469408Sache				if (getaddrinfo(cbuf, NULL, &hints, &res) != 0)
219569408Sache				    res = NULL;
219669408Sache				break;
219769408Sache			    }
219869408Sache			}
219969408Sache		    }
220069408Sache		    if (res != NULL) {
220169408Sache			if (res->ai_canonname != NULL) {
220269408Sache			    strncpy(hbuf, res->ai_canonname, sizeof(hbuf));
220369408Sache			    host = hbuf;
220469408Sache			}
220569408Sache			freeaddrinfo(res);
220669408Sache		    }
220769408Sache#else
220859243Sobrien		    if ((hp = gethostbyname(name)) == NULL) {
220959243Sobrien			/* Try again eliminating the trailing domain */
221059243Sobrien			if ((ptr = strchr(name, '.')) != NULL) {
221159243Sobrien			    *ptr = '\0';
221259243Sobrien			    if ((hp = gethostbyname(name)) != NULL)
221359243Sobrien				host = hp->h_name;
221459243Sobrien			    *ptr = '.';
221559243Sobrien			}
221659243Sobrien		    }
221759243Sobrien		    else
221859243Sobrien			host = hp->h_name;
221969408Sache#endif
222059243Sobrien		}
222159243Sobrien	    }
222259243Sobrien	}
222359243Sobrien    }
222459243Sobrien#endif
222559243Sobrien
222659243Sobrien    if (host)
222759243Sobrien	tsetenv(STRREMOTEHOST, str2short(host));
222859243Sobrien
222959243Sobrien#if defined(UTHOST) && !defined(HAVENOUTMP)
223059243Sobrien    if (sptr)
223159243Sobrien	*sptr = ':';
223259243Sobrien#endif
223359243Sobrien}
223459243Sobrien
223559243Sobrien
223659243Sobrien/*
223759243Sobrien * From: <lesv@ppvku.ericsson.se> (Lennart Svensson)
223859243Sobrien */
223959243Sobrienvoid
224059243Sobrienremotehost()
224159243Sobrien{
224259243Sobrien    /* Don't get stuck if the resolver does not work! */
224359243Sobrien    signalfun_t osig = sigset(SIGALRM, palarm);
224459243Sobrien
224559243Sobrien    jmp_buf_t osetexit;
224659243Sobrien    getexit(osetexit);
224759243Sobrien
224859243Sobrien    (void) alarm(2);
224959243Sobrien
225059243Sobrien    if (setexit() == 0)
225159243Sobrien	getremotehost();
225259243Sobrien
225359243Sobrien    resexit(osetexit);
225459243Sobrien
225559243Sobrien    (void) alarm(0);
225659243Sobrien    (void) sigset(SIGALRM, osig);
225759243Sobrien
225859243Sobrien#ifdef YPBUGS
225959243Sobrien    /* From: casper@fwi.uva.nl (Casper H.S. Dik), for Solaris 2.3 */
226059243Sobrien    fix_yp_bugs();
226159243Sobrien#endif /* YPBUGS */
226259243Sobrien
226359243Sobrien}
226459243Sobrien#endif /* REMOTEHOST */
2265