1231990Smp/* $Header: /p/tcsh/cvsroot/tcsh/tc.func.c,v 3.148 2011/12/14 16:36: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. 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 35231990SmpRCSID("$tcsh: tc.func.c,v 3.148 2011/12/14 16:36:44 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) 121231990Smp && (((*s & TRIM) == HIST && HIST != '\0') || 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; 177231990Smp } while ((pad && (ssize_t)--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 674231990Smp# define XCRYPT(pw, 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 684231990Smp# define XCRYPT(pw, 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 699231990Smp#ifdef __CYGWIN__ 700231990Smp# define XCRYPT(pw, a, b) cygwin_xcrypt(pw, a, b) 701231990Smp#else 702231990Smp# define XCRYPT(pw, a, b) crypt(a, b) 703231990Smp#endif 704231990Smp 70569408Sache#if !defined(__MVS__) 706167465Smp if ((pw = xgetpwuid(euid)) != NULL) /* effective user passwd */ 70759243Sobrien srpp = pw->pw_passwd; 70869408Sache#endif /* !MVS */ 70959243Sobrien 710145479Smp#endif 71159243Sobrien 71259243Sobrien if (srpp == NULL) { 713167465Smp auto_logout(); 71459243Sobrien /*NOTREACHED*/ 71559243Sobrien return; 71659243Sobrien } 71759243Sobrien 71859243Sobrien setalarm(0); /* Not for locking any more */ 719167465Smp xputchar('\n'); 72059243Sobrien for (i = 0; i < 5; i++) { 72159243Sobrien const char *crpp; 72259243Sobrien char *pp; 72359243Sobrien#ifdef AFS 72459243Sobrien char *afsname; 72559243Sobrien Char *safs; 72659243Sobrien 72759243Sobrien if ((safs = varval(STRafsuser)) != STRNULL) 72859243Sobrien afsname = short2str(safs); 72959243Sobrien else 73059243Sobrien if ((afsname = getenv("AFSUSER")) == NULL) 73159243Sobrien afsname = pw->pw_name; 73259243Sobrien#endif 733167465Smp pp = xgetpass("Password:"); 73459243Sobrien 735231990Smp crpp = XCRYPT(pw, pp, srpp); 73659243Sobrien if ((strcmp(crpp, srpp) == 0) 73759243Sobrien#ifdef AFS 73859243Sobrien || (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, 73959243Sobrien afsname, /* name */ 74059243Sobrien NULL, /* instance */ 74159243Sobrien NULL, /* realm */ 74259243Sobrien pp, /* password */ 74359243Sobrien 0, /* lifetime */ 74459243Sobrien 0, 0, /* spare */ 74559243Sobrien NULL) /* reason */ 74659243Sobrien == 0) 74759243Sobrien#endif /* AFS */ 74859243Sobrien ) { 749167465Smp (void) memset(pp, 0, strlen(pp)); 75059243Sobrien if (GettingInput && !just_signaled) { 75159243Sobrien (void) Rawmode(); 752167465Smp ClearLines(); 753167465Smp ClearDisp(); 75459243Sobrien Refresh(); 75559243Sobrien } 75659243Sobrien just_signaled = 0; 75759243Sobrien return; 75859243Sobrien } 75959243Sobrien xprintf(CGETS(22, 2, "\nIncorrect passwd for %s\n"), pw->pw_name); 76059243Sobrien } 76159243Sobrien#endif /* NO_CRYPT */ 762167465Smp auto_logout(); 76359243Sobrien} 76459243Sobrien 76559243Sobrien 76659243Sobrienstatic void 767167465Smpauto_logout(void) 76859243Sobrien{ 76959243Sobrien xprintf("auto-logout\n"); 77059243Sobrien /* Don't leave the tty in raw mode */ 77159243Sobrien if (editing) 77259243Sobrien (void) Cookedmode(); 773167465Smp xclose(SHIN); 774167465Smp setcopy(STRlogout, STRautomatic, VAR_READWRITE); 77559243Sobrien child = 1; 77659243Sobrien#ifdef TESLA 77759243Sobrien do_logout = 1; 77859243Sobrien#endif /* TESLA */ 77959243Sobrien GettingInput = FALSE; /* make flush() work to write hist files. Huber*/ 78059243Sobrien goodbye(NULL, NULL); 78159243Sobrien} 78259243Sobrien 783167465Smpvoid 784167465Smpalrmcatch(void) 78559243Sobrien{ 786167465Smp (*alm_fun)(); 78759243Sobrien setalarm(1); 78859243Sobrien} 78959243Sobrien 79059243Sobrien/* 79159243Sobrien * Karl Kleinpaste, 21oct1983. 79259243Sobrien * Added precmd(), which checks for the alias 79359243Sobrien * precmd in aliases. If it's there, the alias 79459243Sobrien * is executed as a command. This is done 79559243Sobrien * after mailchk() and just before print- 79659243Sobrien * ing the prompt. Useful for things like printing 79759243Sobrien * one's current directory just before each command. 79859243Sobrien */ 79959243Sobrienvoid 800167465Smpprecmd(void) 80159243Sobrien{ 802167465Smp pintr_disabled++; 803167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 80459243Sobrien if (precmd_active) { /* an error must have been caught */ 80559243Sobrien aliasrun(2, STRunalias, STRprecmd); 806195609Smp xprintf("%s", CGETS(22, 3, "Faulty alias 'precmd' removed.\n")); 80759243Sobrien goto leave; 80859243Sobrien } 80959243Sobrien precmd_active = 1; 81059243Sobrien if (!whyles && adrof1(STRprecmd, &aliases)) 81159243Sobrien aliasrun(1, STRprecmd, NULL); 81259243Sobrienleave: 81359243Sobrien precmd_active = 0; 814167465Smp cleanup_until(&pintr_disabled); 81559243Sobrien} 81659243Sobrien 81759243Sobrienvoid 818167465Smppostcmd(void) 81959243Sobrien{ 820167465Smp pintr_disabled++; 821167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 82259243Sobrien if (postcmd_active) { /* an error must have been caught */ 82359243Sobrien aliasrun(2, STRunalias, STRpostcmd); 824195609Smp xprintf("%s", CGETS(22, 3, "Faulty alias 'postcmd' removed.\n")); 82559243Sobrien goto leave; 82659243Sobrien } 82759243Sobrien postcmd_active = 1; 82859243Sobrien if (!whyles && adrof1(STRpostcmd, &aliases)) 82959243Sobrien aliasrun(1, STRpostcmd, NULL); 83059243Sobrienleave: 83159243Sobrien postcmd_active = 0; 832167465Smp cleanup_until(&pintr_disabled); 83359243Sobrien} 83459243Sobrien 83559243Sobrien/* 83659243Sobrien * Paul Placeway 11/24/87 Added cwd_cmd by hacking precmd() into 83759243Sobrien * submission... Run every time $cwd is set (after it is set). Useful 83859243Sobrien * for putting your machine and cwd (or anything else) in an xterm title 83959243Sobrien * space. 84059243Sobrien */ 84159243Sobrienvoid 842167465Smpcwd_cmd(void) 84359243Sobrien{ 844167465Smp pintr_disabled++; 845167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 84659243Sobrien if (cwdcmd_active) { /* an error must have been caught */ 84759243Sobrien aliasrun(2, STRunalias, STRcwdcmd); 848195609Smp xprintf("%s", CGETS(22, 4, "Faulty alias 'cwdcmd' removed.\n")); 84959243Sobrien goto leave; 85059243Sobrien } 85159243Sobrien cwdcmd_active = 1; 85259243Sobrien if (!whyles && adrof1(STRcwdcmd, &aliases)) 85359243Sobrien aliasrun(1, STRcwdcmd, NULL); 85459243Sobrienleave: 85559243Sobrien cwdcmd_active = 0; 856167465Smp cleanup_until(&pintr_disabled); 85759243Sobrien} 85859243Sobrien 85959243Sobrien/* 86059243Sobrien * Joachim Hoenig 07/16/91 Added beep_cmd, run every time tcsh wishes 86159243Sobrien * to beep the terminal bell. Useful for playing nice sounds instead. 86259243Sobrien */ 86359243Sobrienvoid 864167465Smpbeep_cmd(void) 86559243Sobrien{ 866167465Smp pintr_disabled++; 867167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 86859243Sobrien if (beepcmd_active) { /* an error must have been caught */ 86959243Sobrien aliasrun(2, STRunalias, STRbeepcmd); 870195609Smp xprintf("%s", CGETS(22, 5, "Faulty alias 'beepcmd' removed.\n")); 87159243Sobrien } 87259243Sobrien else { 87359243Sobrien beepcmd_active = 1; 87459243Sobrien if (!whyles && adrof1(STRbeepcmd, &aliases)) 87559243Sobrien aliasrun(1, STRbeepcmd, NULL); 87659243Sobrien } 87759243Sobrien beepcmd_active = 0; 878167465Smp cleanup_until(&pintr_disabled); 87959243Sobrien} 88059243Sobrien 88159243Sobrien 88259243Sobrien/* 88359243Sobrien * Karl Kleinpaste, 18 Jan 1984. 88459243Sobrien * Added period_cmd(), which executes the alias "periodic" every 88559243Sobrien * $tperiod minutes. Useful for occasional checking of msgs and such. 88659243Sobrien */ 88759243Sobrienvoid 888167465Smpperiod_cmd(void) 88959243Sobrien{ 890145479Smp Char *vp; 89159243Sobrien time_t t, interval; 89259243Sobrien 893167465Smp pintr_disabled++; 894167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 89559243Sobrien if (periodic_active) { /* an error must have been caught */ 89659243Sobrien aliasrun(2, STRunalias, STRperiodic); 897195609Smp xprintf("%s", CGETS(22, 6, "Faulty alias 'periodic' removed.\n")); 89859243Sobrien goto leave; 89959243Sobrien } 90059243Sobrien periodic_active = 1; 90159243Sobrien if (!whyles && adrof1(STRperiodic, &aliases)) { 90259243Sobrien vp = varval(STRtperiod); 90359243Sobrien if (vp == STRNULL) { 90459243Sobrien aliasrun(1, STRperiodic, NULL); 90559243Sobrien goto leave; 90659243Sobrien } 90759243Sobrien interval = getn(vp); 90859243Sobrien (void) time(&t); 90959243Sobrien if (t - t_period >= interval * 60) { 91059243Sobrien t_period = t; 91159243Sobrien aliasrun(1, STRperiodic, NULL); 91259243Sobrien } 91359243Sobrien } 91459243Sobrienleave: 91559243Sobrien periodic_active = 0; 916167465Smp cleanup_until(&pintr_disabled); 91759243Sobrien} 91859243Sobrien 91983098Smp 92083098Smp/* 92183098Smp * GrP Greg Parker May 2001 92283098Smp * Added job_cmd(), which is run every time a job is started or 92383098Smp * foregrounded. The command is passed a single argument, the string 92483098Smp * used to start the job originally. With precmd, useful for setting 92583098Smp * xterm titles. 92683098Smp * Cloned from cwd_cmd(). 92783098Smp */ 92883098Smpvoid 929167465Smpjob_cmd(Char *args) 93083098Smp{ 931167465Smp pintr_disabled++; 932167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 93383098Smp if (jobcmd_active) { /* an error must have been caught */ 93483098Smp aliasrun(2, STRunalias, STRjobcmd); 935195609Smp xprintf("%s", CGETS(22, 14, "Faulty alias 'jobcmd' removed.\n")); 93683098Smp goto leave; 93783098Smp } 93883098Smp jobcmd_active = 1; 939100616Smp if (!whyles && adrof1(STRjobcmd, &aliases)) { 940100616Smp struct process *pp = pcurrjob; /* put things back after the hook */ 94183098Smp aliasrun(2, STRjobcmd, args); 942100616Smp pcurrjob = pp; 943100616Smp } 94483098Smpleave: 94583098Smp jobcmd_active = 0; 946167465Smp cleanup_until(&pintr_disabled); 94783098Smp} 94883098Smp 94983098Smp 95059243Sobrien/* 95159243Sobrien * Karl Kleinpaste, 21oct1983. 95259243Sobrien * Set up a one-word alias command, for use for special things. 95359243Sobrien * This code is based on the mainline of process(). 95459243Sobrien */ 95559243Sobrienvoid 956167465Smpaliasrun(int cnt, Char *s1, Char *s2) 95759243Sobrien{ 95859243Sobrien struct wordent w, *new1, *new2; /* for holding alias name */ 95959243Sobrien struct command *t = NULL; 96059243Sobrien jmp_buf_t osetexit; 96159243Sobrien int status; 962167465Smp size_t omark; 96359243Sobrien 96459243Sobrien getexit(osetexit); 96559243Sobrien if (seterr) { 966167465Smp xfree(seterr); 96759243Sobrien seterr = NULL; /* don't repeatedly print err msg. */ 96859243Sobrien } 96959243Sobrien w.word = STRNULL; 970167465Smp new1 = xcalloc(1, sizeof w); 97159243Sobrien new1->word = Strsave(s1); 97259243Sobrien if (cnt == 1) { 97359243Sobrien /* build a lex list with one word. */ 97459243Sobrien w.next = w.prev = new1; 97559243Sobrien new1->next = new1->prev = &w; 97659243Sobrien } 97759243Sobrien else { 97859243Sobrien /* build a lex list with two words. */ 979167465Smp new2 = xcalloc(1, sizeof w); 98059243Sobrien new2->word = Strsave(s2); 98159243Sobrien w.next = new2->prev = new1; 98259243Sobrien new1->next = w.prev = new2; 98359243Sobrien new1->prev = new2->next = &w; 98459243Sobrien } 985167465Smp cleanup_push(&w, lex_cleanup); 98659243Sobrien 98759243Sobrien /* Save the old status */ 98859243Sobrien status = getn(varval(STRstatus)); 98959243Sobrien 99059243Sobrien /* expand aliases like process() does. */ 99159243Sobrien alias(&w); 99259243Sobrien /* build a syntax tree for the command. */ 99359243Sobrien t = syntax(w.next, &w, 0); 994167465Smp cleanup_push(t, syntax_cleanup); 99559243Sobrien if (seterr) 99659243Sobrien stderror(ERR_OLD); 99759243Sobrien 99859243Sobrien psavejob(); 999167465Smp cleanup_push(&cnt, psavejob_cleanup); /* cnt is used only as a marker */ 100059243Sobrien 100159243Sobrien /* catch any errors here */ 1002167465Smp omark = cleanup_push_mark(); 100359243Sobrien if (setexit() == 0) 100459243Sobrien /* execute the parse tree. */ 100559243Sobrien /* 100659243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 100759243Sobrien * was execute(t, tpgrp); 100859243Sobrien */ 1009100616Smp execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL, TRUE); 1010167465Smp /* reset the error catcher to the old place */ 1011167465Smp cleanup_pop_mark(omark); 1012167465Smp resexit(osetexit); 101359243Sobrien if (haderr) { 101459243Sobrien haderr = 0; 101559243Sobrien /* 101659243Sobrien * Either precmd, or cwdcmd, or periodic had an error. Call it again so 101759243Sobrien * that it is removed 101859243Sobrien */ 101959243Sobrien if (precmd_active) 102059243Sobrien precmd(); 102159243Sobrien if (postcmd_active) 102259243Sobrien postcmd(); 102359243Sobrien#ifdef notdef 102459243Sobrien /* 102559243Sobrien * XXX: On the other hand, just interrupting them causes an error too. 102659243Sobrien * So if we hit ^C in the middle of cwdcmd or periodic the alias gets 102759243Sobrien * removed. We don't want that. Note that we want to remove precmd 102859243Sobrien * though, cause that could lead into an infinite loop. This should be 102959243Sobrien * fixed correctly, but then haderr should give us the whole exit 103059243Sobrien * status not just true or false. 103159243Sobrien */ 103259243Sobrien else if (cwdcmd_active) 103359243Sobrien cwd_cmd(); 103459243Sobrien else if (beepcmd_active) 103559243Sobrien beep_cmd(); 103659243Sobrien else if (periodic_active) 103759243Sobrien period_cmd(); 103859243Sobrien#endif /* notdef */ 103959243Sobrien } 1040167465Smp cleanup_until(&w); 104159243Sobrien pendjob(); 104259243Sobrien /* Restore status */ 1043231990Smp setv(STRstatus, putn((tcsh_number_t)status), VAR_READWRITE); 104459243Sobrien} 104559243Sobrien 104659243Sobrienvoid 1047167465Smpsetalarm(int lck) 104859243Sobrien{ 104959243Sobrien struct varent *vp; 105059243Sobrien Char *cp; 105159243Sobrien unsigned alrm_time = 0, logout_time, lock_time; 105259243Sobrien time_t cl, nl, sched_dif; 105359243Sobrien 1054100616Smp if ((vp = adrof(STRautologout)) != NULL && vp->vec != NULL) { 105559243Sobrien if ((cp = vp->vec[0]) != 0) { 105659243Sobrien if ((logout_time = (unsigned) atoi(short2str(cp)) * 60) > 0) { 1057145479Smp#ifdef SOLARIS2 1058145479Smp /* 1059145479Smp * Solaris alarm(2) uses a timer based in clock ticks 1060145479Smp * internally so it multiplies our value with CLK_TCK... 1061145479Smp * Of course that can overflow leading to unexpected 1062145479Smp * results, so we clip it here. Grr. Where is that 1063145479Smp * documented folks? 1064145479Smp */ 1065145479Smp if (logout_time >= 0x7fffffff / CLK_TCK) 1066145479Smp logout_time = 0x7fffffff / CLK_TCK; 1067145479Smp#endif /* SOLARIS2 */ 106859243Sobrien alrm_time = logout_time; 106959243Sobrien alm_fun = auto_logout; 107059243Sobrien } 107159243Sobrien } 107259243Sobrien if ((cp = vp->vec[1]) != 0) { 107359243Sobrien if ((lock_time = (unsigned) atoi(short2str(cp)) * 60) > 0) { 107459243Sobrien if (lck) { 107559243Sobrien if (alrm_time == 0 || lock_time < alrm_time) { 107659243Sobrien alrm_time = lock_time; 107759243Sobrien alm_fun = auto_lock; 107859243Sobrien } 107959243Sobrien } 108059243Sobrien else /* lock_time always < alrm_time */ 108159243Sobrien if (alrm_time) 108259243Sobrien alrm_time -= lock_time; 108359243Sobrien } 108459243Sobrien } 108559243Sobrien } 108659243Sobrien if ((nl = sched_next()) != -1) { 108759243Sobrien (void) time(&cl); 108859243Sobrien sched_dif = nl > cl ? nl - cl : 0; 108959243Sobrien if ((alrm_time == 0) || ((unsigned) sched_dif < alrm_time)) { 109059243Sobrien alrm_time = ((unsigned) sched_dif) + 1; 109159243Sobrien alm_fun = sched_run; 109259243Sobrien } 109359243Sobrien } 1094167465Smp alrmcatch_disabled = 0; 109559243Sobrien (void) alarm(alrm_time); /* Autologout ON */ 109659243Sobrien} 109759243Sobrien 109859243Sobrien#undef RMDEBUG /* For now... */ 109959243Sobrien 110059243Sobrienvoid 1101167465Smprmstar(struct wordent *cp) 110259243Sobrien{ 110359243Sobrien struct wordent *we, *args; 1104145479Smp struct wordent *tmp, *del; 110559243Sobrien 110659243Sobrien#ifdef RMDEBUG 110759243Sobrien static Char STRrmdebug[] = {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'}; 110859243Sobrien Char *tag; 110959243Sobrien#endif /* RMDEBUG */ 111059243Sobrien Char *charac; 111159243Sobrien char c; 111259243Sobrien int ask, doit, star = 0, silent = 0; 111359243Sobrien 111459243Sobrien if (!adrof(STRrmstar)) 111559243Sobrien return; 111659243Sobrien#ifdef RMDEBUG 111759243Sobrien tag = varval(STRrmdebug); 111859243Sobrien#endif /* RMDEBUG */ 111959243Sobrien we = cp->next; 112059243Sobrien while (*we->word == ';' && we != cp) 112159243Sobrien we = we->next; 112259243Sobrien while (we != cp) { 112359243Sobrien#ifdef RMDEBUG 112459243Sobrien if (*tag) 112559243Sobrien xprintf(CGETS(22, 7, "parsing command line\n")); 112659243Sobrien#endif /* RMDEBUG */ 112759243Sobrien if (!Strcmp(we->word, STRrm)) { 112859243Sobrien args = we->next; 112959243Sobrien ask = (*args->word != '-'); 113059243Sobrien while (*args->word == '-' && !silent) { /* check options */ 113159243Sobrien for (charac = (args->word + 1); *charac && !silent; charac++) 113259243Sobrien silent = (*charac == 'i' || *charac == 'f'); 113359243Sobrien args = args->next; 113459243Sobrien } 113559243Sobrien ask = (ask || (!ask && !silent)); 113659243Sobrien if (ask) { 113759243Sobrien for (; !star && *args->word != ';' 113859243Sobrien && args != cp; args = args->next) 113959243Sobrien if (!Strcmp(args->word, STRstar)) 114059243Sobrien star = 1; 114159243Sobrien if (ask && star) { 1142195609Smp xprintf("%s", CGETS(22, 8, 114359243Sobrien "Do you really want to delete all files? [n/y] ")); 114459243Sobrien flush(); 114559243Sobrien (void) force_read(SHIN, &c, 1); 114659243Sobrien /* 114759243Sobrien * Perhaps we should use the yesexpr from the 114859243Sobrien * actual locale 114959243Sobrien */ 115059243Sobrien doit = (strchr(CGETS(22, 14, "Yy"), c) != NULL); 115159243Sobrien while (c != '\n' && force_read(SHIN, &c, 1) == 1) 115259243Sobrien continue; 115359243Sobrien if (!doit) { 115459243Sobrien /* remove the command instead */ 115559243Sobrien#ifdef RMDEBUG 115659243Sobrien if (*tag) 115759243Sobrien xprintf(CGETS(22, 9, 115859243Sobrien "skipping deletion of files!\n")); 115959243Sobrien#endif /* RMDEBUG */ 116059243Sobrien for (tmp = we; 116159243Sobrien *tmp->word != '\n' && 116259243Sobrien *tmp->word != ';' && tmp != cp;) { 116359243Sobrien tmp->prev->next = tmp->next; 116459243Sobrien tmp->next->prev = tmp->prev; 1165167465Smp xfree(tmp->word); 116659243Sobrien del = tmp; 116759243Sobrien tmp = tmp->next; 1168167465Smp xfree(del); 116959243Sobrien } 117059243Sobrien if (*tmp->word == ';') { 117159243Sobrien tmp->prev->next = tmp->next; 117259243Sobrien tmp->next->prev = tmp->prev; 1173167465Smp xfree(tmp->word); 117459243Sobrien del = tmp; 117583098Smp tmp = tmp->next; 1176167465Smp xfree(del); 117759243Sobrien } 117883098Smp we = tmp; 117983098Smp continue; 118059243Sobrien } 118159243Sobrien } 118259243Sobrien } 118359243Sobrien } 118459243Sobrien for (we = we->next; 118559243Sobrien *we->word != ';' && we != cp; 118659243Sobrien we = we->next) 118759243Sobrien continue; 118859243Sobrien if (*we->word == ';') 118959243Sobrien we = we->next; 119059243Sobrien } 119159243Sobrien#ifdef RMDEBUG 119259243Sobrien if (*tag) { 119359243Sobrien xprintf(CGETS(22, 10, "command line now is:\n")); 119459243Sobrien for (we = cp->next; we != cp; we = we->next) 119559243Sobrien xprintf("%S ", we->word); 119659243Sobrien } 119759243Sobrien#endif /* RMDEBUG */ 119859243Sobrien return; 119959243Sobrien} 120059243Sobrien 120159243Sobrien#ifdef BSDJOBS 120259243Sobrien/* Check if command is in continue list 120359243Sobrien and do a "aliasing" if it exists as a job in background */ 120459243Sobrien 120559243Sobrien#undef CNDEBUG /* For now */ 120659243Sobrienvoid 1207167465Smpcontinue_jobs(struct wordent *cp) 120859243Sobrien{ 120959243Sobrien struct wordent *we; 1210145479Smp struct process *pp, *np; 121159243Sobrien Char *cmd, *continue_list, *continue_args_list; 121259243Sobrien 121359243Sobrien#ifdef CNDEBUG 121459243Sobrien Char *tag; 121559243Sobrien static Char STRcndebug[] = 121659243Sobrien {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'}; 121759243Sobrien#endif /* CNDEBUG */ 1218145479Smp int in_cont_list, in_cont_arg_list; 121959243Sobrien 122059243Sobrien 122159243Sobrien#ifdef CNDEBUG 122259243Sobrien tag = varval(STRcndebug); 122359243Sobrien#endif /* CNDEBUG */ 122459243Sobrien continue_list = varval(STRcontinue); 122559243Sobrien continue_args_list = varval(STRcontinue_args); 122659243Sobrien if (*continue_list == '\0' && *continue_args_list == '\0') 122759243Sobrien return; 122859243Sobrien 122959243Sobrien we = cp->next; 123059243Sobrien while (*we->word == ';' && we != cp) 123159243Sobrien we = we->next; 123259243Sobrien while (we != cp) { 123359243Sobrien#ifdef CNDEBUG 123459243Sobrien if (*tag) 123559243Sobrien xprintf(CGETS(22, 11, "parsing command line\n")); 123659243Sobrien#endif /* CNDEBUG */ 123759243Sobrien cmd = we->word; 123859243Sobrien in_cont_list = inlist(continue_list, cmd); 123959243Sobrien in_cont_arg_list = inlist(continue_args_list, cmd); 124059243Sobrien if (in_cont_list || in_cont_arg_list) { 124159243Sobrien#ifdef CNDEBUG 124259243Sobrien if (*tag) 124359243Sobrien xprintf(CGETS(22, 12, "in one of the lists\n")); 124459243Sobrien#endif /* CNDEBUG */ 124559243Sobrien np = NULL; 124659243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 124759243Sobrien if (prefix(cmd, pp->p_command)) { 124859243Sobrien if (pp->p_index) { 124959243Sobrien np = pp; 125059243Sobrien break; 125159243Sobrien } 125259243Sobrien } 125359243Sobrien } 125459243Sobrien if (np) { 125559243Sobrien insert(we, in_cont_arg_list); 125659243Sobrien } 125759243Sobrien } 125859243Sobrien for (we = we->next; 125959243Sobrien *we->word != ';' && we != cp; 126059243Sobrien we = we->next) 126159243Sobrien continue; 126259243Sobrien if (*we->word == ';') 126359243Sobrien we = we->next; 126459243Sobrien } 126559243Sobrien#ifdef CNDEBUG 126659243Sobrien if (*tag) { 126759243Sobrien xprintf(CGETS(22, 13, "command line now is:\n")); 126859243Sobrien for (we = cp->next; we != cp; we = we->next) 126959243Sobrien xprintf("%S ", we->word); 127059243Sobrien } 127159243Sobrien#endif /* CNDEBUG */ 127259243Sobrien return; 127359243Sobrien} 127459243Sobrien 127559243Sobrien/* The actual "aliasing" of for backgrounds() is done here 127659243Sobrien with the aid of insert_we(). */ 127759243Sobrienstatic void 1278167465Smpinsert(struct wordent *pl, int file_args) 127959243Sobrien{ 128059243Sobrien struct wordent *now, *last; 128159243Sobrien Char *cmd, *bcmd, *cp1, *cp2; 1282167465Smp size_t cmd_len; 1283145479Smp Char *upause = STRunderpause; 1284167465Smp size_t p_len = Strlen(upause); 128559243Sobrien 1286167465Smp cmd_len = Strlen(pl->word); 1287167465Smp cmd = xcalloc(1, (cmd_len + 1) * sizeof(Char)); 128859243Sobrien (void) Strcpy(cmd, pl->word); 128959243Sobrien/* Do insertions at beginning, first replace command word */ 129059243Sobrien 129159243Sobrien if (file_args) { 129259243Sobrien now = pl; 1293167465Smp xfree(now->word); 1294167465Smp now->word = xcalloc(1, 5 * sizeof(Char)); 129559243Sobrien (void) Strcpy(now->word, STRecho); 129659243Sobrien 1297167465Smp now = xcalloc(1, sizeof(struct wordent)); 1298167465Smp now->word = xcalloc(1, 6 * sizeof(Char)); 129959243Sobrien (void) Strcpy(now->word, STRbackqpwd); 130059243Sobrien insert_we(now, pl); 130159243Sobrien 130259243Sobrien for (last = now; *last->word != '\n' && *last->word != ';'; 130359243Sobrien last = last->next) 130459243Sobrien continue; 130559243Sobrien 1306167465Smp now = xcalloc(1, sizeof(struct wordent)); 1307167465Smp now->word = xcalloc(1, 2 * sizeof(Char)); 130859243Sobrien (void) Strcpy(now->word, STRgt); 130959243Sobrien insert_we(now, last->prev); 131059243Sobrien 1311167465Smp now = xcalloc(1, sizeof(struct wordent)); 1312167465Smp now->word = xcalloc(1, 2 * sizeof(Char)); 131359243Sobrien (void) Strcpy(now->word, STRbang); 131459243Sobrien insert_we(now, last->prev); 131559243Sobrien 1316167465Smp now = xcalloc(1, sizeof(struct wordent)); 1317167465Smp now->word = xcalloc(1, (cmd_len + p_len + 4) * sizeof(Char)); 131859243Sobrien cp1 = now->word; 131959243Sobrien cp2 = cmd; 132059243Sobrien *cp1++ = '~'; 132159243Sobrien *cp1++ = '/'; 132259243Sobrien *cp1++ = '.'; 132359243Sobrien while ((*cp1++ = *cp2++) != '\0') 132459243Sobrien continue; 132559243Sobrien cp1--; 1326145479Smp cp2 = upause; 132759243Sobrien while ((*cp1++ = *cp2++) != '\0') 132859243Sobrien continue; 132959243Sobrien insert_we(now, last->prev); 133059243Sobrien 1331167465Smp now = xcalloc(1, sizeof(struct wordent)); 1332167465Smp now->word = xcalloc(1, 2 * sizeof(Char)); 133359243Sobrien (void) Strcpy(now->word, STRsemi); 133459243Sobrien insert_we(now, last->prev); 1335167465Smp bcmd = xcalloc(1, (cmd_len + 2) * sizeof(Char)); 1336167465Smp *bcmd = '%'; 1337167465Smp Strcpy(bcmd + 1, cmd); 1338167465Smp now = xcalloc(1, sizeof(struct wordent)); 133959243Sobrien now->word = bcmd; 134059243Sobrien insert_we(now, last->prev); 134159243Sobrien } 134259243Sobrien else { 134359243Sobrien struct wordent *del; 134459243Sobrien 134559243Sobrien now = pl; 1346167465Smp xfree(now->word); 1347167465Smp now->word = xcalloc(1, (cmd_len + 2) * sizeof(Char)); 1348167465Smp *now->word = '%'; 1349167465Smp Strcpy(now->word + 1, cmd); 135059243Sobrien for (now = now->next; 135159243Sobrien *now->word != '\n' && *now->word != ';' && now != pl;) { 135259243Sobrien now->prev->next = now->next; 135359243Sobrien now->next->prev = now->prev; 1354167465Smp xfree(now->word); 135559243Sobrien del = now; 135659243Sobrien now = now->next; 1357167465Smp xfree(del); 135859243Sobrien } 135959243Sobrien } 136059243Sobrien} 136159243Sobrien 136259243Sobrienstatic void 1363167465Smpinsert_we(struct wordent *new, struct wordent *where) 136459243Sobrien{ 136559243Sobrien 136659243Sobrien new->prev = where; 136759243Sobrien new->next = where->next; 136859243Sobrien where->next = new; 136959243Sobrien new->next->prev = new; 137059243Sobrien} 137159243Sobrien 137259243Sobrienstatic int 1373167465Smpinlist(Char *list, Char *name) 137459243Sobrien{ 1375145479Smp Char *l, *n; 137659243Sobrien 137759243Sobrien l = list; 137859243Sobrien n = name; 137959243Sobrien 138059243Sobrien while (*l && *n) { 138159243Sobrien if (*l == *n) { 138259243Sobrien l++; 138359243Sobrien n++; 138459243Sobrien if (*n == '\0' && (*l == ' ' || *l == '\0')) 138559243Sobrien return (1); 138659243Sobrien else 138759243Sobrien continue; 138859243Sobrien } 138959243Sobrien else { 139059243Sobrien while (*l && *l != ' ') 139159243Sobrien l++; /* skip to blank */ 139259243Sobrien while (*l && *l == ' ') 139359243Sobrien l++; /* and find first nonblank character */ 139459243Sobrien n = name; 139559243Sobrien } 139659243Sobrien } 139759243Sobrien return (0); 139859243Sobrien} 139959243Sobrien 140059243Sobrien#endif /* BSDJOBS */ 140159243Sobrien 140259243Sobrien 140359243Sobrien/* 140459243Sobrien * Implement a small cache for tilde names. This is used primarily 140559243Sobrien * to expand tilde names to directories, but also 140659243Sobrien * we can find users from their home directories for the tilde 140759243Sobrien * prompt, on machines where yp lookup is slow this can be a big win... 140859243Sobrien * As with any cache this can run out of sync, rehash can sync it again. 140959243Sobrien */ 141059243Sobrienstatic struct tildecache { 141159243Sobrien Char *user; 141259243Sobrien Char *home; 1413167465Smp size_t hlen; 141459243Sobrien} *tcache = NULL; 141559243Sobrien 141659243Sobrien#define TILINCR 10 1417167465Smpsize_t tlength = 0; 1418167465Smpstatic size_t tsize = TILINCR; 141959243Sobrien 142059243Sobrienstatic int 1421167465Smptildecompare(const void *xp1, const void *xp2) 142259243Sobrien{ 1423167465Smp const struct tildecache *p1, *p2; 1424167465Smp 1425167465Smp p1 = xp1; 1426167465Smp p2 = xp2; 142759243Sobrien return Strcmp(p1->user, p2->user); 142859243Sobrien} 142959243Sobrien 143059243Sobrienstatic Char * 1431167465Smpgethomedir(const Char *us) 143259243Sobrien{ 1433145479Smp struct passwd *pp; 143459243Sobrien#ifdef HESIOD 143559243Sobrien char **res, **res1, *cp; 143659243Sobrien Char *rp; 143759243Sobrien#endif /* HESIOD */ 143859243Sobrien 1439167465Smp pp = xgetpwnam(short2str(us)); 144059243Sobrien#ifdef YPBUGS 144159243Sobrien fix_yp_bugs(); 144259243Sobrien#endif /* YPBUGS */ 144383098Smp if (pp != NULL) { 1444100616Smp#if 0 144583098Smp /* Don't return if root */ 144683098Smp if (pp->pw_dir[0] == '/' && pp->pw_dir[1] == '\0') 144783098Smp return NULL; 144883098Smp else 1449100616Smp#endif 145083098Smp return Strsave(str2short(pp->pw_dir)); 145183098Smp } 145259243Sobrien#ifdef HESIOD 145359243Sobrien res = hes_resolve(short2str(us), "filsys"); 145483098Smp rp = NULL; 145583098Smp if (res != NULL) { 145683098Smp if ((*res) != NULL) { 145759243Sobrien /* 145859243Sobrien * Look at the first token to determine how to interpret 145959243Sobrien * the rest of it. 146059243Sobrien * Yes, strtok is evil (it's not thread-safe), but it's also 146159243Sobrien * easy to use. 146259243Sobrien */ 146359243Sobrien cp = strtok(*res, " "); 146459243Sobrien if (strcmp(cp, "AFS") == 0) { 146559243Sobrien /* next token is AFS pathname.. */ 146659243Sobrien cp = strtok(NULL, " "); 146759243Sobrien if (cp != NULL) 146859243Sobrien rp = Strsave(str2short(cp)); 146959243Sobrien } else if (strcmp(cp, "NFS") == 0) { 147059243Sobrien cp = NULL; 147159243Sobrien if ((strtok(NULL, " ")) && /* skip remote pathname */ 147259243Sobrien (strtok(NULL, " ")) && /* skip host */ 147359243Sobrien (strtok(NULL, " ")) && /* skip mode */ 147459243Sobrien (cp = strtok(NULL, " "))) { 147559243Sobrien rp = Strsave(str2short(cp)); 147659243Sobrien } 147759243Sobrien } 147859243Sobrien } 147959243Sobrien for (res1 = res; *res1; res1++) 148059243Sobrien free(*res1); 1481100616Smp#if 0 1482100616Smp /* Don't return if root */ 148383098Smp if (rp != NULL && rp[0] == '/' && rp[1] == '\0') { 1484167465Smp xfree(rp); 148583098Smp rp = NULL; 148683098Smp } 1487100616Smp#endif 148859243Sobrien return rp; 148959243Sobrien } 149059243Sobrien#endif /* HESIOD */ 149159243Sobrien return NULL; 149259243Sobrien} 149359243Sobrien 149459243SobrienChar * 1495167465Smpgettilde(const Char *us) 149659243Sobrien{ 149759243Sobrien struct tildecache *bp1, *bp2, *bp; 149859243Sobrien Char *hd; 149959243Sobrien 150059243Sobrien /* Ignore NIS special names */ 150159243Sobrien if (*us == '+' || *us == '-') 150259243Sobrien return NULL; 150359243Sobrien 150459243Sobrien if (tcache == NULL) 1505167465Smp tcache = xmalloc(TILINCR * sizeof(struct tildecache)); 150659243Sobrien /* 150759243Sobrien * Binary search 150859243Sobrien */ 150959243Sobrien for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) { 1510145479Smp int i; 151159243Sobrien 151259243Sobrien bp = bp1 + ((bp2 - bp1) >> 1); 151359243Sobrien if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0) 151459243Sobrien return (bp->home); 151559243Sobrien if (i < 0) 151659243Sobrien bp2 = bp; 151759243Sobrien else 151859243Sobrien bp1 = bp + 1; 151959243Sobrien } 152059243Sobrien /* 152159243Sobrien * Not in the cache, try to get it from the passwd file 152259243Sobrien */ 152359243Sobrien hd = gethomedir(us); 152459243Sobrien if (hd == NULL) 152559243Sobrien return NULL; 152659243Sobrien 152759243Sobrien /* 152859243Sobrien * Update the cache 152959243Sobrien */ 153059243Sobrien tcache[tlength].user = Strsave(us); 153159243Sobrien tcache[tlength].home = hd; 1532167465Smp tcache[tlength++].hlen = Strlen(hd); 153359243Sobrien 1534167465Smp qsort(tcache, tlength, sizeof(struct tildecache), tildecompare); 153559243Sobrien 153659243Sobrien if (tlength == tsize) { 153759243Sobrien tsize += TILINCR; 1538167465Smp tcache = xrealloc(tcache, tsize * sizeof(struct tildecache)); 153959243Sobrien } 154059243Sobrien return (hd); 154159243Sobrien} 154259243Sobrien 154359243Sobrien/* 154459243Sobrien * Return the username if the directory path passed contains a 154559243Sobrien * user's home directory in the tilde cache, otherwise return NULL 154659243Sobrien * hm points to the place where the path became different. 154759243Sobrien * Special case: Our own home directory. 154859243Sobrien * If we are passed a null pointer, then we flush the cache. 154959243Sobrien */ 155059243SobrienChar * 1551167465Smpgetusername(Char **hm) 155259243Sobrien{ 155359243Sobrien Char *h, *p; 1554167465Smp size_t i, j; 155559243Sobrien 155659243Sobrien if (hm == NULL) { 155759243Sobrien for (i = 0; i < tlength; i++) { 1558167465Smp xfree(tcache[i].home); 1559167465Smp xfree(tcache[i].user); 156059243Sobrien } 1561167465Smp xfree(tcache); 156259243Sobrien tlength = 0; 156359243Sobrien tsize = TILINCR; 156459243Sobrien tcache = NULL; 156559243Sobrien return NULL; 156659243Sobrien } 1567167465Smp p = *hm; 156859243Sobrien if (((h = varval(STRhome)) != STRNULL) && 1569167465Smp (Strncmp(p, h, j = Strlen(h)) == 0) && 157059243Sobrien (p[j] == '/' || p[j] == '\0')) { 157159243Sobrien *hm = &p[j]; 157259243Sobrien return STRNULL; 157359243Sobrien } 157459243Sobrien for (i = 0; i < tlength; i++) 1575167465Smp if ((Strncmp(p, tcache[i].home, (j = tcache[i].hlen)) == 0) && 1576167465Smp (p[j] == '/' || p[j] == '\0')) { 157759243Sobrien *hm = &p[j]; 157859243Sobrien return tcache[i].user; 157959243Sobrien } 158059243Sobrien return NULL; 158159243Sobrien} 158259243Sobrien 158359243Sobrien 158459243Sobrien/* 158559243Sobrien * set the shell-level var to 1 or apply change to it. 158659243Sobrien */ 158759243Sobrienvoid 1588167465Smpshlvl(int val) 158959243Sobrien{ 159059243Sobrien char *cp; 159159243Sobrien 159259243Sobrien if ((cp = getenv("SHLVL")) != NULL) { 159359243Sobrien 159459243Sobrien if (loginsh) 159559243Sobrien val = 1; 159659243Sobrien else 159759243Sobrien val += atoi(cp); 159859243Sobrien 159959243Sobrien if (val <= 0) { 160059243Sobrien if (adrof(STRshlvl) != NULL) 160159243Sobrien unsetv(STRshlvl); 160259243Sobrien Unsetenv(STRKSHLVL); 160359243Sobrien } 160459243Sobrien else { 1605167465Smp Char *p; 160659243Sobrien 1607167465Smp p = Itoa(val, 0, 0); 1608167465Smp cleanup_push(p, xfree); 1609167465Smp setv(STRshlvl, p, VAR_READWRITE); 1610167465Smp cleanup_ignore(p); 1611167465Smp cleanup_until(p); 1612167465Smp tsetenv(STRKSHLVL, p); 161359243Sobrien } 161459243Sobrien } 161559243Sobrien else { 1616167465Smp setcopy(STRshlvl, STR1, VAR_READWRITE); 1617167465Smp tsetenv(STRKSHLVL, STR1); 161859243Sobrien } 161959243Sobrien} 162059243Sobrien 162159243Sobrien 162259243Sobrien/* fixio(): 162359243Sobrien * Try to recover from a read error 162459243Sobrien */ 162559243Sobrienint 1626167465Smpfixio(int fd, int e) 162759243Sobrien{ 162859243Sobrien switch (e) { 162959243Sobrien case -1: /* Make sure that the code is reachable */ 163059243Sobrien 163159243Sobrien#ifdef EWOULDBLOCK 163259243Sobrien case EWOULDBLOCK: 163359243Sobrien# define FDRETRY 163459243Sobrien#endif /* EWOULDBLOCK */ 163559243Sobrien 163659243Sobrien#if defined(POSIX) && defined(EAGAIN) 163759243Sobrien# if !defined(EWOULDBLOCK) || EWOULDBLOCK != EAGAIN 163859243Sobrien case EAGAIN: 163959243Sobrien# define FDRETRY 164059243Sobrien# endif /* !EWOULDBLOCK || EWOULDBLOCK != EAGAIN */ 164159243Sobrien#endif /* POSIX && EAGAIN */ 164259243Sobrien 1643231990Smp e = -1; 164459243Sobrien#ifdef FDRETRY 164559243Sobrien# ifdef F_SETFL 164659243Sobrien/* 164759243Sobrien * Great! we have on suns 3 flavors and 5 names... 164859243Sobrien * I hope that will cover everything. 164959243Sobrien * I added some more defines... many systems have different defines. 165059243Sobrien * Rather than dealing with getting the right includes, we'll just 165159243Sobrien * cover all the known possibilities here. -- sterling@netcom.com 165259243Sobrien */ 165359243Sobrien# ifndef O_NONBLOCK 165459243Sobrien# define O_NONBLOCK 0 165559243Sobrien# endif /* O_NONBLOCK */ 165659243Sobrien# ifndef O_NDELAY 165759243Sobrien# define O_NDELAY 0 165859243Sobrien# endif /* O_NDELAY */ 165959243Sobrien# ifndef FNBIO 166059243Sobrien# define FNBIO 0 166159243Sobrien# endif /* FNBIO */ 166259243Sobrien# ifndef _FNBIO 166359243Sobrien# define _FNBIO 0 166459243Sobrien# endif /* _FNBIO */ 166559243Sobrien# ifndef FNONBIO 166659243Sobrien# define FNONBIO 0 166759243Sobrien# endif /* FNONBIO */ 166859243Sobrien# ifndef FNONBLOCK 166959243Sobrien# define FNONBLOCK 0 167059243Sobrien# endif /* FNONBLOCK */ 167159243Sobrien# ifndef _FNONBLOCK 167259243Sobrien# define _FNONBLOCK 0 167359243Sobrien# endif /* _FNONBLOCK */ 167459243Sobrien# ifndef FNDELAY 167559243Sobrien# define FNDELAY 0 167659243Sobrien# endif /* FNDELAY */ 167759243Sobrien# ifndef _FNDELAY 167859243Sobrien# define _FNDELAY 0 167959243Sobrien# endif /* _FNDELAY */ 168059243Sobrien# ifndef FNDLEAY /* Some linux versions have this typo */ 168159243Sobrien# define FNDLEAY 0 168259243Sobrien# endif /* FNDLEAY */ 168359243Sobrien if ((e = fcntl(fd, F_GETFL, 0)) == -1) 168459243Sobrien return -1; 168559243Sobrien 168659243Sobrien e &= ~(O_NDELAY|O_NONBLOCK|FNBIO|_FNBIO|FNONBIO|FNONBLOCK|_FNONBLOCK| 168759243Sobrien FNDELAY|_FNDELAY|FNDLEAY); /* whew! */ 168859243Sobrien if (fcntl(fd, F_SETFL, e) == -1) 168959243Sobrien return -1; 169059243Sobrien else 1691231990Smp e = 0; 169259243Sobrien# endif /* F_SETFL */ 169359243Sobrien 169459243Sobrien# ifdef FIONBIO 169559243Sobrien e = 0; 169659243Sobrien if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1) 169759243Sobrien return -1; 169859243Sobrien# endif /* FIONBIO */ 169959243Sobrien 170059243Sobrien#endif /* FDRETRY */ 1701231990Smp return e; 170259243Sobrien 170359243Sobrien case EINTR: 170459243Sobrien return 0; 170559243Sobrien 170659243Sobrien default: 170759243Sobrien return -1; 170859243Sobrien } 170959243Sobrien} 171059243Sobrien 171159243Sobrien/* collate(): 171259243Sobrien * String collation 171359243Sobrien */ 171459243Sobrienint 1715167465Smpcollate(const Char *a, const Char *b) 171659243Sobrien{ 171759243Sobrien int rv; 171859243Sobrien#ifdef SHORT_STRINGS 171959243Sobrien /* This strips the quote bit as a side effect */ 172059243Sobrien char *sa = strsave(short2str(a)); 172159243Sobrien char *sb = strsave(short2str(b)); 172259243Sobrien#else 172359243Sobrien char *sa = strip(strsave(a)); 172459243Sobrien char *sb = strip(strsave(b)); 172559243Sobrien#endif /* SHORT_STRINGS */ 172659243Sobrien 1727167465Smp#if defined(NLS) && defined(HAVE_STRCOLL) 172859243Sobrien errno = 0; /* strcoll sets errno, another brain-damage */ 172959243Sobrien 173059243Sobrien rv = strcoll(sa, sb); 173159243Sobrien 173259243Sobrien /* 173359243Sobrien * We should be checking for errno != 0, but some systems 173459243Sobrien * forget to reset errno to 0. So we only check for the 173559243Sobrien * only documented valid errno value for strcoll [EINVAL] 173659243Sobrien */ 173759243Sobrien if (errno == EINVAL) { 1738167465Smp xfree(sa); 1739167465Smp xfree(sb); 174059243Sobrien stderror(ERR_SYSTEM, "strcoll", strerror(errno)); 174159243Sobrien } 174259243Sobrien#else 174359243Sobrien rv = strcmp(sa, sb); 1744167465Smp#endif /* NLS && HAVE_STRCOLL */ 174559243Sobrien 1746167465Smp xfree(sa); 1747167465Smp xfree(sb); 174859243Sobrien 174959243Sobrien return rv; 175059243Sobrien} 175159243Sobrien 175259243Sobrien#ifdef HASHBANG 175359243Sobrien/* 175459243Sobrien * From: peter@zeus.dialix.oz.au (Peter Wemm) 175559243Sobrien * If exec() fails look first for a #! [word] [word] .... 175659243Sobrien * If it is, splice the header into the argument list and retry. 175759243Sobrien */ 175859243Sobrien#define HACKBUFSZ 1024 /* Max chars in #! vector */ 175959243Sobrienint 1760167465Smphashbang(int fd, Char ***vp) 176159243Sobrien{ 1762167465Smp struct blk_buf sarg = BLK_BUF_INIT; 1763167465Smp char lbuf[HACKBUFSZ], *p, *ws; 176469408Sache#ifdef WINNT_NATIVE 176559243Sobrien int fw = 0; /* found at least one word */ 1766167465Smp int first_word = 1; 1767167465Smp char *real; 176869408Sache#endif /* WINNT_NATIVE */ 176959243Sobrien 1770167465Smp if (xread(fd, lbuf, HACKBUFSZ) <= 0) 177159243Sobrien return -1; 177259243Sobrien 177359243Sobrien ws = 0; /* word started = 0 */ 177459243Sobrien 1775167465Smp for (p = lbuf; p < &lbuf[HACKBUFSZ]; ) { 177659243Sobrien switch (*p) { 177759243Sobrien case ' ': 177859243Sobrien case '\t': 1779195609Smp#if defined(WINNT_NATIVE) || defined (__CYGWIN__) 178059243Sobrien case '\r': 1781195609Smp#endif /* WINNT_NATIVE || __CYGWIN__ */ 178259243Sobrien if (ws) { /* a blank after a word.. save it */ 178359243Sobrien *p = '\0'; 1784167465Smp#ifdef WINNT_NATIVE 1785167465Smp if (first_word) { 1786167465Smp real = hb_subst(ws); 1787167465Smp if (real != NULL) 1788167465Smp ws = real; 178959243Sobrien } 179059243Sobrien fw = 1; 1791167465Smp first_word = 0; 179269408Sache#endif /* WINNT_NATIVE */ 1793167465Smp bb_append(&sarg, SAVE(ws)); 1794167465Smp ws = NULL; 179559243Sobrien } 179659243Sobrien p++; 179759243Sobrien continue; 179859243Sobrien 179959243Sobrien case '\0': /* Whoa!! what the hell happened */ 1800167465Smp goto err; 180159243Sobrien 180259243Sobrien case '\n': /* The end of the line. */ 180359243Sobrien if ( 180469408Sache#ifdef WINNT_NATIVE 180559243Sobrien fw || 180669408Sache#endif /* WINNT_NATIVE */ 180759243Sobrien ws) { /* terminate the last word */ 180859243Sobrien *p = '\0'; 1809167465Smp#ifdef WINNT_NATIVE 1810167465Smp /* deal with the 1-word case */ 1811167465Smp if (first_word) { 1812167465Smp real = hb_subst(ws); 1813167465Smp if (real != NULL) 1814167465Smp ws = real; 181559243Sobrien } 181669408Sache#endif /* !WINNT_NATIVE */ 1817167465Smp if (ws) 1818167465Smp bb_append(&sarg, SAVE(ws)); 181959243Sobrien } 1820167465Smp if (sarg.len > 0) { 1821167465Smp *vp = bb_finish(&sarg); 182259243Sobrien return 0; 182359243Sobrien } 182459243Sobrien else 1825167465Smp goto err; 182659243Sobrien 182759243Sobrien default: 182859243Sobrien if (!ws) /* Start a new word? */ 182959243Sobrien ws = p; 183059243Sobrien p++; 183159243Sobrien break; 183259243Sobrien } 1833167465Smp } 1834167465Smp err: 1835167465Smp bb_cleanup(&sarg); 183659243Sobrien return -1; 183759243Sobrien} 183859243Sobrien#endif /* HASHBANG */ 183959243Sobrien 184059243Sobrien#ifdef REMOTEHOST 184159243Sobrien 1842167465Smpstatic void 1843167465Smppalarm(int snum) 184459243Sobrien{ 184559243Sobrien USE(snum); 1846167465Smp _exit(1); 184759243Sobrien} 184859243Sobrien 184959243Sobrienstatic void 1850167465Smpgetremotehost(int dest_fd) 185159243Sobrien{ 185259243Sobrien const char *host = NULL; 185369408Sache#ifdef INET6 185469408Sache struct sockaddr_storage saddr; 185569408Sache static char hbuf[NI_MAXHOST]; 185669408Sache#else 185759243Sobrien struct hostent* hp; 185859243Sobrien struct sockaddr_in saddr; 185969408Sache#endif 1860167465Smp socklen_t len = sizeof(saddr); 186159243Sobrien 186269408Sache#ifdef INET6 1863100616Smp if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 1864100616Smp (saddr.ss_family == AF_INET6 || saddr.ss_family == AF_INET)) { 186569408Sache int flag = NI_NUMERICHOST; 186669408Sache 186769408Sache#ifdef NI_WITHSCOPEID 186869408Sache flag |= NI_WITHSCOPEID; 186969408Sache#endif 187069408Sache getnameinfo((struct sockaddr *)&saddr, len, hbuf, sizeof(hbuf), 187169408Sache NULL, 0, flag); 187269408Sache host = hbuf; 187369408Sache#else 1874100616Smp if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 1875100616Smp saddr.sin_family == AF_INET) { 187669408Sache#if 0 187759243Sobrien if ((hp = gethostbyaddr((char *)&saddr.sin_addr, sizeof(struct in_addr), 187859243Sobrien AF_INET)) != NULL) 187959243Sobrien host = hp->h_name; 188059243Sobrien else 188159243Sobrien#endif 188259243Sobrien host = inet_ntoa(saddr.sin_addr); 188369408Sache#endif 188459243Sobrien } 1885145479Smp#ifdef HAVE_STRUCT_UTMP_UT_HOST 188659243Sobrien else { 188759243Sobrien char *ptr; 188859243Sobrien char *name = utmphost(); 188959243Sobrien /* Avoid empty names and local X displays */ 189059243Sobrien if (name != NULL && *name != '\0' && *name != ':') { 189169408Sache struct in_addr addr; 1892167465Smp char *sptr; 189369408Sache 189459243Sobrien /* Look for host:display.screen */ 189569408Sache /* 189669408Sache * There is conflict with IPv6 address and X DISPLAY. So, 189769408Sache * we assume there is no IPv6 address in utmp and don't 189869408Sache * touch here. 189969408Sache */ 190059243Sobrien if ((sptr = strchr(name, ':')) != NULL) 190159243Sobrien *sptr = '\0'; 190269408Sache /* Leave IPv4 address as is */ 190369408Sache /* 190469408Sache * we use inet_addr here, not inet_aton because many systems 190569408Sache * have not caught up yet. 190669408Sache */ 190769408Sache addr.s_addr = inet_addr(name); 1908131962Smp if (addr.s_addr != (unsigned int)~0) 190959243Sobrien host = name; 191059243Sobrien else { 191159243Sobrien if (sptr != name) { 191269408Sache#ifdef INET6 191369408Sache char *s, *domain; 1914167465Smp char dbuf[MAXHOSTNAMELEN]; 191569408Sache struct addrinfo hints, *res = NULL; 191669408Sache 191769408Sache memset(&hints, 0, sizeof(hints)); 191869408Sache hints.ai_family = PF_UNSPEC; 191969408Sache hints.ai_socktype = SOCK_STREAM; 192069408Sache hints.ai_flags = AI_PASSIVE | AI_CANONNAME; 192169408Sache if (strlen(name) < utmphostsize()) 192269408Sache { 192369408Sache if (getaddrinfo(name, NULL, &hints, &res) != 0) 192469408Sache res = NULL; 1925167465Smp } else if (gethostname(dbuf, sizeof(dbuf)) == 0 && 1926167465Smp (dbuf[sizeof(dbuf)-1] = '\0', /*FIXME: ugly*/ 1927167465Smp (domain = strchr(dbuf, '.')) != NULL)) { 192869408Sache for (s = strchr(name, '.'); 192969408Sache s != NULL; s = strchr(s + 1, '.')) { 193069408Sache if (*(s + 1) != '\0' && 193169408Sache (ptr = strstr(domain, s)) != NULL) { 1932167465Smp char *cbuf; 1933167465Smp 1934231990Smp cbuf = strspl(name, ptr + strlen(s)); 193569408Sache if (getaddrinfo(cbuf, NULL, &hints, &res) != 0) 193669408Sache res = NULL; 1937167465Smp xfree(cbuf); 193869408Sache break; 193969408Sache } 194069408Sache } 194169408Sache } 194269408Sache if (res != NULL) { 194369408Sache if (res->ai_canonname != NULL) { 194469408Sache strncpy(hbuf, res->ai_canonname, sizeof(hbuf)); 1945231990Smp hbuf[sizeof(hbuf) - 1] = '\0'; 194669408Sache host = hbuf; 194769408Sache } 194869408Sache freeaddrinfo(res); 194969408Sache } 195069408Sache#else 195159243Sobrien if ((hp = gethostbyname(name)) == NULL) { 195259243Sobrien /* Try again eliminating the trailing domain */ 195359243Sobrien if ((ptr = strchr(name, '.')) != NULL) { 195459243Sobrien *ptr = '\0'; 195559243Sobrien if ((hp = gethostbyname(name)) != NULL) 195659243Sobrien host = hp->h_name; 195759243Sobrien *ptr = '.'; 195859243Sobrien } 195959243Sobrien } 196059243Sobrien else 196159243Sobrien host = hp->h_name; 196269408Sache#endif 196359243Sobrien } 196459243Sobrien } 196559243Sobrien } 196659243Sobrien } 196759243Sobrien#endif 196859243Sobrien 1969167465Smp if (host) { 1970167465Smp size_t left; 197159243Sobrien 1972167465Smp left = strlen(host); 1973167465Smp while (left != 0) { 1974167465Smp ssize_t res; 1975167465Smp 1976167465Smp res = xwrite(dest_fd, host, left); 1977167465Smp if (res < 0) 1978167465Smp _exit(1); 1979167465Smp host += res; 1980167465Smp left -= res; 1981167465Smp } 1982167465Smp } 1983167465Smp _exit(0); 198459243Sobrien} 198559243Sobrien 198659243Sobrien/* 198759243Sobrien * From: <lesv@ppvku.ericsson.se> (Lennart Svensson) 198859243Sobrien */ 1989167465Smpvoid 1990167465Smpremotehost(void) 199159243Sobrien{ 1992167465Smp struct sigaction sa; 1993167465Smp struct strbuf hostname = strbuf_INIT; 1994167465Smp int fds[2], wait_options, status; 1995167465Smp pid_t pid, wait_res; 199659243Sobrien 1997167465Smp sa.sa_handler = SIG_DFL; /* Make sure a zombie is created */ 1998167465Smp sigemptyset(&sa.sa_mask); 1999167465Smp sa.sa_flags = 0; 2000167465Smp sigaction(SIGCHLD, &sa, NULL); 2001167465Smp mypipe(fds); 2002167465Smp pid = fork(); 2003167465Smp if (pid == 0) { 2004167465Smp sigset_t set; 2005167465Smp xclose(fds[0]); 2006167465Smp /* Don't get stuck if the resolver does not work! */ 2007167465Smp signal(SIGALRM, palarm); 2008167465Smp sigemptyset(&set); 2009167465Smp sigaddset(&set, SIGALRM); 2010167465Smp (void)sigprocmask(SIG_UNBLOCK, &set, NULL); 2011167465Smp (void)alarm(2); 2012167465Smp getremotehost(fds[1]); 2013167465Smp /*NOTREACHED*/ 2014167465Smp } 2015167465Smp xclose(fds[1]); 2016167465Smp for (;;) { 2017167465Smp char buf[BUFSIZE]; 2018167465Smp ssize_t res; 201959243Sobrien 2020167465Smp res = xread(fds[0], buf, sizeof(buf)); 2021167465Smp if (res == -1) { 2022167465Smp hostname.len = 0; 2023167465Smp wait_options = WNOHANG; 2024167465Smp goto done; 2025167465Smp } 2026167465Smp if (res == 0) 2027167465Smp break; 2028167465Smp strbuf_appendn(&hostname, buf, res); 2029167465Smp } 2030167465Smp wait_options = 0; 2031167465Smp done: 2032231990Smp cleanup_push(&hostname, strbuf_cleanup); 2033167465Smp xclose(fds[0]); 2034167465Smp while ((wait_res = waitpid(pid, &status, wait_options)) == -1 2035167465Smp && errno == EINTR) 2036167465Smp handle_pending_signals(); 2037231990Smp if (hostname.len > 0 && wait_res == pid && WIFEXITED(status) 2038231990Smp && WEXITSTATUS(status) == 0) { 2039167465Smp strbuf_terminate(&hostname); 2040167465Smp tsetenv(STRREMOTEHOST, str2short(hostname.s)); 2041167465Smp } 2042167465Smp cleanup_until(&hostname); 204359243Sobrien 204459243Sobrien#ifdef YPBUGS 204559243Sobrien /* From: casper@fwi.uva.nl (Casper H.S. Dik), for Solaris 2.3 */ 204659243Sobrien fix_yp_bugs(); 204759243Sobrien#endif /* YPBUGS */ 204859243Sobrien 204959243Sobrien} 205059243Sobrien#endif /* REMOTEHOST */ 2051145479Smp 2052145479Smp#ifndef WINNT_NATIVE 2053145479Smp/* 2054145479Smp * indicate if a terminal type is defined in terminfo/termcap 2055145479Smp * (by default the current term type). This allows ppl to look 2056145479Smp * for a working term type automatically in their login scripts 2057145479Smp * when using a terminal known as different things on different 2058145479Smp * platforms 2059145479Smp */ 2060145479Smpvoid 2061167465Smpdotermname(Char **v, struct command *c) 2062145479Smp{ 2063145479Smp char *termtype; 2064145479Smp /* 2065145479Smp * Maximum size of a termcap record. We make it twice as large. 2066145479Smp */ 2067145479Smp char termcap_buffer[2048]; 2068145479Smp 2069145479Smp USE(c); 2070145479Smp /* try to find which entry we should be looking for */ 2071145479Smp termtype = (v[1] == NULL ? getenv("TERM") : short2str(v[1])); 2072145479Smp if (termtype == NULL) { 2073145479Smp /* no luck - the user didn't provide one and none is 2074145479Smp * specified in the environment 2075145479Smp */ 2076167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 2077145479Smp return; 2078145479Smp } 2079145479Smp 2080145479Smp /* 2081145479Smp * we use the termcap function - if we are using terminfo we 2082145479Smp * will end up with it's compatibility function 2083145479Smp * terminfo/termcap will be initialized with the new 2084145479Smp * type but we don't care because tcsh has cached all the things 2085145479Smp * it needs. 2086145479Smp */ 2087145479Smp if (tgetent(termcap_buffer, termtype) == 1) { 2088145479Smp xprintf("%s\n", termtype); 2089167465Smp setcopy(STRstatus, STR0, VAR_READWRITE); 2090167465Smp } else 2091167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 2092145479Smp} 2093145479Smp#endif /* WINNT_NATIVE */ 2094