1316958Sdchagin/* $Header: /p/tcsh/cvsroot/tcsh/tc.func.c,v 3.158 2016/05/13 15:08:12 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 35316958SdchaginRCSID("$tcsh: tc.func.c,v 3.158 2016/05/13 15:08:12 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 != '\\')) || 123316958Sdchagin (((*s & TRIM) == '\"') && (prev_c != '\\')))) { 124167465Smp Strbuf_append1(&buf, '\\'); 12559243Sobrien } 126316958Sdchagin#if INVALID_BYTE != 0 127316958Sdchagin if ((*s & INVALID_BYTE) != INVALID_BYTE) /* *s < INVALID_BYTE */ 128316958Sdchagin Strbuf_append1(&buf, *s & TRIM); 129316958Sdchagin else 130316958Sdchagin Strbuf_append1(&buf, *s); 131316958Sdchagin#else 132167465Smp Strbuf_append1(&buf, *s & TRIM); 133316958Sdchagin#endif 13459243Sobrien prev_c = *s; 13559243Sobrien } 136167465Smp Strbuf_append1(&buf, ' '); 13759243Sobrien } 13859243Sobrien sp = sp->next; 13959243Sobrien if (sp == sp0) 14059243Sobrien break; 14159243Sobrien } 142167465Smp if (buf.len != 0) 143167465Smp buf.len--; /* get rid of trailing space */ 14459243Sobrien 145167465Smp return Strbuf_finish(&buf); 14659243Sobrien} 14759243Sobrien 14859243SobrienChar * 149167465Smpsprlex(const struct wordent *sp0) 15059243Sobrien{ 151167465Smp return expand_lex(sp0, 0, INT_MAX); 15259243Sobrien} 15359243Sobrien 15459243Sobrien 15559243SobrienChar * 156167465SmpItoa(int n, size_t min_digits, Char attributes) 15759243Sobrien{ 15859243Sobrien /* 15959243Sobrien * The array size here is derived from 16059243Sobrien * log8(UINT_MAX) 16159243Sobrien * which is guaranteed to be enough for a decimal 16259243Sobrien * representation. We add 1 because integer divide 16359243Sobrien * rounds down. 16459243Sobrien */ 16559243Sobrien#ifndef CHAR_BIT 16659243Sobrien# define CHAR_BIT 8 16759243Sobrien#endif 168167465Smp Char buf[CHAR_BIT * sizeof(int) / 3 + 1], *res, *p, *s; 16959243Sobrien unsigned int un; /* handle most negative # too */ 17059243Sobrien int pad = (min_digits != 0); 17159243Sobrien 172167465Smp if (sizeof(buf) - 1 < min_digits) 17359243Sobrien min_digits = sizeof(buf) - 1; 17459243Sobrien 17559243Sobrien un = n; 176167465Smp if (n < 0) 17759243Sobrien un = -n; 17859243Sobrien 17959243Sobrien p = buf; 18059243Sobrien do { 18159243Sobrien *p++ = un % 10 + '0'; 18259243Sobrien un /= 10; 183231990Smp } while ((pad && (ssize_t)--min_digits > 0) || un != 0); 18459243Sobrien 185167465Smp res = xmalloc((p - buf + 2) * sizeof(*res)); 186167465Smp s = res; 187167465Smp if (n < 0) 188167465Smp *s++ = '-'; 18959243Sobrien while (p > buf) 19059243Sobrien *s++ = *--p | attributes; 19159243Sobrien 19259243Sobrien *s = '\0'; 193167465Smp return res; 19459243Sobrien} 19559243Sobrien 19659243Sobrien 19759243Sobrien/*ARGSUSED*/ 19859243Sobrienvoid 199167465Smpdolist(Char **v, struct command *c) 20059243Sobrien{ 201167465Smp Char **globbed; 202316958Sdchagin int i, k, ret = 0; 20359243Sobrien struct stat st; 20459243Sobrien 20559243Sobrien USE(c); 20659243Sobrien if (*++v == NULL) { 207167465Smp struct Strbuf word = Strbuf_INIT; 208167465Smp 209167465Smp Strbuf_terminate(&word); 210167465Smp cleanup_push(&word, Strbuf_cleanup); 211167465Smp (void) t_search(&word, LIST, TW_ZERO, 0, STRNULL, 0); 212167465Smp cleanup_until(&word); 21359243Sobrien return; 21459243Sobrien } 215167465Smp v = glob_all_or_error(v); 216167465Smp globbed = v; 217167465Smp cleanup_push(globbed, blk_cleanup); 21859243Sobrien for (k = 0; v[k] != NULL && v[k][0] != '-'; k++) 21959243Sobrien continue; 22059243Sobrien if (v[k]) { 22159243Sobrien /* 22259243Sobrien * We cannot process a flag therefore we let ls do it right. 22359243Sobrien */ 22459243Sobrien Char *lspath; 22559243Sobrien struct command *t; 22659243Sobrien struct wordent cmd, *nextword, *lastword; 22759243Sobrien Char *cp; 22859243Sobrien struct varent *vp; 22959243Sobrien 230167465Smp if (setintr) { 231167465Smp pintr_disabled++; 232167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 233167465Smp } 23459243Sobrien if (seterr) { 235167465Smp xfree(seterr); 23659243Sobrien seterr = NULL; 23759243Sobrien } 23859243Sobrien 23959243Sobrien lspath = STRls; 24059243Sobrien STRmCF[1] = 'C'; 24159243Sobrien STRmCF[3] = '\0'; 24259243Sobrien /* Look at listflags, to add -A to the flags, to get a path 24359243Sobrien of ls if necessary */ 244100616Smp if ((vp = adrof(STRlistflags)) != NULL && vp->vec != NULL && 245100616Smp vp->vec[0] != STRNULL) { 24659243Sobrien if (vp->vec[1] != NULL && vp->vec[1][0] != '\0') 24759243Sobrien lspath = vp->vec[1]; 24859243Sobrien for (cp = vp->vec[0]; *cp; cp++) 24959243Sobrien switch (*cp) { 25059243Sobrien case 'x': 25159243Sobrien STRmCF[1] = 'x'; 25259243Sobrien break; 25359243Sobrien case 'a': 25459243Sobrien STRmCF[3] = 'a'; 25559243Sobrien break; 25659243Sobrien case 'A': 25759243Sobrien STRmCF[3] = 'A'; 25859243Sobrien break; 25959243Sobrien default: 26059243Sobrien break; 26159243Sobrien } 26259243Sobrien } 26359243Sobrien 26459243Sobrien cmd.word = STRNULL; 26559243Sobrien lastword = &cmd; 266167465Smp nextword = xcalloc(1, sizeof cmd); 26759243Sobrien nextword->word = Strsave(lspath); 26859243Sobrien lastword->next = nextword; 26959243Sobrien nextword->prev = lastword; 27059243Sobrien lastword = nextword; 271167465Smp nextword = xcalloc(1, sizeof cmd); 27259243Sobrien nextword->word = Strsave(STRmCF); 27359243Sobrien lastword->next = nextword; 27459243Sobrien nextword->prev = lastword; 27559243Sobrien#if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 27659243Sobrien if (dspmbyte_ls) { 27759243Sobrien lastword = nextword; 278167465Smp nextword = xcalloc(1, sizeof cmd); 27959243Sobrien nextword->word = Strsave(STRmmliteral); 28059243Sobrien lastword->next = nextword; 28159243Sobrien nextword->prev = lastword; 28259243Sobrien } 28359243Sobrien#endif 28459243Sobrien#ifdef COLOR_LS_F 28559243Sobrien if (color_context_ls) { 28659243Sobrien lastword = nextword; 287167465Smp nextword = xcalloc(1, sizeof cmd); 28859243Sobrien nextword->word = Strsave(STRmmcolormauto); 28959243Sobrien lastword->next = nextword; 29059243Sobrien nextword->prev = lastword; 29159243Sobrien } 29259243Sobrien#endif /* COLOR_LS_F */ 29359243Sobrien lastword = nextword; 29459243Sobrien for (cp = *v; cp; cp = *++v) { 295167465Smp nextword = xcalloc(1, sizeof cmd); 296100616Smp nextword->word = quote(Strsave(cp)); 29759243Sobrien lastword->next = nextword; 29859243Sobrien nextword->prev = lastword; 29959243Sobrien lastword = nextword; 30059243Sobrien } 30159243Sobrien lastword->next = &cmd; 30259243Sobrien cmd.prev = lastword; 303167465Smp cleanup_push(&cmd, lex_cleanup); 30459243Sobrien 30559243Sobrien /* build a syntax tree for the command. */ 30659243Sobrien t = syntax(cmd.next, &cmd, 0); 307167465Smp cleanup_push(t, syntax_cleanup); 30859243Sobrien if (seterr) 30959243Sobrien stderror(ERR_OLD); 31059243Sobrien /* expand aliases like process() does */ 31159243Sobrien /* alias(&cmd); */ 31259243Sobrien /* execute the parse tree. */ 313100616Smp execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL, FALSE); 31459243Sobrien /* done. free the lex list and parse tree. */ 315167465Smp cleanup_until(&cmd); 31659243Sobrien if (setintr) 317167465Smp cleanup_until(&pintr_disabled); 31859243Sobrien } 31959243Sobrien else { 320167465Smp Char *dp, *tmp; 321167465Smp struct Strbuf buf = Strbuf_INIT; 32259243Sobrien 323167465Smp cleanup_push(&buf, Strbuf_cleanup); 32459243Sobrien for (k = 0, i = 0; v[k] != NULL; k++) { 32559243Sobrien tmp = dnormalize(v[k], symlinks == SYM_IGNORE); 326167465Smp cleanup_push(tmp, xfree); 327167465Smp dp = Strend(tmp) - 1; 32859243Sobrien if (*dp == '/' && dp != tmp) 32959243Sobrien#ifdef apollo 33059243Sobrien if (dp != &tmp[1]) 33159243Sobrien#endif /* apollo */ 33259243Sobrien *dp = '\0'; 333167465Smp if (stat(short2str(tmp), &st) == -1) { 334167465Smp int err; 335167465Smp 336167465Smp err = errno; 33759243Sobrien if (k != i) { 33859243Sobrien if (i != 0) 33959243Sobrien xputchar('\n'); 34059243Sobrien print_by_column(STRNULL, &v[i], k - i, FALSE); 34159243Sobrien } 342316958Sdchagin haderr = 1; 343167465Smp xprintf("%S: %s.\n", tmp, strerror(err)); 344316958Sdchagin haderr = 0; 34559243Sobrien i = k + 1; 346316958Sdchagin ret = 1; 34759243Sobrien } 34859243Sobrien else if (S_ISDIR(st.st_mode)) { 34959243Sobrien Char *cp; 35059243Sobrien 35159243Sobrien if (k != i) { 35259243Sobrien if (i != 0) 35359243Sobrien xputchar('\n'); 35459243Sobrien print_by_column(STRNULL, &v[i], k - i, FALSE); 35559243Sobrien } 35659243Sobrien if (k != 0 && v[1] != NULL) 35759243Sobrien xputchar('\n'); 35859243Sobrien xprintf("%S:\n", tmp); 359167465Smp buf.len = 0; 360167465Smp for (cp = tmp; *cp; cp++) 361167465Smp Strbuf_append1(&buf, (*cp | QUOTE)); 362167465Smp Strbuf_terminate(&buf); 363167465Smp dp = &buf.s[buf.len - 1]; 36459243Sobrien if ( 36569408Sache#ifdef WINNT_NATIVE 366167465Smp (*dp != (Char) (':' | QUOTE)) && 36769408Sache#endif /* WINNT_NATIVE */ 368167465Smp (*dp != (Char) ('/' | QUOTE))) { 369167465Smp Strbuf_append1(&buf, '/'); 370167465Smp Strbuf_terminate(&buf); 371167465Smp } else 372167465Smp *dp &= TRIM; 373167465Smp (void) t_search(&buf, LIST, TW_ZERO, 0, STRNULL, 0); 37459243Sobrien i = k + 1; 37559243Sobrien } 376167465Smp cleanup_until(tmp); 37759243Sobrien } 378167465Smp cleanup_until(&buf); 37959243Sobrien if (k != i) { 38059243Sobrien if (i != 0) 38159243Sobrien xputchar('\n'); 38259243Sobrien print_by_column(STRNULL, &v[i], k - i, FALSE); 38359243Sobrien } 384316958Sdchagin if (ret) 385316958Sdchagin stderror(ERR_SILENT); 38659243Sobrien } 38759243Sobrien 388167465Smp cleanup_until(globbed); 38959243Sobrien} 39059243Sobrien 391145479Smpextern int GotTermCaps; 39259243Sobrien 39359243Sobrien/*ARGSUSED*/ 39459243Sobrienvoid 395167465Smpdotelltc(Char **v, struct command *c) 39659243Sobrien{ 397145479Smp USE(v); 39859243Sobrien USE(c); 39959243Sobrien if (!GotTermCaps) 40059243Sobrien GetTermCaps(); 401145479Smp TellTC(); 40259243Sobrien} 40359243Sobrien 40459243Sobrien/*ARGSUSED*/ 40559243Sobrienvoid 406167465Smpdoechotc(Char **v, struct command *c) 40759243Sobrien{ 408145479Smp USE(c); 40959243Sobrien if (!GotTermCaps) 41059243Sobrien GetTermCaps(); 41159243Sobrien EchoTC(++v); 41259243Sobrien} 41359243Sobrien 41459243Sobrien/*ARGSUSED*/ 41559243Sobrienvoid 416167465Smpdosettc(Char **v, struct command *c) 41759243Sobrien{ 418167465Smp char *tv[2]; 41959243Sobrien 420145479Smp USE(c); 42159243Sobrien if (!GotTermCaps) 42259243Sobrien GetTermCaps(); 42359243Sobrien 424167465Smp tv[0] = strsave(short2str(v[1])); 425167465Smp cleanup_push(tv[0], xfree); 426167465Smp tv[1] = strsave(short2str(v[2])); 427167465Smp cleanup_push(tv[1], xfree); 42859243Sobrien SetTC(tv[0], tv[1]); 429167465Smp cleanup_until(tv[0]); 43059243Sobrien} 43159243Sobrien 43259243Sobrien/* The dowhich() is by: 43359243Sobrien * Andreas Luik <luik@isaak.isa.de> 43459243Sobrien * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 43559243Sobrien * Azenberstr. 35 43659243Sobrien * D-7000 Stuttgart 1 43759243Sobrien * West-Germany 43859243Sobrien * Thanks!! 43959243Sobrien */ 44059243Sobrienint 441167465Smpcmd_expand(Char *cmd, Char **str) 44259243Sobrien{ 44359243Sobrien struct wordent lexp[3]; 44459243Sobrien struct varent *vp; 44559243Sobrien int rv = TRUE; 44659243Sobrien 44759243Sobrien lexp[0].next = &lexp[1]; 44859243Sobrien lexp[1].next = &lexp[2]; 44959243Sobrien lexp[2].next = &lexp[0]; 45059243Sobrien 45159243Sobrien lexp[0].prev = &lexp[2]; 45259243Sobrien lexp[1].prev = &lexp[0]; 45359243Sobrien lexp[2].prev = &lexp[1]; 45459243Sobrien 45559243Sobrien lexp[0].word = STRNULL; 45659243Sobrien lexp[2].word = STRret; 45759243Sobrien 458100616Smp if ((vp = adrof1(cmd, &aliases)) != NULL && vp->vec != NULL) { 45959243Sobrien if (str == NULL) { 46059243Sobrien xprintf(CGETS(22, 1, "%S: \t aliased to "), cmd); 46159243Sobrien blkpr(vp->vec); 46259243Sobrien xputchar('\n'); 46359243Sobrien } 464167465Smp else 465167465Smp *str = blkexpand(vp->vec); 46659243Sobrien } 46759243Sobrien else { 46859243Sobrien lexp[1].word = cmd; 46959243Sobrien rv = tellmewhat(lexp, str); 47059243Sobrien } 47159243Sobrien return rv; 47259243Sobrien} 47359243Sobrien 47459243Sobrien 47559243Sobrien/*ARGSUSED*/ 47659243Sobrienvoid 477167465Smpdowhich(Char **v, struct command *c) 47859243Sobrien{ 47959243Sobrien int rv = TRUE; 48059243Sobrien USE(c); 48159243Sobrien 482167465Smp /* 48359243Sobrien * We don't want to glob dowhich args because we lose quoteing 48459243Sobrien * E.g. which \ls if ls is aliased will not work correctly if 48559243Sobrien * we glob here. 48659243Sobrien */ 48759243Sobrien 48859243Sobrien while (*++v) 48959243Sobrien rv &= cmd_expand(*v, NULL); 49059243Sobrien 49159243Sobrien if (!rv) 492167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 49359243Sobrien} 49459243Sobrien 495316958Sdchaginstatic int 496316958Sdchaginfindvv(Char **vv, const char *cp) 497316958Sdchagin{ 498316958Sdchagin for (; vv && *vv; vv++) { 499316958Sdchagin size_t i; 500316958Sdchagin for (i = 0; (*vv)[i] && (*vv)[i] == cp[i]; i++) 501316958Sdchagin continue; 502316958Sdchagin if ((*vv)[i] == '\0' && cp[i] == '\0') 503316958Sdchagin return 1; 504316958Sdchagin } 505316958Sdchagin return 0; 506316958Sdchagin} 507316958Sdchagin 50859243Sobrien/* PWP: a hack to start up your stopped editor on a single keystroke */ 50959243Sobrien/* jbs - fixed hack so it worked :-) 3/28/89 */ 51059243Sobrien 51159243Sobrienstruct process * 512167465Smpfind_stop_ed(void) 51359243Sobrien{ 514145479Smp struct process *pp, *retp; 515316958Sdchagin const char *ep = NULL, *vp = NULL; 516145479Smp char *cp, *p; 517316958Sdchagin size_t epl = 0, vpl = 0; 518167465Smp int pstatus; 519316958Sdchagin struct varent *varp; 520316958Sdchagin Char **vv; 52159243Sobrien 522316958Sdchagin if (pcurrent == NULL) /* see if we have any jobs */ 523316958Sdchagin return NULL; /* nope */ 52459243Sobrien 525316958Sdchagin if ((varp = adrof(STReditors)) != NULL) 526316958Sdchagin vv = varp->vec; 527316958Sdchagin else 528316958Sdchagin vv = NULL; 52959243Sobrien 530316958Sdchagin if (! vv) { 531316958Sdchagin if ((ep = getenv("EDITOR")) != NULL) { /* if we have a value */ 532316958Sdchagin if ((p = strrchr(ep, '/')) != NULL) /* if it has a path */ 533316958Sdchagin ep = p + 1; /* then we want only the last part */ 534316958Sdchagin } 535316958Sdchagin else 536316958Sdchagin ep = "ed"; 53759243Sobrien 538316958Sdchagin if ((vp = getenv("VISUAL")) != NULL) { /* if we have a value */ 539316958Sdchagin if ((p = strrchr(vp, '/')) != NULL) /* and it has a path */ 540316958Sdchagin vp = p + 1; /* then we want only the last part */ 541316958Sdchagin } 542316958Sdchagin else 543316958Sdchagin vp = "vi"; 54459243Sobrien 545316958Sdchagin for (vpl = 0; vp[vpl] && !isspace((unsigned char)vp[vpl]); vpl++) 546316958Sdchagin continue; 547316958Sdchagin for (epl = 0; ep[epl] && !isspace((unsigned char)ep[epl]); epl++) 548316958Sdchagin continue; 549316958Sdchagin } 550316958Sdchagin 55159243Sobrien retp = NULL; 55259243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) 55359243Sobrien if (pp->p_procid == pp->p_jobid) { 55459243Sobrien 55559243Sobrien /* 55659243Sobrien * Only foreground an edit session if it is suspended. Some GUI 55759243Sobrien * editors have may be happily running in a separate window, no 55859243Sobrien * point in foregrounding these if they're already running - webb 55959243Sobrien */ 56059243Sobrien pstatus = (int) (pp->p_flags & PALLSTATES); 56159243Sobrien if (pstatus != PINTERRUPTED && pstatus != PSTOPPED && 56259243Sobrien pstatus != PSIGNALED) 56359243Sobrien continue; 56459243Sobrien 56559243Sobrien p = short2str(pp->p_command); 56659243Sobrien /* get the first word */ 56759243Sobrien for (cp = p; *cp && !isspace((unsigned char) *cp); cp++) 56859243Sobrien continue; 56959243Sobrien *cp = '\0'; 57059243Sobrien 57159243Sobrien if ((cp = strrchr(p, '/')) != NULL) /* and it has a path */ 57259243Sobrien cp = cp + 1; /* then we want only the last part */ 57359243Sobrien else 57459243Sobrien cp = p; /* else we get all of it */ 57559243Sobrien 576316958Sdchagin /* 577316958Sdchagin * If we find the current name in the $editors array (if set) 578316958Sdchagin * or as $EDITOR or $VISUAL (if $editors not set), fg it. 579316958Sdchagin */ 580316958Sdchagin if ((vv && findvv(vv, cp)) || 581316958Sdchagin (epl && strncmp(ep, cp, epl) == 0 && cp[epl] == '\0') || 582316958Sdchagin (vpl && strncmp(vp, cp, vpl) == 0 && cp[vpl] == '\0')) { 58359243Sobrien /* 58459243Sobrien * If there is a choice, then choose the current process if 58559243Sobrien * available, or the previous process otherwise, or else 58659243Sobrien * anything will do - Robert Webb (robertw@mulga.cs.mu.oz.au). 58759243Sobrien */ 58859243Sobrien if (pp == pcurrent) 58959243Sobrien return pp; 59059243Sobrien else if (retp == NULL || pp == pprevious) 59159243Sobrien retp = pp; 59259243Sobrien } 59359243Sobrien } 59459243Sobrien 59559243Sobrien return retp; /* Will be NULL if we didn't find a job */ 59659243Sobrien} 59759243Sobrien 59859243Sobrienvoid 599167465Smpfg_proc_entry(struct process *pp) 60059243Sobrien{ 60159243Sobrien jmp_buf_t osetexit; 602145479Smp int ohaderr; 60359243Sobrien Char oGettingInput; 604167465Smp size_t omark; 60559243Sobrien 60659243Sobrien getexit(osetexit); 60759243Sobrien 608167465Smp pintr_disabled++; 60959243Sobrien oGettingInput = GettingInput; 61059243Sobrien GettingInput = 0; 61159243Sobrien 61259243Sobrien ohaderr = haderr; /* we need to ignore setting of haderr due to 61359243Sobrien * process getting stopped by a signal */ 614167465Smp omark = cleanup_push_mark(); 61559243Sobrien if (setexit() == 0) { /* come back here after pjwait */ 61659243Sobrien pendjob(); 61759243Sobrien (void) alarm(0); /* No autologout */ 618167465Smp alrmcatch_disabled = 1; 61959243Sobrien if (!pstart(pp, 1)) { 62059243Sobrien pp->p_procid = 0; 62159243Sobrien stderror(ERR_BADJOB, pp->p_command, strerror(errno)); 62259243Sobrien } 62359243Sobrien pjwait(pp); 62459243Sobrien } 62559243Sobrien setalarm(1); /* Autologout back on */ 626167465Smp cleanup_pop_mark(omark); 62759243Sobrien resexit(osetexit); 62859243Sobrien haderr = ohaderr; 62959243Sobrien GettingInput = oGettingInput; 63059243Sobrien 631167465Smp disabled_cleanup(&pintr_disabled); 63259243Sobrien} 63359243Sobrien 63459243Sobrienstatic char * 635167465Smpxgetpass(const char *prm) 63659243Sobrien{ 637167465Smp static struct strbuf pass; /* = strbuf_INIT; */ 638167465Smp int fd; 639167465Smp sigset_t oset, set; 640167465Smp struct sigaction sa, osa; 64159243Sobrien 642167465Smp sa.sa_handler = SIG_IGN; 643167465Smp sigemptyset(&sa.sa_mask); 644167465Smp sa.sa_flags = 0; 645167465Smp (void)sigaction(SIGINT, &sa, &osa); 646167465Smp 647167465Smp sigemptyset(&set); 648167465Smp sigaddset(&set, SIGINT); 649167465Smp (void)sigprocmask(SIG_UNBLOCK, &set, &oset); 650167465Smp 651167465Smp cleanup_push(&osa, sigint_cleanup); 652167465Smp cleanup_push(&oset, sigprocmask_cleanup); 65359243Sobrien (void) Rawmode(); /* Make sure, cause we want echo off */ 654167465Smp fd = xopen("/dev/tty", O_RDWR|O_LARGEFILE); 655167465Smp if (fd == -1) 65659243Sobrien fd = SHIN; 657167465Smp else 658167465Smp cleanup_push(&fd, open_cleanup); 65959243Sobrien 66059243Sobrien xprintf("%s", prm); flush(); 661167465Smp pass.len = 0; 662167465Smp for (;;) { 663167465Smp char c; 664167465Smp 665167465Smp if (xread(fd, &c, 1) < 1 || c == '\n') 66659243Sobrien break; 667167465Smp strbuf_append1(&pass, c); 66859243Sobrien } 669167465Smp strbuf_terminate(&pass); 67059243Sobrien 671180637Skeramida cleanup_until(&osa); 67259243Sobrien 673167465Smp return pass.s; 67459243Sobrien} 675167465Smp 676145479Smp#ifndef NO_CRYPT 677167465Smp#if !HAVE_DECL_CRYPT 678167465Smp extern char *crypt (); 679145479Smp#endif 680167465Smp#ifdef HAVE_CRYPT_H 681145479Smp#include <crypt.h> 682145479Smp#endif 683145479Smp#endif 684145479Smp 68559243Sobrien/* 68659243Sobrien * Ask the user for his login password to continue working 68759243Sobrien * On systems that have a shadow password, this will only 68859243Sobrien * work for root, but what can we do? 68959243Sobrien * 69059243Sobrien * If we fail to get the password, then we log the user out 69159243Sobrien * immediately 69259243Sobrien */ 69359243Sobrien/*ARGSUSED*/ 69459243Sobrienstatic void 695167465Smpauto_lock(void) 69659243Sobrien{ 69759243Sobrien#ifndef NO_CRYPT 69859243Sobrien 69959243Sobrien int i; 70059243Sobrien char *srpp = NULL; 70159243Sobrien struct passwd *pw; 70259243Sobrien 70359243Sobrien#undef XCRYPT 70459243Sobrien 705167465Smp#if defined(HAVE_AUTH_H) && defined(HAVE_GETAUTHUID) 70659243Sobrien 70759243Sobrien struct authorization *apw; 708167465Smp extern char *crypt16 (const char *, const char *); 70959243Sobrien 710231990Smp# define XCRYPT(pw, a, b) crypt16(a, b) 71159243Sobrien 712167465Smp if ((pw = xgetpwuid(euid)) != NULL && /* effective user passwd */ 71359243Sobrien (apw = getauthuid(euid)) != NULL) /* enhanced ultrix passwd */ 71459243Sobrien srpp = apw->a_password; 71559243Sobrien 716145479Smp#elif defined(HAVE_SHADOW_H) 71759243Sobrien 71859243Sobrien struct spwd *spw; 71959243Sobrien 720231990Smp# define XCRYPT(pw, a, b) crypt(a, b) 72159243Sobrien 722167465Smp if ((pw = xgetpwuid(euid)) != NULL) { /* effective user passwd */ 723167465Smp errno = 0; 724167465Smp while ((spw = getspnam(pw->pw_name)) == NULL && errno == EINTR) { 725167465Smp handle_pending_signals(); 726167465Smp errno = 0; 727167465Smp } 728167465Smp if (spw != NULL) /* shadowed passwd */ 729167465Smp srpp = spw->sp_pwdp; 730167465Smp } 73159243Sobrien 732145479Smp#else 73359243Sobrien 73459243Sobrien 735231990Smp#ifdef __CYGWIN__ 736231990Smp# define XCRYPT(pw, a, b) cygwin_xcrypt(pw, a, b) 737231990Smp#else 738231990Smp# define XCRYPT(pw, a, b) crypt(a, b) 739231990Smp#endif 740231990Smp 74169408Sache#if !defined(__MVS__) 742167465Smp if ((pw = xgetpwuid(euid)) != NULL) /* effective user passwd */ 74359243Sobrien srpp = pw->pw_passwd; 74469408Sache#endif /* !MVS */ 74559243Sobrien 746145479Smp#endif 74759243Sobrien 74859243Sobrien if (srpp == NULL) { 749167465Smp auto_logout(); 75059243Sobrien /*NOTREACHED*/ 75159243Sobrien return; 75259243Sobrien } 75359243Sobrien 75459243Sobrien setalarm(0); /* Not for locking any more */ 755167465Smp xputchar('\n'); 75659243Sobrien for (i = 0; i < 5; i++) { 75759243Sobrien const char *crpp; 75859243Sobrien char *pp; 75959243Sobrien#ifdef AFS 76059243Sobrien char *afsname; 76159243Sobrien Char *safs; 76259243Sobrien 76359243Sobrien if ((safs = varval(STRafsuser)) != STRNULL) 76459243Sobrien afsname = short2str(safs); 76559243Sobrien else 76659243Sobrien if ((afsname = getenv("AFSUSER")) == NULL) 76759243Sobrien afsname = pw->pw_name; 76859243Sobrien#endif 769167465Smp pp = xgetpass("Password:"); 77059243Sobrien 771231990Smp crpp = XCRYPT(pw, pp, srpp); 772316958Sdchagin if ((crpp && strcmp(crpp, srpp) == 0) 77359243Sobrien#ifdef AFS 77459243Sobrien || (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, 77559243Sobrien afsname, /* name */ 77659243Sobrien NULL, /* instance */ 77759243Sobrien NULL, /* realm */ 77859243Sobrien pp, /* password */ 77959243Sobrien 0, /* lifetime */ 78059243Sobrien 0, 0, /* spare */ 78159243Sobrien NULL) /* reason */ 78259243Sobrien == 0) 78359243Sobrien#endif /* AFS */ 78459243Sobrien ) { 785167465Smp (void) memset(pp, 0, strlen(pp)); 78659243Sobrien if (GettingInput && !just_signaled) { 78759243Sobrien (void) Rawmode(); 788167465Smp ClearLines(); 789167465Smp ClearDisp(); 79059243Sobrien Refresh(); 79159243Sobrien } 79259243Sobrien just_signaled = 0; 79359243Sobrien return; 79459243Sobrien } 79559243Sobrien xprintf(CGETS(22, 2, "\nIncorrect passwd for %s\n"), pw->pw_name); 79659243Sobrien } 79759243Sobrien#endif /* NO_CRYPT */ 798167465Smp auto_logout(); 79959243Sobrien} 80059243Sobrien 80159243Sobrien 80259243Sobrienstatic void 803167465Smpauto_logout(void) 80459243Sobrien{ 80559243Sobrien xprintf("auto-logout\n"); 80659243Sobrien /* Don't leave the tty in raw mode */ 80759243Sobrien if (editing) 80859243Sobrien (void) Cookedmode(); 809167465Smp xclose(SHIN); 810167465Smp setcopy(STRlogout, STRautomatic, VAR_READWRITE); 81159243Sobrien child = 1; 81259243Sobrien#ifdef TESLA 81359243Sobrien do_logout = 1; 81459243Sobrien#endif /* TESLA */ 81559243Sobrien GettingInput = FALSE; /* make flush() work to write hist files. Huber*/ 81659243Sobrien goodbye(NULL, NULL); 81759243Sobrien} 81859243Sobrien 819167465Smpvoid 820167465Smpalrmcatch(void) 82159243Sobrien{ 822167465Smp (*alm_fun)(); 82359243Sobrien setalarm(1); 82459243Sobrien} 82559243Sobrien 82659243Sobrien/* 82759243Sobrien * Karl Kleinpaste, 21oct1983. 82859243Sobrien * Added precmd(), which checks for the alias 82959243Sobrien * precmd in aliases. If it's there, the alias 83059243Sobrien * is executed as a command. This is done 83159243Sobrien * after mailchk() and just before print- 83259243Sobrien * ing the prompt. Useful for things like printing 83359243Sobrien * one's current directory just before each command. 83459243Sobrien */ 83559243Sobrienvoid 836167465Smpprecmd(void) 83759243Sobrien{ 838167465Smp pintr_disabled++; 839167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 84059243Sobrien if (precmd_active) { /* an error must have been caught */ 84159243Sobrien aliasrun(2, STRunalias, STRprecmd); 842195609Smp xprintf("%s", CGETS(22, 3, "Faulty alias 'precmd' removed.\n")); 84359243Sobrien goto leave; 84459243Sobrien } 84559243Sobrien precmd_active = 1; 84659243Sobrien if (!whyles && adrof1(STRprecmd, &aliases)) 84759243Sobrien aliasrun(1, STRprecmd, NULL); 84859243Sobrienleave: 84959243Sobrien precmd_active = 0; 850167465Smp cleanup_until(&pintr_disabled); 85159243Sobrien} 85259243Sobrien 85359243Sobrienvoid 854167465Smppostcmd(void) 85559243Sobrien{ 856167465Smp pintr_disabled++; 857167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 85859243Sobrien if (postcmd_active) { /* an error must have been caught */ 85959243Sobrien aliasrun(2, STRunalias, STRpostcmd); 860195609Smp xprintf("%s", CGETS(22, 3, "Faulty alias 'postcmd' removed.\n")); 86159243Sobrien goto leave; 86259243Sobrien } 86359243Sobrien postcmd_active = 1; 86459243Sobrien if (!whyles && adrof1(STRpostcmd, &aliases)) 86559243Sobrien aliasrun(1, STRpostcmd, NULL); 86659243Sobrienleave: 86759243Sobrien postcmd_active = 0; 868167465Smp cleanup_until(&pintr_disabled); 86959243Sobrien} 87059243Sobrien 87159243Sobrien/* 87259243Sobrien * Paul Placeway 11/24/87 Added cwd_cmd by hacking precmd() into 87359243Sobrien * submission... Run every time $cwd is set (after it is set). Useful 87459243Sobrien * for putting your machine and cwd (or anything else) in an xterm title 87559243Sobrien * space. 87659243Sobrien */ 87759243Sobrienvoid 878167465Smpcwd_cmd(void) 87959243Sobrien{ 880167465Smp pintr_disabled++; 881167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 88259243Sobrien if (cwdcmd_active) { /* an error must have been caught */ 88359243Sobrien aliasrun(2, STRunalias, STRcwdcmd); 884195609Smp xprintf("%s", CGETS(22, 4, "Faulty alias 'cwdcmd' removed.\n")); 88559243Sobrien goto leave; 88659243Sobrien } 88759243Sobrien cwdcmd_active = 1; 88859243Sobrien if (!whyles && adrof1(STRcwdcmd, &aliases)) 88959243Sobrien aliasrun(1, STRcwdcmd, NULL); 89059243Sobrienleave: 89159243Sobrien cwdcmd_active = 0; 892167465Smp cleanup_until(&pintr_disabled); 89359243Sobrien} 89459243Sobrien 89559243Sobrien/* 89659243Sobrien * Joachim Hoenig 07/16/91 Added beep_cmd, run every time tcsh wishes 89759243Sobrien * to beep the terminal bell. Useful for playing nice sounds instead. 89859243Sobrien */ 89959243Sobrienvoid 900167465Smpbeep_cmd(void) 90159243Sobrien{ 902167465Smp pintr_disabled++; 903167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 90459243Sobrien if (beepcmd_active) { /* an error must have been caught */ 90559243Sobrien aliasrun(2, STRunalias, STRbeepcmd); 906195609Smp xprintf("%s", CGETS(22, 5, "Faulty alias 'beepcmd' removed.\n")); 90759243Sobrien } 90859243Sobrien else { 90959243Sobrien beepcmd_active = 1; 91059243Sobrien if (!whyles && adrof1(STRbeepcmd, &aliases)) 91159243Sobrien aliasrun(1, STRbeepcmd, NULL); 91259243Sobrien } 91359243Sobrien beepcmd_active = 0; 914167465Smp cleanup_until(&pintr_disabled); 91559243Sobrien} 91659243Sobrien 91759243Sobrien 91859243Sobrien/* 91959243Sobrien * Karl Kleinpaste, 18 Jan 1984. 92059243Sobrien * Added period_cmd(), which executes the alias "periodic" every 92159243Sobrien * $tperiod minutes. Useful for occasional checking of msgs and such. 92259243Sobrien */ 92359243Sobrienvoid 924167465Smpperiod_cmd(void) 92559243Sobrien{ 926145479Smp Char *vp; 92759243Sobrien time_t t, interval; 92859243Sobrien 929167465Smp pintr_disabled++; 930167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 93159243Sobrien if (periodic_active) { /* an error must have been caught */ 93259243Sobrien aliasrun(2, STRunalias, STRperiodic); 933195609Smp xprintf("%s", CGETS(22, 6, "Faulty alias 'periodic' removed.\n")); 93459243Sobrien goto leave; 93559243Sobrien } 93659243Sobrien periodic_active = 1; 93759243Sobrien if (!whyles && adrof1(STRperiodic, &aliases)) { 93859243Sobrien vp = varval(STRtperiod); 93959243Sobrien if (vp == STRNULL) { 94059243Sobrien aliasrun(1, STRperiodic, NULL); 94159243Sobrien goto leave; 94259243Sobrien } 94359243Sobrien interval = getn(vp); 94459243Sobrien (void) time(&t); 94559243Sobrien if (t - t_period >= interval * 60) { 94659243Sobrien t_period = t; 94759243Sobrien aliasrun(1, STRperiodic, NULL); 94859243Sobrien } 94959243Sobrien } 95059243Sobrienleave: 95159243Sobrien periodic_active = 0; 952167465Smp cleanup_until(&pintr_disabled); 95359243Sobrien} 95459243Sobrien 95583098Smp 95683098Smp/* 95783098Smp * GrP Greg Parker May 2001 95883098Smp * Added job_cmd(), which is run every time a job is started or 95983098Smp * foregrounded. The command is passed a single argument, the string 96083098Smp * used to start the job originally. With precmd, useful for setting 96183098Smp * xterm titles. 96283098Smp * Cloned from cwd_cmd(). 96383098Smp */ 96483098Smpvoid 965167465Smpjob_cmd(Char *args) 96683098Smp{ 967167465Smp pintr_disabled++; 968167465Smp cleanup_push(&pintr_disabled, disabled_cleanup); 96983098Smp if (jobcmd_active) { /* an error must have been caught */ 97083098Smp aliasrun(2, STRunalias, STRjobcmd); 971195609Smp xprintf("%s", CGETS(22, 14, "Faulty alias 'jobcmd' removed.\n")); 97283098Smp goto leave; 97383098Smp } 97483098Smp jobcmd_active = 1; 975100616Smp if (!whyles && adrof1(STRjobcmd, &aliases)) { 976100616Smp struct process *pp = pcurrjob; /* put things back after the hook */ 97783098Smp aliasrun(2, STRjobcmd, args); 978100616Smp pcurrjob = pp; 979100616Smp } 98083098Smpleave: 98183098Smp jobcmd_active = 0; 982167465Smp cleanup_until(&pintr_disabled); 98383098Smp} 98483098Smp 98583098Smp 98659243Sobrien/* 98759243Sobrien * Karl Kleinpaste, 21oct1983. 98859243Sobrien * Set up a one-word alias command, for use for special things. 98959243Sobrien * This code is based on the mainline of process(). 99059243Sobrien */ 99159243Sobrienvoid 992167465Smpaliasrun(int cnt, Char *s1, Char *s2) 99359243Sobrien{ 99459243Sobrien struct wordent w, *new1, *new2; /* for holding alias name */ 99559243Sobrien struct command *t = NULL; 99659243Sobrien jmp_buf_t osetexit; 99759243Sobrien int status; 998167465Smp size_t omark; 99959243Sobrien 100059243Sobrien getexit(osetexit); 100159243Sobrien if (seterr) { 1002167465Smp xfree(seterr); 100359243Sobrien seterr = NULL; /* don't repeatedly print err msg. */ 100459243Sobrien } 100559243Sobrien w.word = STRNULL; 1006167465Smp new1 = xcalloc(1, sizeof w); 100759243Sobrien new1->word = Strsave(s1); 100859243Sobrien if (cnt == 1) { 100959243Sobrien /* build a lex list with one word. */ 101059243Sobrien w.next = w.prev = new1; 101159243Sobrien new1->next = new1->prev = &w; 101259243Sobrien } 101359243Sobrien else { 101459243Sobrien /* build a lex list with two words. */ 1015167465Smp new2 = xcalloc(1, sizeof w); 101659243Sobrien new2->word = Strsave(s2); 101759243Sobrien w.next = new2->prev = new1; 101859243Sobrien new1->next = w.prev = new2; 101959243Sobrien new1->prev = new2->next = &w; 102059243Sobrien } 1021167465Smp cleanup_push(&w, lex_cleanup); 102259243Sobrien 102359243Sobrien /* Save the old status */ 102459243Sobrien status = getn(varval(STRstatus)); 102559243Sobrien 102659243Sobrien /* expand aliases like process() does. */ 102759243Sobrien alias(&w); 102859243Sobrien /* build a syntax tree for the command. */ 102959243Sobrien t = syntax(w.next, &w, 0); 1030167465Smp cleanup_push(t, syntax_cleanup); 103159243Sobrien if (seterr) 103259243Sobrien stderror(ERR_OLD); 103359243Sobrien 103459243Sobrien psavejob(); 1035167465Smp cleanup_push(&cnt, psavejob_cleanup); /* cnt is used only as a marker */ 103659243Sobrien 103759243Sobrien /* catch any errors here */ 1038167465Smp omark = cleanup_push_mark(); 103959243Sobrien if (setexit() == 0) 104059243Sobrien /* execute the parse tree. */ 104159243Sobrien /* 104259243Sobrien * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 104359243Sobrien * was execute(t, tpgrp); 104459243Sobrien */ 1045100616Smp execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL, TRUE); 1046167465Smp /* reset the error catcher to the old place */ 1047167465Smp cleanup_pop_mark(omark); 1048167465Smp resexit(osetexit); 104959243Sobrien if (haderr) { 105059243Sobrien haderr = 0; 105159243Sobrien /* 105259243Sobrien * Either precmd, or cwdcmd, or periodic had an error. Call it again so 105359243Sobrien * that it is removed 105459243Sobrien */ 105559243Sobrien if (precmd_active) 105659243Sobrien precmd(); 105759243Sobrien if (postcmd_active) 105859243Sobrien postcmd(); 105959243Sobrien#ifdef notdef 106059243Sobrien /* 106159243Sobrien * XXX: On the other hand, just interrupting them causes an error too. 106259243Sobrien * So if we hit ^C in the middle of cwdcmd or periodic the alias gets 106359243Sobrien * removed. We don't want that. Note that we want to remove precmd 106459243Sobrien * though, cause that could lead into an infinite loop. This should be 106559243Sobrien * fixed correctly, but then haderr should give us the whole exit 106659243Sobrien * status not just true or false. 106759243Sobrien */ 106859243Sobrien else if (cwdcmd_active) 106959243Sobrien cwd_cmd(); 107059243Sobrien else if (beepcmd_active) 107159243Sobrien beep_cmd(); 107259243Sobrien else if (periodic_active) 107359243Sobrien period_cmd(); 107459243Sobrien#endif /* notdef */ 107559243Sobrien } 1076167465Smp cleanup_until(&w); 107759243Sobrien pendjob(); 107859243Sobrien /* Restore status */ 1079231990Smp setv(STRstatus, putn((tcsh_number_t)status), VAR_READWRITE); 108059243Sobrien} 108159243Sobrien 108259243Sobrienvoid 1083167465Smpsetalarm(int lck) 108459243Sobrien{ 108559243Sobrien struct varent *vp; 108659243Sobrien Char *cp; 108759243Sobrien unsigned alrm_time = 0, logout_time, lock_time; 108859243Sobrien time_t cl, nl, sched_dif; 108959243Sobrien 1090100616Smp if ((vp = adrof(STRautologout)) != NULL && vp->vec != NULL) { 109159243Sobrien if ((cp = vp->vec[0]) != 0) { 109259243Sobrien if ((logout_time = (unsigned) atoi(short2str(cp)) * 60) > 0) { 1093145479Smp#ifdef SOLARIS2 1094145479Smp /* 1095145479Smp * Solaris alarm(2) uses a timer based in clock ticks 1096145479Smp * internally so it multiplies our value with CLK_TCK... 1097145479Smp * Of course that can overflow leading to unexpected 1098145479Smp * results, so we clip it here. Grr. Where is that 1099145479Smp * documented folks? 1100145479Smp */ 1101145479Smp if (logout_time >= 0x7fffffff / CLK_TCK) 1102145479Smp logout_time = 0x7fffffff / CLK_TCK; 1103145479Smp#endif /* SOLARIS2 */ 110459243Sobrien alrm_time = logout_time; 110559243Sobrien alm_fun = auto_logout; 110659243Sobrien } 110759243Sobrien } 110859243Sobrien if ((cp = vp->vec[1]) != 0) { 110959243Sobrien if ((lock_time = (unsigned) atoi(short2str(cp)) * 60) > 0) { 111059243Sobrien if (lck) { 111159243Sobrien if (alrm_time == 0 || lock_time < alrm_time) { 111259243Sobrien alrm_time = lock_time; 111359243Sobrien alm_fun = auto_lock; 111459243Sobrien } 111559243Sobrien } 111659243Sobrien else /* lock_time always < alrm_time */ 111759243Sobrien if (alrm_time) 111859243Sobrien alrm_time -= lock_time; 111959243Sobrien } 112059243Sobrien } 112159243Sobrien } 112259243Sobrien if ((nl = sched_next()) != -1) { 112359243Sobrien (void) time(&cl); 112459243Sobrien sched_dif = nl > cl ? nl - cl : 0; 112559243Sobrien if ((alrm_time == 0) || ((unsigned) sched_dif < alrm_time)) { 112659243Sobrien alrm_time = ((unsigned) sched_dif) + 1; 112759243Sobrien alm_fun = sched_run; 112859243Sobrien } 112959243Sobrien } 1130167465Smp alrmcatch_disabled = 0; 113159243Sobrien (void) alarm(alrm_time); /* Autologout ON */ 113259243Sobrien} 113359243Sobrien 113459243Sobrien#undef RMDEBUG /* For now... */ 113559243Sobrien 113659243Sobrienvoid 1137167465Smprmstar(struct wordent *cp) 113859243Sobrien{ 113959243Sobrien struct wordent *we, *args; 1140145479Smp struct wordent *tmp, *del; 114159243Sobrien 114259243Sobrien#ifdef RMDEBUG 114359243Sobrien static Char STRrmdebug[] = {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'}; 114459243Sobrien Char *tag; 114559243Sobrien#endif /* RMDEBUG */ 114659243Sobrien Char *charac; 1147316958Sdchagin int ask, doit, star = 0, silent = 0, opintr_disabled; 114859243Sobrien 114959243Sobrien if (!adrof(STRrmstar)) 115059243Sobrien return; 115159243Sobrien#ifdef RMDEBUG 115259243Sobrien tag = varval(STRrmdebug); 115359243Sobrien#endif /* RMDEBUG */ 115459243Sobrien we = cp->next; 115559243Sobrien while (*we->word == ';' && we != cp) 115659243Sobrien we = we->next; 1157316958Sdchagin opintr_disabled = pintr_disabled; 1158316958Sdchagin pintr_disabled = 0; 115959243Sobrien while (we != cp) { 116059243Sobrien#ifdef RMDEBUG 116159243Sobrien if (*tag) 116259243Sobrien xprintf(CGETS(22, 7, "parsing command line\n")); 116359243Sobrien#endif /* RMDEBUG */ 116459243Sobrien if (!Strcmp(we->word, STRrm)) { 116559243Sobrien args = we->next; 116659243Sobrien ask = (*args->word != '-'); 116759243Sobrien while (*args->word == '-' && !silent) { /* check options */ 116859243Sobrien for (charac = (args->word + 1); *charac && !silent; charac++) 116959243Sobrien silent = (*charac == 'i' || *charac == 'f'); 117059243Sobrien args = args->next; 117159243Sobrien } 117259243Sobrien ask = (ask || (!ask && !silent)); 117359243Sobrien if (ask) { 117459243Sobrien for (; !star && *args->word != ';' 117559243Sobrien && args != cp; args = args->next) 117659243Sobrien if (!Strcmp(args->word, STRstar)) 117759243Sobrien star = 1; 117859243Sobrien if (ask && star) { 1179316958Sdchagin doit = getYN(CGETS(22, 8, 1180316958Sdchagin "Do you really want to delete all files? [N/y] ")); 118159243Sobrien if (!doit) { 118259243Sobrien /* remove the command instead */ 118359243Sobrien#ifdef RMDEBUG 118459243Sobrien if (*tag) 118559243Sobrien xprintf(CGETS(22, 9, 118659243Sobrien "skipping deletion of files!\n")); 118759243Sobrien#endif /* RMDEBUG */ 118859243Sobrien for (tmp = we; 118959243Sobrien *tmp->word != '\n' && 119059243Sobrien *tmp->word != ';' && tmp != cp;) { 119159243Sobrien tmp->prev->next = tmp->next; 119259243Sobrien tmp->next->prev = tmp->prev; 1193167465Smp xfree(tmp->word); 119459243Sobrien del = tmp; 119559243Sobrien tmp = tmp->next; 1196167465Smp xfree(del); 119759243Sobrien } 119859243Sobrien if (*tmp->word == ';') { 119959243Sobrien tmp->prev->next = tmp->next; 120059243Sobrien tmp->next->prev = tmp->prev; 1201167465Smp xfree(tmp->word); 120259243Sobrien del = tmp; 120383098Smp tmp = tmp->next; 1204167465Smp xfree(del); 120559243Sobrien } 120683098Smp we = tmp; 120783098Smp continue; 120859243Sobrien } 120959243Sobrien } 121059243Sobrien } 121159243Sobrien } 121259243Sobrien for (we = we->next; 121359243Sobrien *we->word != ';' && we != cp; 121459243Sobrien we = we->next) 121559243Sobrien continue; 121659243Sobrien if (*we->word == ';') 121759243Sobrien we = we->next; 121859243Sobrien } 121959243Sobrien#ifdef RMDEBUG 122059243Sobrien if (*tag) { 122159243Sobrien xprintf(CGETS(22, 10, "command line now is:\n")); 122259243Sobrien for (we = cp->next; we != cp; we = we->next) 122359243Sobrien xprintf("%S ", we->word); 122459243Sobrien } 122559243Sobrien#endif /* RMDEBUG */ 1226316958Sdchagin pintr_disabled = opintr_disabled; 122759243Sobrien return; 122859243Sobrien} 122959243Sobrien 123059243Sobrien#ifdef BSDJOBS 123159243Sobrien/* Check if command is in continue list 123259243Sobrien and do a "aliasing" if it exists as a job in background */ 123359243Sobrien 123459243Sobrien#undef CNDEBUG /* For now */ 123559243Sobrienvoid 1236167465Smpcontinue_jobs(struct wordent *cp) 123759243Sobrien{ 123859243Sobrien struct wordent *we; 1239145479Smp struct process *pp, *np; 124059243Sobrien Char *cmd, *continue_list, *continue_args_list; 124159243Sobrien 124259243Sobrien#ifdef CNDEBUG 124359243Sobrien Char *tag; 124459243Sobrien static Char STRcndebug[] = 124559243Sobrien {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'}; 124659243Sobrien#endif /* CNDEBUG */ 1247145479Smp int in_cont_list, in_cont_arg_list; 124859243Sobrien 124959243Sobrien 125059243Sobrien#ifdef CNDEBUG 125159243Sobrien tag = varval(STRcndebug); 125259243Sobrien#endif /* CNDEBUG */ 125359243Sobrien continue_list = varval(STRcontinue); 125459243Sobrien continue_args_list = varval(STRcontinue_args); 125559243Sobrien if (*continue_list == '\0' && *continue_args_list == '\0') 125659243Sobrien return; 125759243Sobrien 125859243Sobrien we = cp->next; 125959243Sobrien while (*we->word == ';' && we != cp) 126059243Sobrien we = we->next; 126159243Sobrien while (we != cp) { 126259243Sobrien#ifdef CNDEBUG 126359243Sobrien if (*tag) 126459243Sobrien xprintf(CGETS(22, 11, "parsing command line\n")); 126559243Sobrien#endif /* CNDEBUG */ 126659243Sobrien cmd = we->word; 126759243Sobrien in_cont_list = inlist(continue_list, cmd); 126859243Sobrien in_cont_arg_list = inlist(continue_args_list, cmd); 126959243Sobrien if (in_cont_list || in_cont_arg_list) { 127059243Sobrien#ifdef CNDEBUG 127159243Sobrien if (*tag) 127259243Sobrien xprintf(CGETS(22, 12, "in one of the lists\n")); 127359243Sobrien#endif /* CNDEBUG */ 127459243Sobrien np = NULL; 127559243Sobrien for (pp = proclist.p_next; pp; pp = pp->p_next) { 127659243Sobrien if (prefix(cmd, pp->p_command)) { 127759243Sobrien if (pp->p_index) { 127859243Sobrien np = pp; 127959243Sobrien break; 128059243Sobrien } 128159243Sobrien } 128259243Sobrien } 128359243Sobrien if (np) { 128459243Sobrien insert(we, in_cont_arg_list); 128559243Sobrien } 128659243Sobrien } 128759243Sobrien for (we = we->next; 128859243Sobrien *we->word != ';' && we != cp; 128959243Sobrien we = we->next) 129059243Sobrien continue; 129159243Sobrien if (*we->word == ';') 129259243Sobrien we = we->next; 129359243Sobrien } 129459243Sobrien#ifdef CNDEBUG 129559243Sobrien if (*tag) { 129659243Sobrien xprintf(CGETS(22, 13, "command line now is:\n")); 129759243Sobrien for (we = cp->next; we != cp; we = we->next) 129859243Sobrien xprintf("%S ", we->word); 129959243Sobrien } 130059243Sobrien#endif /* CNDEBUG */ 130159243Sobrien return; 130259243Sobrien} 130359243Sobrien 130459243Sobrien/* The actual "aliasing" of for backgrounds() is done here 130559243Sobrien with the aid of insert_we(). */ 130659243Sobrienstatic void 1307167465Smpinsert(struct wordent *pl, int file_args) 130859243Sobrien{ 130959243Sobrien struct wordent *now, *last; 131059243Sobrien Char *cmd, *bcmd, *cp1, *cp2; 1311167465Smp size_t cmd_len; 1312145479Smp Char *upause = STRunderpause; 1313167465Smp size_t p_len = Strlen(upause); 131459243Sobrien 1315167465Smp cmd_len = Strlen(pl->word); 1316167465Smp cmd = xcalloc(1, (cmd_len + 1) * sizeof(Char)); 131759243Sobrien (void) Strcpy(cmd, pl->word); 131859243Sobrien/* Do insertions at beginning, first replace command word */ 131959243Sobrien 132059243Sobrien if (file_args) { 132159243Sobrien now = pl; 1322167465Smp xfree(now->word); 1323167465Smp now->word = xcalloc(1, 5 * sizeof(Char)); 132459243Sobrien (void) Strcpy(now->word, STRecho); 132559243Sobrien 1326167465Smp now = xcalloc(1, sizeof(struct wordent)); 1327167465Smp now->word = xcalloc(1, 6 * sizeof(Char)); 132859243Sobrien (void) Strcpy(now->word, STRbackqpwd); 132959243Sobrien insert_we(now, pl); 133059243Sobrien 133159243Sobrien for (last = now; *last->word != '\n' && *last->word != ';'; 133259243Sobrien last = last->next) 133359243Sobrien continue; 133459243Sobrien 1335167465Smp now = xcalloc(1, sizeof(struct wordent)); 1336167465Smp now->word = xcalloc(1, 2 * sizeof(Char)); 133759243Sobrien (void) Strcpy(now->word, STRgt); 133859243Sobrien insert_we(now, last->prev); 133959243Sobrien 1340167465Smp now = xcalloc(1, sizeof(struct wordent)); 1341167465Smp now->word = xcalloc(1, 2 * sizeof(Char)); 134259243Sobrien (void) Strcpy(now->word, STRbang); 134359243Sobrien insert_we(now, last->prev); 134459243Sobrien 1345167465Smp now = xcalloc(1, sizeof(struct wordent)); 1346167465Smp now->word = xcalloc(1, (cmd_len + p_len + 4) * sizeof(Char)); 134759243Sobrien cp1 = now->word; 134859243Sobrien cp2 = cmd; 134959243Sobrien *cp1++ = '~'; 135059243Sobrien *cp1++ = '/'; 135159243Sobrien *cp1++ = '.'; 135259243Sobrien while ((*cp1++ = *cp2++) != '\0') 135359243Sobrien continue; 135459243Sobrien cp1--; 1355145479Smp cp2 = upause; 135659243Sobrien while ((*cp1++ = *cp2++) != '\0') 135759243Sobrien continue; 135859243Sobrien insert_we(now, last->prev); 135959243Sobrien 1360167465Smp now = xcalloc(1, sizeof(struct wordent)); 1361167465Smp now->word = xcalloc(1, 2 * sizeof(Char)); 136259243Sobrien (void) Strcpy(now->word, STRsemi); 136359243Sobrien insert_we(now, last->prev); 1364167465Smp bcmd = xcalloc(1, (cmd_len + 2) * sizeof(Char)); 1365167465Smp *bcmd = '%'; 1366167465Smp Strcpy(bcmd + 1, cmd); 1367167465Smp now = xcalloc(1, sizeof(struct wordent)); 136859243Sobrien now->word = bcmd; 136959243Sobrien insert_we(now, last->prev); 137059243Sobrien } 137159243Sobrien else { 137259243Sobrien struct wordent *del; 137359243Sobrien 137459243Sobrien now = pl; 1375167465Smp xfree(now->word); 1376167465Smp now->word = xcalloc(1, (cmd_len + 2) * sizeof(Char)); 1377167465Smp *now->word = '%'; 1378167465Smp Strcpy(now->word + 1, cmd); 137959243Sobrien for (now = now->next; 138059243Sobrien *now->word != '\n' && *now->word != ';' && now != pl;) { 138159243Sobrien now->prev->next = now->next; 138259243Sobrien now->next->prev = now->prev; 1383167465Smp xfree(now->word); 138459243Sobrien del = now; 138559243Sobrien now = now->next; 1386167465Smp xfree(del); 138759243Sobrien } 138859243Sobrien } 138959243Sobrien} 139059243Sobrien 139159243Sobrienstatic void 1392167465Smpinsert_we(struct wordent *new, struct wordent *where) 139359243Sobrien{ 139459243Sobrien 139559243Sobrien new->prev = where; 139659243Sobrien new->next = where->next; 139759243Sobrien where->next = new; 139859243Sobrien new->next->prev = new; 139959243Sobrien} 140059243Sobrien 140159243Sobrienstatic int 1402167465Smpinlist(Char *list, Char *name) 140359243Sobrien{ 1404145479Smp Char *l, *n; 140559243Sobrien 140659243Sobrien l = list; 140759243Sobrien n = name; 140859243Sobrien 140959243Sobrien while (*l && *n) { 141059243Sobrien if (*l == *n) { 141159243Sobrien l++; 141259243Sobrien n++; 141359243Sobrien if (*n == '\0' && (*l == ' ' || *l == '\0')) 141459243Sobrien return (1); 141559243Sobrien else 141659243Sobrien continue; 141759243Sobrien } 141859243Sobrien else { 141959243Sobrien while (*l && *l != ' ') 142059243Sobrien l++; /* skip to blank */ 142159243Sobrien while (*l && *l == ' ') 142259243Sobrien l++; /* and find first nonblank character */ 142359243Sobrien n = name; 142459243Sobrien } 142559243Sobrien } 142659243Sobrien return (0); 142759243Sobrien} 142859243Sobrien 142959243Sobrien#endif /* BSDJOBS */ 143059243Sobrien 143159243Sobrien 143259243Sobrien/* 143359243Sobrien * Implement a small cache for tilde names. This is used primarily 143459243Sobrien * to expand tilde names to directories, but also 143559243Sobrien * we can find users from their home directories for the tilde 143659243Sobrien * prompt, on machines where yp lookup is slow this can be a big win... 143759243Sobrien * As with any cache this can run out of sync, rehash can sync it again. 143859243Sobrien */ 143959243Sobrienstatic struct tildecache { 144059243Sobrien Char *user; 144159243Sobrien Char *home; 1442167465Smp size_t hlen; 144359243Sobrien} *tcache = NULL; 144459243Sobrien 144559243Sobrien#define TILINCR 10 1446167465Smpsize_t tlength = 0; 1447167465Smpstatic size_t tsize = TILINCR; 144859243Sobrien 144959243Sobrienstatic int 1450167465Smptildecompare(const void *xp1, const void *xp2) 145159243Sobrien{ 1452167465Smp const struct tildecache *p1, *p2; 1453167465Smp 1454167465Smp p1 = xp1; 1455167465Smp p2 = xp2; 145659243Sobrien return Strcmp(p1->user, p2->user); 145759243Sobrien} 145859243Sobrien 145959243Sobrienstatic Char * 1460167465Smpgethomedir(const Char *us) 146159243Sobrien{ 1462145479Smp struct passwd *pp; 146359243Sobrien#ifdef HESIOD 146459243Sobrien char **res, **res1, *cp; 146559243Sobrien Char *rp; 146659243Sobrien#endif /* HESIOD */ 146759243Sobrien 1468167465Smp pp = xgetpwnam(short2str(us)); 146959243Sobrien#ifdef YPBUGS 147059243Sobrien fix_yp_bugs(); 147159243Sobrien#endif /* YPBUGS */ 147283098Smp if (pp != NULL) { 1473100616Smp#if 0 147483098Smp /* Don't return if root */ 147583098Smp if (pp->pw_dir[0] == '/' && pp->pw_dir[1] == '\0') 147683098Smp return NULL; 147783098Smp else 1478100616Smp#endif 147983098Smp return Strsave(str2short(pp->pw_dir)); 148083098Smp } 148159243Sobrien#ifdef HESIOD 148259243Sobrien res = hes_resolve(short2str(us), "filsys"); 148383098Smp rp = NULL; 148483098Smp if (res != NULL) { 148583098Smp if ((*res) != NULL) { 148659243Sobrien /* 148759243Sobrien * Look at the first token to determine how to interpret 148859243Sobrien * the rest of it. 148959243Sobrien * Yes, strtok is evil (it's not thread-safe), but it's also 149059243Sobrien * easy to use. 149159243Sobrien */ 149259243Sobrien cp = strtok(*res, " "); 149359243Sobrien if (strcmp(cp, "AFS") == 0) { 149459243Sobrien /* next token is AFS pathname.. */ 149559243Sobrien cp = strtok(NULL, " "); 149659243Sobrien if (cp != NULL) 149759243Sobrien rp = Strsave(str2short(cp)); 149859243Sobrien } else if (strcmp(cp, "NFS") == 0) { 149959243Sobrien cp = NULL; 150059243Sobrien if ((strtok(NULL, " ")) && /* skip remote pathname */ 150159243Sobrien (strtok(NULL, " ")) && /* skip host */ 150259243Sobrien (strtok(NULL, " ")) && /* skip mode */ 150359243Sobrien (cp = strtok(NULL, " "))) { 150459243Sobrien rp = Strsave(str2short(cp)); 150559243Sobrien } 150659243Sobrien } 150759243Sobrien } 150859243Sobrien for (res1 = res; *res1; res1++) 150959243Sobrien free(*res1); 1510100616Smp#if 0 1511100616Smp /* Don't return if root */ 151283098Smp if (rp != NULL && rp[0] == '/' && rp[1] == '\0') { 1513167465Smp xfree(rp); 151483098Smp rp = NULL; 151583098Smp } 1516100616Smp#endif 151759243Sobrien return rp; 151859243Sobrien } 151959243Sobrien#endif /* HESIOD */ 152059243Sobrien return NULL; 152159243Sobrien} 152259243Sobrien 152359243SobrienChar * 1524167465Smpgettilde(const Char *us) 152559243Sobrien{ 152659243Sobrien struct tildecache *bp1, *bp2, *bp; 152759243Sobrien Char *hd; 152859243Sobrien 152959243Sobrien /* Ignore NIS special names */ 153059243Sobrien if (*us == '+' || *us == '-') 153159243Sobrien return NULL; 153259243Sobrien 153359243Sobrien if (tcache == NULL) 1534167465Smp tcache = xmalloc(TILINCR * sizeof(struct tildecache)); 153559243Sobrien /* 153659243Sobrien * Binary search 153759243Sobrien */ 153859243Sobrien for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) { 1539145479Smp int i; 154059243Sobrien 154159243Sobrien bp = bp1 + ((bp2 - bp1) >> 1); 154259243Sobrien if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0) 154359243Sobrien return (bp->home); 154459243Sobrien if (i < 0) 154559243Sobrien bp2 = bp; 154659243Sobrien else 154759243Sobrien bp1 = bp + 1; 154859243Sobrien } 154959243Sobrien /* 155059243Sobrien * Not in the cache, try to get it from the passwd file 155159243Sobrien */ 155259243Sobrien hd = gethomedir(us); 155359243Sobrien if (hd == NULL) 155459243Sobrien return NULL; 155559243Sobrien 155659243Sobrien /* 155759243Sobrien * Update the cache 155859243Sobrien */ 155959243Sobrien tcache[tlength].user = Strsave(us); 156059243Sobrien tcache[tlength].home = hd; 1561167465Smp tcache[tlength++].hlen = Strlen(hd); 156259243Sobrien 1563167465Smp qsort(tcache, tlength, sizeof(struct tildecache), tildecompare); 156459243Sobrien 156559243Sobrien if (tlength == tsize) { 156659243Sobrien tsize += TILINCR; 1567167465Smp tcache = xrealloc(tcache, tsize * sizeof(struct tildecache)); 156859243Sobrien } 156959243Sobrien return (hd); 157059243Sobrien} 157159243Sobrien 157259243Sobrien/* 157359243Sobrien * Return the username if the directory path passed contains a 157459243Sobrien * user's home directory in the tilde cache, otherwise return NULL 157559243Sobrien * hm points to the place where the path became different. 157659243Sobrien * Special case: Our own home directory. 157759243Sobrien * If we are passed a null pointer, then we flush the cache. 157859243Sobrien */ 157959243SobrienChar * 1580167465Smpgetusername(Char **hm) 158159243Sobrien{ 158259243Sobrien Char *h, *p; 1583167465Smp size_t i, j; 158459243Sobrien 158559243Sobrien if (hm == NULL) { 158659243Sobrien for (i = 0; i < tlength; i++) { 1587167465Smp xfree(tcache[i].home); 1588167465Smp xfree(tcache[i].user); 158959243Sobrien } 1590167465Smp xfree(tcache); 159159243Sobrien tlength = 0; 159259243Sobrien tsize = TILINCR; 159359243Sobrien tcache = NULL; 159459243Sobrien return NULL; 159559243Sobrien } 1596167465Smp p = *hm; 159759243Sobrien if (((h = varval(STRhome)) != STRNULL) && 1598167465Smp (Strncmp(p, h, j = Strlen(h)) == 0) && 159959243Sobrien (p[j] == '/' || p[j] == '\0')) { 160059243Sobrien *hm = &p[j]; 160159243Sobrien return STRNULL; 160259243Sobrien } 160359243Sobrien for (i = 0; i < tlength; i++) 1604167465Smp if ((Strncmp(p, tcache[i].home, (j = tcache[i].hlen)) == 0) && 1605167465Smp (p[j] == '/' || p[j] == '\0')) { 160659243Sobrien *hm = &p[j]; 160759243Sobrien return tcache[i].user; 160859243Sobrien } 160959243Sobrien return NULL; 161059243Sobrien} 161159243Sobrien 161259243Sobrien 161359243Sobrien/* 161459243Sobrien * set the shell-level var to 1 or apply change to it. 161559243Sobrien */ 161659243Sobrienvoid 1617167465Smpshlvl(int val) 161859243Sobrien{ 161959243Sobrien char *cp; 162059243Sobrien 162159243Sobrien if ((cp = getenv("SHLVL")) != NULL) { 162259243Sobrien 162359243Sobrien if (loginsh) 162459243Sobrien val = 1; 162559243Sobrien else 162659243Sobrien val += atoi(cp); 162759243Sobrien 162859243Sobrien if (val <= 0) { 162959243Sobrien if (adrof(STRshlvl) != NULL) 163059243Sobrien unsetv(STRshlvl); 163159243Sobrien Unsetenv(STRKSHLVL); 163259243Sobrien } 163359243Sobrien else { 1634167465Smp Char *p; 163559243Sobrien 1636167465Smp p = Itoa(val, 0, 0); 1637167465Smp cleanup_push(p, xfree); 1638167465Smp setv(STRshlvl, p, VAR_READWRITE); 1639167465Smp cleanup_ignore(p); 1640167465Smp cleanup_until(p); 1641167465Smp tsetenv(STRKSHLVL, p); 164259243Sobrien } 164359243Sobrien } 164459243Sobrien else { 1645167465Smp setcopy(STRshlvl, STR1, VAR_READWRITE); 1646167465Smp tsetenv(STRKSHLVL, STR1); 164759243Sobrien } 164859243Sobrien} 164959243Sobrien 165059243Sobrien 165159243Sobrien/* fixio(): 165259243Sobrien * Try to recover from a read error 165359243Sobrien */ 165459243Sobrienint 1655167465Smpfixio(int fd, int e) 165659243Sobrien{ 165759243Sobrien switch (e) { 165859243Sobrien case -1: /* Make sure that the code is reachable */ 165959243Sobrien 166059243Sobrien#ifdef EWOULDBLOCK 166159243Sobrien case EWOULDBLOCK: 166259243Sobrien# define FDRETRY 166359243Sobrien#endif /* EWOULDBLOCK */ 166459243Sobrien 166559243Sobrien#if defined(POSIX) && defined(EAGAIN) 166659243Sobrien# if !defined(EWOULDBLOCK) || EWOULDBLOCK != EAGAIN 166759243Sobrien case EAGAIN: 166859243Sobrien# define FDRETRY 166959243Sobrien# endif /* !EWOULDBLOCK || EWOULDBLOCK != EAGAIN */ 167059243Sobrien#endif /* POSIX && EAGAIN */ 167159243Sobrien 1672231990Smp e = -1; 167359243Sobrien#ifdef FDRETRY 167459243Sobrien# ifdef F_SETFL 167559243Sobrien/* 167659243Sobrien * Great! we have on suns 3 flavors and 5 names... 167759243Sobrien * I hope that will cover everything. 167859243Sobrien * I added some more defines... many systems have different defines. 167959243Sobrien * Rather than dealing with getting the right includes, we'll just 168059243Sobrien * cover all the known possibilities here. -- sterling@netcom.com 168159243Sobrien */ 168259243Sobrien# ifndef O_NONBLOCK 168359243Sobrien# define O_NONBLOCK 0 168459243Sobrien# endif /* O_NONBLOCK */ 168559243Sobrien# ifndef O_NDELAY 168659243Sobrien# define O_NDELAY 0 168759243Sobrien# endif /* O_NDELAY */ 168859243Sobrien# ifndef FNBIO 168959243Sobrien# define FNBIO 0 169059243Sobrien# endif /* FNBIO */ 169159243Sobrien# ifndef _FNBIO 169259243Sobrien# define _FNBIO 0 169359243Sobrien# endif /* _FNBIO */ 169459243Sobrien# ifndef FNONBIO 169559243Sobrien# define FNONBIO 0 169659243Sobrien# endif /* FNONBIO */ 169759243Sobrien# ifndef FNONBLOCK 169859243Sobrien# define FNONBLOCK 0 169959243Sobrien# endif /* FNONBLOCK */ 170059243Sobrien# ifndef _FNONBLOCK 170159243Sobrien# define _FNONBLOCK 0 170259243Sobrien# endif /* _FNONBLOCK */ 170359243Sobrien# ifndef FNDELAY 170459243Sobrien# define FNDELAY 0 170559243Sobrien# endif /* FNDELAY */ 170659243Sobrien# ifndef _FNDELAY 170759243Sobrien# define _FNDELAY 0 170859243Sobrien# endif /* _FNDELAY */ 170959243Sobrien# ifndef FNDLEAY /* Some linux versions have this typo */ 171059243Sobrien# define FNDLEAY 0 171159243Sobrien# endif /* FNDLEAY */ 171259243Sobrien if ((e = fcntl(fd, F_GETFL, 0)) == -1) 171359243Sobrien return -1; 171459243Sobrien 171559243Sobrien e &= ~(O_NDELAY|O_NONBLOCK|FNBIO|_FNBIO|FNONBIO|FNONBLOCK|_FNONBLOCK| 171659243Sobrien FNDELAY|_FNDELAY|FNDLEAY); /* whew! */ 171759243Sobrien if (fcntl(fd, F_SETFL, e) == -1) 171859243Sobrien return -1; 171959243Sobrien else 1720231990Smp e = 0; 172159243Sobrien# endif /* F_SETFL */ 172259243Sobrien 172359243Sobrien# ifdef FIONBIO 172459243Sobrien e = 0; 172559243Sobrien if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1) 172659243Sobrien return -1; 172759243Sobrien# endif /* FIONBIO */ 172859243Sobrien 172959243Sobrien#endif /* FDRETRY */ 1730231990Smp return e; 173159243Sobrien 173259243Sobrien case EINTR: 173359243Sobrien return 0; 173459243Sobrien 173559243Sobrien default: 173659243Sobrien return -1; 173759243Sobrien } 173859243Sobrien} 173959243Sobrien 174059243Sobrien/* collate(): 174159243Sobrien * String collation 174259243Sobrien */ 174359243Sobrienint 1744167465Smpcollate(const Char *a, const Char *b) 174559243Sobrien{ 174659243Sobrien int rv; 174759243Sobrien#ifdef SHORT_STRINGS 174859243Sobrien /* This strips the quote bit as a side effect */ 174959243Sobrien char *sa = strsave(short2str(a)); 175059243Sobrien char *sb = strsave(short2str(b)); 175159243Sobrien#else 175259243Sobrien char *sa = strip(strsave(a)); 175359243Sobrien char *sb = strip(strsave(b)); 175459243Sobrien#endif /* SHORT_STRINGS */ 175559243Sobrien 1756167465Smp#if defined(NLS) && defined(HAVE_STRCOLL) 175759243Sobrien errno = 0; /* strcoll sets errno, another brain-damage */ 175859243Sobrien 175959243Sobrien rv = strcoll(sa, sb); 176059243Sobrien 176159243Sobrien /* 176259243Sobrien * We should be checking for errno != 0, but some systems 176359243Sobrien * forget to reset errno to 0. So we only check for the 176459243Sobrien * only documented valid errno value for strcoll [EINVAL] 176559243Sobrien */ 176659243Sobrien if (errno == EINVAL) { 1767167465Smp xfree(sa); 1768167465Smp xfree(sb); 176959243Sobrien stderror(ERR_SYSTEM, "strcoll", strerror(errno)); 177059243Sobrien } 177159243Sobrien#else 177259243Sobrien rv = strcmp(sa, sb); 1773167465Smp#endif /* NLS && HAVE_STRCOLL */ 177459243Sobrien 1775167465Smp xfree(sa); 1776167465Smp xfree(sb); 177759243Sobrien 177859243Sobrien return rv; 177959243Sobrien} 178059243Sobrien 178159243Sobrien#ifdef HASHBANG 178259243Sobrien/* 178359243Sobrien * From: peter@zeus.dialix.oz.au (Peter Wemm) 178459243Sobrien * If exec() fails look first for a #! [word] [word] .... 178559243Sobrien * If it is, splice the header into the argument list and retry. 178659243Sobrien */ 178759243Sobrien#define HACKBUFSZ 1024 /* Max chars in #! vector */ 178859243Sobrienint 1789167465Smphashbang(int fd, Char ***vp) 179059243Sobrien{ 1791167465Smp struct blk_buf sarg = BLK_BUF_INIT; 1792167465Smp char lbuf[HACKBUFSZ], *p, *ws; 179369408Sache#ifdef WINNT_NATIVE 179459243Sobrien int fw = 0; /* found at least one word */ 1795167465Smp int first_word = 1; 1796167465Smp char *real; 179769408Sache#endif /* WINNT_NATIVE */ 179859243Sobrien 1799167465Smp if (xread(fd, lbuf, HACKBUFSZ) <= 0) 180059243Sobrien return -1; 180159243Sobrien 180259243Sobrien ws = 0; /* word started = 0 */ 180359243Sobrien 1804167465Smp for (p = lbuf; p < &lbuf[HACKBUFSZ]; ) { 180559243Sobrien switch (*p) { 180659243Sobrien case ' ': 180759243Sobrien case '\t': 1808195609Smp#if defined(WINNT_NATIVE) || defined (__CYGWIN__) 180959243Sobrien case '\r': 1810195609Smp#endif /* WINNT_NATIVE || __CYGWIN__ */ 181159243Sobrien if (ws) { /* a blank after a word.. save it */ 181259243Sobrien *p = '\0'; 1813167465Smp#ifdef WINNT_NATIVE 1814167465Smp if (first_word) { 1815167465Smp real = hb_subst(ws); 1816167465Smp if (real != NULL) 1817167465Smp ws = real; 181859243Sobrien } 181959243Sobrien fw = 1; 1820167465Smp first_word = 0; 182169408Sache#endif /* WINNT_NATIVE */ 1822167465Smp bb_append(&sarg, SAVE(ws)); 1823167465Smp ws = NULL; 182459243Sobrien } 182559243Sobrien p++; 182659243Sobrien continue; 182759243Sobrien 182859243Sobrien case '\0': /* Whoa!! what the hell happened */ 1829167465Smp goto err; 183059243Sobrien 183159243Sobrien case '\n': /* The end of the line. */ 183259243Sobrien if ( 183369408Sache#ifdef WINNT_NATIVE 183459243Sobrien fw || 183569408Sache#endif /* WINNT_NATIVE */ 183659243Sobrien ws) { /* terminate the last word */ 183759243Sobrien *p = '\0'; 1838167465Smp#ifdef WINNT_NATIVE 1839167465Smp /* deal with the 1-word case */ 1840167465Smp if (first_word) { 1841167465Smp real = hb_subst(ws); 1842167465Smp if (real != NULL) 1843167465Smp ws = real; 184459243Sobrien } 184569408Sache#endif /* !WINNT_NATIVE */ 1846167465Smp if (ws) 1847167465Smp bb_append(&sarg, SAVE(ws)); 184859243Sobrien } 1849167465Smp if (sarg.len > 0) { 1850167465Smp *vp = bb_finish(&sarg); 185159243Sobrien return 0; 185259243Sobrien } 185359243Sobrien else 1854167465Smp goto err; 185559243Sobrien 185659243Sobrien default: 185759243Sobrien if (!ws) /* Start a new word? */ 185859243Sobrien ws = p; 185959243Sobrien p++; 186059243Sobrien break; 186159243Sobrien } 1862167465Smp } 1863167465Smp err: 1864167465Smp bb_cleanup(&sarg); 186559243Sobrien return -1; 186659243Sobrien} 186759243Sobrien#endif /* HASHBANG */ 186859243Sobrien 186959243Sobrien#ifdef REMOTEHOST 187059243Sobrien 1871167465Smpstatic void 1872167465Smppalarm(int snum) 187359243Sobrien{ 187459243Sobrien USE(snum); 1875167465Smp _exit(1); 187659243Sobrien} 187759243Sobrien 187859243Sobrienstatic void 1879167465Smpgetremotehost(int dest_fd) 188059243Sobrien{ 188159243Sobrien const char *host = NULL; 188269408Sache#ifdef INET6 188369408Sache struct sockaddr_storage saddr; 188469408Sache static char hbuf[NI_MAXHOST]; 188569408Sache#else 188659243Sobrien struct hostent* hp; 188759243Sobrien struct sockaddr_in saddr; 188869408Sache#endif 1889167465Smp socklen_t len = sizeof(saddr); 189059243Sobrien 189169408Sache#ifdef INET6 1892100616Smp if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 1893100616Smp (saddr.ss_family == AF_INET6 || saddr.ss_family == AF_INET)) { 189469408Sache int flag = NI_NUMERICHOST; 189569408Sache 189669408Sache#ifdef NI_WITHSCOPEID 189769408Sache flag |= NI_WITHSCOPEID; 189869408Sache#endif 189969408Sache getnameinfo((struct sockaddr *)&saddr, len, hbuf, sizeof(hbuf), 190069408Sache NULL, 0, flag); 190169408Sache host = hbuf; 190269408Sache#else 1903100616Smp if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 1904100616Smp saddr.sin_family == AF_INET) { 190569408Sache#if 0 190659243Sobrien if ((hp = gethostbyaddr((char *)&saddr.sin_addr, sizeof(struct in_addr), 190759243Sobrien AF_INET)) != NULL) 190859243Sobrien host = hp->h_name; 190959243Sobrien else 191059243Sobrien#endif 191159243Sobrien host = inet_ntoa(saddr.sin_addr); 191269408Sache#endif 191359243Sobrien } 1914145479Smp#ifdef HAVE_STRUCT_UTMP_UT_HOST 191559243Sobrien else { 191659243Sobrien char *ptr; 191759243Sobrien char *name = utmphost(); 191859243Sobrien /* Avoid empty names and local X displays */ 191959243Sobrien if (name != NULL && *name != '\0' && *name != ':') { 192069408Sache struct in_addr addr; 1921167465Smp char *sptr; 192269408Sache 192359243Sobrien /* Look for host:display.screen */ 192469408Sache /* 192569408Sache * There is conflict with IPv6 address and X DISPLAY. So, 192669408Sache * we assume there is no IPv6 address in utmp and don't 192769408Sache * touch here. 192869408Sache */ 192959243Sobrien if ((sptr = strchr(name, ':')) != NULL) 193059243Sobrien *sptr = '\0'; 193169408Sache /* Leave IPv4 address as is */ 193269408Sache /* 193369408Sache * we use inet_addr here, not inet_aton because many systems 193469408Sache * have not caught up yet. 193569408Sache */ 193669408Sache addr.s_addr = inet_addr(name); 1937131962Smp if (addr.s_addr != (unsigned int)~0) 193859243Sobrien host = name; 193959243Sobrien else { 194059243Sobrien if (sptr != name) { 194169408Sache#ifdef INET6 194269408Sache char *s, *domain; 1943167465Smp char dbuf[MAXHOSTNAMELEN]; 194469408Sache struct addrinfo hints, *res = NULL; 194569408Sache 194669408Sache memset(&hints, 0, sizeof(hints)); 194769408Sache hints.ai_family = PF_UNSPEC; 194869408Sache hints.ai_socktype = SOCK_STREAM; 194969408Sache hints.ai_flags = AI_PASSIVE | AI_CANONNAME; 195069408Sache if (strlen(name) < utmphostsize()) 195169408Sache { 195269408Sache if (getaddrinfo(name, NULL, &hints, &res) != 0) 195369408Sache res = NULL; 1954167465Smp } else if (gethostname(dbuf, sizeof(dbuf)) == 0 && 1955167465Smp (dbuf[sizeof(dbuf)-1] = '\0', /*FIXME: ugly*/ 1956167465Smp (domain = strchr(dbuf, '.')) != NULL)) { 195769408Sache for (s = strchr(name, '.'); 195869408Sache s != NULL; s = strchr(s + 1, '.')) { 195969408Sache if (*(s + 1) != '\0' && 196069408Sache (ptr = strstr(domain, s)) != NULL) { 1961167465Smp char *cbuf; 1962167465Smp 1963231990Smp cbuf = strspl(name, ptr + strlen(s)); 196469408Sache if (getaddrinfo(cbuf, NULL, &hints, &res) != 0) 196569408Sache res = NULL; 1966167465Smp xfree(cbuf); 196769408Sache break; 196869408Sache } 196969408Sache } 197069408Sache } 197169408Sache if (res != NULL) { 197269408Sache if (res->ai_canonname != NULL) { 197369408Sache strncpy(hbuf, res->ai_canonname, sizeof(hbuf)); 1974231990Smp hbuf[sizeof(hbuf) - 1] = '\0'; 197569408Sache host = hbuf; 197669408Sache } 197769408Sache freeaddrinfo(res); 197869408Sache } 197969408Sache#else 198059243Sobrien if ((hp = gethostbyname(name)) == NULL) { 198159243Sobrien /* Try again eliminating the trailing domain */ 198259243Sobrien if ((ptr = strchr(name, '.')) != NULL) { 198359243Sobrien *ptr = '\0'; 198459243Sobrien if ((hp = gethostbyname(name)) != NULL) 198559243Sobrien host = hp->h_name; 198659243Sobrien *ptr = '.'; 198759243Sobrien } 198859243Sobrien } 198959243Sobrien else 199059243Sobrien host = hp->h_name; 199169408Sache#endif 199259243Sobrien } 199359243Sobrien } 199459243Sobrien } 199559243Sobrien } 199659243Sobrien#endif 199759243Sobrien 1998167465Smp if (host) { 1999167465Smp size_t left; 200059243Sobrien 2001167465Smp left = strlen(host); 2002167465Smp while (left != 0) { 2003167465Smp ssize_t res; 2004167465Smp 2005167465Smp res = xwrite(dest_fd, host, left); 2006167465Smp if (res < 0) 2007167465Smp _exit(1); 2008167465Smp host += res; 2009167465Smp left -= res; 2010167465Smp } 2011167465Smp } 2012167465Smp _exit(0); 201359243Sobrien} 201459243Sobrien 201559243Sobrien/* 201659243Sobrien * From: <lesv@ppvku.ericsson.se> (Lennart Svensson) 201759243Sobrien */ 2018167465Smpvoid 2019167465Smpremotehost(void) 202059243Sobrien{ 2021167465Smp struct sigaction sa; 2022167465Smp struct strbuf hostname = strbuf_INIT; 2023167465Smp int fds[2], wait_options, status; 2024167465Smp pid_t pid, wait_res; 202559243Sobrien 2026167465Smp sa.sa_handler = SIG_DFL; /* Make sure a zombie is created */ 2027167465Smp sigemptyset(&sa.sa_mask); 2028167465Smp sa.sa_flags = 0; 2029167465Smp sigaction(SIGCHLD, &sa, NULL); 2030167465Smp mypipe(fds); 2031167465Smp pid = fork(); 2032167465Smp if (pid == 0) { 2033167465Smp sigset_t set; 2034167465Smp xclose(fds[0]); 2035167465Smp /* Don't get stuck if the resolver does not work! */ 2036167465Smp signal(SIGALRM, palarm); 2037167465Smp sigemptyset(&set); 2038167465Smp sigaddset(&set, SIGALRM); 2039167465Smp (void)sigprocmask(SIG_UNBLOCK, &set, NULL); 2040167465Smp (void)alarm(2); 2041167465Smp getremotehost(fds[1]); 2042167465Smp /*NOTREACHED*/ 2043167465Smp } 2044167465Smp xclose(fds[1]); 2045167465Smp for (;;) { 2046167465Smp char buf[BUFSIZE]; 2047167465Smp ssize_t res; 204859243Sobrien 2049167465Smp res = xread(fds[0], buf, sizeof(buf)); 2050167465Smp if (res == -1) { 2051167465Smp hostname.len = 0; 2052167465Smp wait_options = WNOHANG; 2053167465Smp goto done; 2054167465Smp } 2055167465Smp if (res == 0) 2056167465Smp break; 2057167465Smp strbuf_appendn(&hostname, buf, res); 2058167465Smp } 2059167465Smp wait_options = 0; 2060167465Smp done: 2061231990Smp cleanup_push(&hostname, strbuf_cleanup); 2062167465Smp xclose(fds[0]); 2063167465Smp while ((wait_res = waitpid(pid, &status, wait_options)) == -1 2064167465Smp && errno == EINTR) 2065167465Smp handle_pending_signals(); 2066231990Smp if (hostname.len > 0 && wait_res == pid && WIFEXITED(status) 2067231990Smp && WEXITSTATUS(status) == 0) { 2068167465Smp strbuf_terminate(&hostname); 2069167465Smp tsetenv(STRREMOTEHOST, str2short(hostname.s)); 2070167465Smp } 2071167465Smp cleanup_until(&hostname); 207259243Sobrien 207359243Sobrien#ifdef YPBUGS 207459243Sobrien /* From: casper@fwi.uva.nl (Casper H.S. Dik), for Solaris 2.3 */ 207559243Sobrien fix_yp_bugs(); 207659243Sobrien#endif /* YPBUGS */ 207759243Sobrien 207859243Sobrien} 207959243Sobrien#endif /* REMOTEHOST */ 2080145479Smp 2081145479Smp#ifndef WINNT_NATIVE 2082145479Smp/* 2083145479Smp * indicate if a terminal type is defined in terminfo/termcap 2084145479Smp * (by default the current term type). This allows ppl to look 2085145479Smp * for a working term type automatically in their login scripts 2086145479Smp * when using a terminal known as different things on different 2087145479Smp * platforms 2088145479Smp */ 2089145479Smpvoid 2090167465Smpdotermname(Char **v, struct command *c) 2091145479Smp{ 2092145479Smp char *termtype; 2093145479Smp /* 2094145479Smp * Maximum size of a termcap record. We make it twice as large. 2095145479Smp */ 2096145479Smp char termcap_buffer[2048]; 2097145479Smp 2098145479Smp USE(c); 2099145479Smp /* try to find which entry we should be looking for */ 2100145479Smp termtype = (v[1] == NULL ? getenv("TERM") : short2str(v[1])); 2101145479Smp if (termtype == NULL) { 2102145479Smp /* no luck - the user didn't provide one and none is 2103145479Smp * specified in the environment 2104145479Smp */ 2105167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 2106145479Smp return; 2107145479Smp } 2108145479Smp 2109145479Smp /* 2110145479Smp * we use the termcap function - if we are using terminfo we 2111145479Smp * will end up with it's compatibility function 2112145479Smp * terminfo/termcap will be initialized with the new 2113145479Smp * type but we don't care because tcsh has cached all the things 2114145479Smp * it needs. 2115145479Smp */ 2116145479Smp if (tgetent(termcap_buffer, termtype) == 1) { 2117145479Smp xprintf("%s\n", termtype); 2118167465Smp setcopy(STRstatus, STR0, VAR_READWRITE); 2119167465Smp } else 2120167465Smp setcopy(STRstatus, STR1, VAR_READWRITE); 2121145479Smp} 2122145479Smp#endif /* WINNT_NATIVE */ 2123