1 /* $Header: /p/tcsh/cvsroot/tcsh/tc.func.c,v 3.153 2014/10/11 21:52:26 christos Exp $ */ 2 /* 3 * tc.func.c: New tcsh builtins. 4 */ 5 /*- 6 * Copyright (c) 1980, 1991 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 #include "sh.h" 34 35 RCSID("$tcsh: tc.func.c,v 3.153 2014/10/11 21:52:26 christos Exp $") 36 37 #include "ed.h" 38 #include "ed.defns.h" /* for the function names */ 39 #include "tw.h" 40 #include "tc.h" 41 #ifdef WINNT_NATIVE 42 #include "nt.const.h" 43 #else /* WINNT_NATIVE */ 44 #include <sys/wait.h> 45 #endif /* WINNT_NATIVE */ 46 47 #ifdef AFS 48 #include <afs/stds.h> 49 #include <afs/kautils.h> 50 long ka_UserAuthenticateGeneral(); 51 #endif /* AFS */ 52 53 #ifdef TESLA 54 extern int do_logout; 55 #endif /* TESLA */ 56 extern time_t t_period; 57 extern int just_signaled; 58 static int precmd_active = 0; 59 static int jobcmd_active = 0; /* GrP */ 60 static int postcmd_active = 0; 61 static int periodic_active = 0; 62 static int cwdcmd_active = 0; /* PWP: for cwd_cmd */ 63 static int beepcmd_active = 0; 64 static void (*alm_fun)(void) = NULL; 65 66 static void auto_logout (void); 67 static char *xgetpass (const char *); 68 static void auto_lock (void); 69 #ifdef BSDJOBS 70 static void insert (struct wordent *, int); 71 static void insert_we (struct wordent *, struct wordent *); 72 static int inlist (Char *, Char *); 73 #endif /* BSDJOBS */ 74 static int tildecompare (const void *, const void *); 75 static Char *gethomedir (const Char *); 76 #ifdef REMOTEHOST 77 static void palarm (int); 78 static void getremotehost (int); 79 #endif /* REMOTEHOST */ 80 81 /* 82 * Tops-C shell 83 */ 84 85 /* 86 * expand_lex: Take the given lex and return an expanded version of it. 87 * First guy in lex list is ignored; last guy is ^J which we ignore. 88 * Only take lex'es from position 'from' to position 'to' inclusive 89 * 90 * Note: csh sometimes sets bit 8 in characters which causes all kinds 91 * of problems if we don't mask it here. Note: excl's in lexes have been 92 * un-back-slashed and must be re-back-slashed 93 * 94 */ 95 /* PWP: this is a combination of the old sprlex() and the expand_lex from 96 the magic-space stuff */ 97 98 Char * 99 expand_lex(const struct wordent *sp0, int from, int to) 100 { 101 struct Strbuf buf = Strbuf_INIT; 102 const struct wordent *sp; 103 Char *s; 104 Char prev_c; 105 int i; 106 107 prev_c = '\0'; 108 109 if (!sp0 || (sp = sp0->next) == sp0 || sp == (sp0 = sp0->prev)) 110 return Strbuf_finish(&buf); /* null lex */ 111 112 for (i = 0; ; i++) { 113 if ((i >= from) && (i <= to)) { /* if in range */ 114 for (s = sp->word; *s; s++) { 115 /* 116 * bugfix by Michael Bloom: anything but the current history 117 * character {(PWP) and backslash} seem to be dealt with 118 * elsewhere. 119 */ 120 if ((*s & QUOTE) 121 && (((*s & TRIM) == HIST && HIST != '\0') || 122 (((*s & TRIM) == '\'') && (prev_c != '\\')) || 123 (((*s & TRIM) == '\"') && (prev_c != '\\')) || 124 (((*s & TRIM) == '\\') && (prev_c != '\\')))) { 125 Strbuf_append1(&buf, '\\'); 126 } 127 Strbuf_append1(&buf, *s & TRIM); 128 prev_c = *s; 129 } 130 Strbuf_append1(&buf, ' '); 131 } 132 sp = sp->next; 133 if (sp == sp0) 134 break; 135 } 136 if (buf.len != 0) 137 buf.len--; /* get rid of trailing space */ 138 139 return Strbuf_finish(&buf); 140 } 141 142 Char * 143 sprlex(const struct wordent *sp0) 144 { 145 return expand_lex(sp0, 0, INT_MAX); 146 } 147 148 149 Char * 150 Itoa(int n, size_t min_digits, Char attributes) 151 { 152 /* 153 * The array size here is derived from 154 * log8(UINT_MAX) 155 * which is guaranteed to be enough for a decimal 156 * representation. We add 1 because integer divide 157 * rounds down. 158 */ 159 #ifndef CHAR_BIT 160 # define CHAR_BIT 8 161 #endif 162 Char buf[CHAR_BIT * sizeof(int) / 3 + 1], *res, *p, *s; 163 unsigned int un; /* handle most negative # too */ 164 int pad = (min_digits != 0); 165 166 if (sizeof(buf) - 1 < min_digits) 167 min_digits = sizeof(buf) - 1; 168 169 un = n; 170 if (n < 0) 171 un = -n; 172 173 p = buf; 174 do { 175 *p++ = un % 10 + '0'; 176 un /= 10; 177 } while ((pad && (ssize_t)--min_digits > 0) || un != 0); 178 179 res = xmalloc((p - buf + 2) * sizeof(*res)); 180 s = res; 181 if (n < 0) 182 *s++ = '-'; 183 while (p > buf) 184 *s++ = *--p | attributes; 185 186 *s = '\0'; 187 return res; 188 } 189 190 191 /*ARGSUSED*/ 192 void 193 dolist(Char **v, struct command *c) 194 { 195 Char **globbed; 196 int i, k, ret = 0; 197 struct stat st; 198 199 USE(c); 200 if (*++v == NULL) { 201 struct Strbuf word = Strbuf_INIT; 202 203 Strbuf_terminate(&word); 204 cleanup_push(&word, Strbuf_cleanup); 205 (void) t_search(&word, LIST, TW_ZERO, 0, STRNULL, 0); 206 cleanup_until(&word); 207 return; 208 } 209 v = glob_all_or_error(v); 210 globbed = v; 211 cleanup_push(globbed, blk_cleanup); 212 for (k = 0; v[k] != NULL && v[k][0] != '-'; k++) 213 continue; 214 if (v[k]) { 215 /* 216 * We cannot process a flag therefore we let ls do it right. 217 */ 218 Char *lspath; 219 struct command *t; 220 struct wordent cmd, *nextword, *lastword; 221 Char *cp; 222 struct varent *vp; 223 224 if (setintr) { 225 pintr_disabled++; 226 cleanup_push(&pintr_disabled, disabled_cleanup); 227 } 228 if (seterr) { 229 xfree(seterr); 230 seterr = NULL; 231 } 232 233 lspath = STRls; 234 STRmCF[1] = 'C'; 235 STRmCF[3] = '\0'; 236 /* Look at listflags, to add -A to the flags, to get a path 237 of ls if necessary */ 238 if ((vp = adrof(STRlistflags)) != NULL && vp->vec != NULL && 239 vp->vec[0] != STRNULL) { 240 if (vp->vec[1] != NULL && vp->vec[1][0] != '\0') 241 lspath = vp->vec[1]; 242 for (cp = vp->vec[0]; *cp; cp++) 243 switch (*cp) { 244 case 'x': 245 STRmCF[1] = 'x'; 246 break; 247 case 'a': 248 STRmCF[3] = 'a'; 249 break; 250 case 'A': 251 STRmCF[3] = 'A'; 252 break; 253 default: 254 break; 255 } 256 } 257 258 cmd.word = STRNULL; 259 lastword = &cmd; 260 nextword = xcalloc(1, sizeof cmd); 261 nextword->word = Strsave(lspath); 262 lastword->next = nextword; 263 nextword->prev = lastword; 264 lastword = nextword; 265 nextword = xcalloc(1, sizeof cmd); 266 nextword->word = Strsave(STRmCF); 267 lastword->next = nextword; 268 nextword->prev = lastword; 269 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 270 if (dspmbyte_ls) { 271 lastword = nextword; 272 nextword = xcalloc(1, sizeof cmd); 273 nextword->word = Strsave(STRmmliteral); 274 lastword->next = nextword; 275 nextword->prev = lastword; 276 } 277 #endif 278 #ifdef COLOR_LS_F 279 if (color_context_ls) { 280 lastword = nextword; 281 nextword = xcalloc(1, sizeof cmd); 282 nextword->word = Strsave(STRmmcolormauto); 283 lastword->next = nextword; 284 nextword->prev = lastword; 285 } 286 #endif /* COLOR_LS_F */ 287 lastword = nextword; 288 for (cp = *v; cp; cp = *++v) { 289 nextword = xcalloc(1, sizeof cmd); 290 nextword->word = quote(Strsave(cp)); 291 lastword->next = nextword; 292 nextword->prev = lastword; 293 lastword = nextword; 294 } 295 lastword->next = &cmd; 296 cmd.prev = lastword; 297 cleanup_push(&cmd, lex_cleanup); 298 299 /* build a syntax tree for the command. */ 300 t = syntax(cmd.next, &cmd, 0); 301 cleanup_push(t, syntax_cleanup); 302 if (seterr) 303 stderror(ERR_OLD); 304 /* expand aliases like process() does */ 305 /* alias(&cmd); */ 306 /* execute the parse tree. */ 307 execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL, FALSE); 308 /* done. free the lex list and parse tree. */ 309 cleanup_until(&cmd); 310 if (setintr) 311 cleanup_until(&pintr_disabled); 312 } 313 else { 314 Char *dp, *tmp; 315 struct Strbuf buf = Strbuf_INIT; 316 317 cleanup_push(&buf, Strbuf_cleanup); 318 for (k = 0, i = 0; v[k] != NULL; k++) { 319 tmp = dnormalize(v[k], symlinks == SYM_IGNORE); 320 cleanup_push(tmp, xfree); 321 dp = Strend(tmp) - 1; 322 if (*dp == '/' && dp != tmp) 323 #ifdef apollo 324 if (dp != &tmp[1]) 325 #endif /* apollo */ 326 *dp = '\0'; 327 if (stat(short2str(tmp), &st) == -1) { 328 int err; 329 330 err = errno; 331 if (k != i) { 332 if (i != 0) 333 xputchar('\n'); 334 print_by_column(STRNULL, &v[i], k - i, FALSE); 335 } 336 haderr = 1; 337 xprintf("%S: %s.\n", tmp, strerror(err)); 338 haderr = 0; 339 i = k + 1; 340 ret = 1; 341 } 342 else if (S_ISDIR(st.st_mode)) { 343 Char *cp; 344 345 if (k != i) { 346 if (i != 0) 347 xputchar('\n'); 348 print_by_column(STRNULL, &v[i], k - i, FALSE); 349 } 350 if (k != 0 && v[1] != NULL) 351 xputchar('\n'); 352 xprintf("%S:\n", tmp); 353 buf.len = 0; 354 for (cp = tmp; *cp; cp++) 355 Strbuf_append1(&buf, (*cp | QUOTE)); 356 Strbuf_terminate(&buf); 357 dp = &buf.s[buf.len - 1]; 358 if ( 359 #ifdef WINNT_NATIVE 360 (*dp != (Char) (':' | QUOTE)) && 361 #endif /* WINNT_NATIVE */ 362 (*dp != (Char) ('/' | QUOTE))) { 363 Strbuf_append1(&buf, '/'); 364 Strbuf_terminate(&buf); 365 } else 366 *dp &= TRIM; 367 (void) t_search(&buf, LIST, TW_ZERO, 0, STRNULL, 0); 368 i = k + 1; 369 } 370 cleanup_until(tmp); 371 } 372 cleanup_until(&buf); 373 if (k != i) { 374 if (i != 0) 375 xputchar('\n'); 376 print_by_column(STRNULL, &v[i], k - i, FALSE); 377 } 378 if (ret) 379 stderror(ERR_SILENT); 380 } 381 382 cleanup_until(globbed); 383 } 384 385 extern int GotTermCaps; 386 387 /*ARGSUSED*/ 388 void 389 dotelltc(Char **v, struct command *c) 390 { 391 USE(v); 392 USE(c); 393 if (!GotTermCaps) 394 GetTermCaps(); 395 TellTC(); 396 } 397 398 /*ARGSUSED*/ 399 void 400 doechotc(Char **v, struct command *c) 401 { 402 USE(c); 403 if (!GotTermCaps) 404 GetTermCaps(); 405 EchoTC(++v); 406 } 407 408 /*ARGSUSED*/ 409 void 410 dosettc(Char **v, struct command *c) 411 { 412 char *tv[2]; 413 414 USE(c); 415 if (!GotTermCaps) 416 GetTermCaps(); 417 418 tv[0] = strsave(short2str(v[1])); 419 cleanup_push(tv[0], xfree); 420 tv[1] = strsave(short2str(v[2])); 421 cleanup_push(tv[1], xfree); 422 SetTC(tv[0], tv[1]); 423 cleanup_until(tv[0]); 424 } 425 426 /* The dowhich() is by: 427 * Andreas Luik <luik@isaak.isa.de> 428 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 429 * Azenberstr. 35 430 * D-7000 Stuttgart 1 431 * West-Germany 432 * Thanks!! 433 */ 434 int 435 cmd_expand(Char *cmd, Char **str) 436 { 437 struct wordent lexp[3]; 438 struct varent *vp; 439 int rv = TRUE; 440 441 lexp[0].next = &lexp[1]; 442 lexp[1].next = &lexp[2]; 443 lexp[2].next = &lexp[0]; 444 445 lexp[0].prev = &lexp[2]; 446 lexp[1].prev = &lexp[0]; 447 lexp[2].prev = &lexp[1]; 448 449 lexp[0].word = STRNULL; 450 lexp[2].word = STRret; 451 452 if ((vp = adrof1(cmd, &aliases)) != NULL && vp->vec != NULL) { 453 if (str == NULL) { 454 xprintf(CGETS(22, 1, "%S: \t aliased to "), cmd); 455 blkpr(vp->vec); 456 xputchar('\n'); 457 } 458 else 459 *str = blkexpand(vp->vec); 460 } 461 else { 462 lexp[1].word = cmd; 463 rv = tellmewhat(lexp, str); 464 } 465 return rv; 466 } 467 468 469 /*ARGSUSED*/ 470 void 471 dowhich(Char **v, struct command *c) 472 { 473 int rv = TRUE; 474 USE(c); 475 476 /* 477 * We don't want to glob dowhich args because we lose quoteing 478 * E.g. which \ls if ls is aliased will not work correctly if 479 * we glob here. 480 */ 481 482 while (*++v) 483 rv &= cmd_expand(*v, NULL); 484 485 if (!rv) 486 setcopy(STRstatus, STR1, VAR_READWRITE); 487 } 488 489 static int 490 findvv(Char **vv, const char *cp) 491 { 492 for (; vv && *vv; vv++) { 493 size_t i; 494 for (i = 0; (*vv)[i] && (*vv)[i] == cp[i]; i++) 495 continue; 496 if ((*vv)[i] == '\0' && cp[i] == '\0') 497 return 1; 498 } 499 return 0; 500 } 501 502 /* PWP: a hack to start up your stopped editor on a single keystroke */ 503 /* jbs - fixed hack so it worked :-) 3/28/89 */ 504 505 struct process * 506 find_stop_ed(void) 507 { 508 struct process *pp, *retp; 509 const char *ep, *vp; 510 char *cp, *p; 511 size_t epl, vpl; 512 int pstatus; 513 struct varent *varp; 514 Char **vv; 515 516 if ((ep = getenv("EDITOR")) != NULL) { /* if we have a value */ 517 if ((p = strrchr(ep, '/')) != NULL) /* if it has a path */ 518 ep = p + 1; /* then we want only the last part */ 519 } 520 else 521 ep = "ed"; 522 523 if ((vp = getenv("VISUAL")) != NULL) { /* if we have a value */ 524 if ((p = strrchr(vp, '/')) != NULL) /* and it has a path */ 525 vp = p + 1; /* then we want only the last part */ 526 } 527 else 528 vp = "vi"; 529 530 for (vpl = 0; vp[vpl] && !isspace((unsigned char)vp[vpl]); vpl++) 531 continue; 532 for (epl = 0; ep[epl] && !isspace((unsigned char)ep[epl]); epl++) 533 continue; 534 535 if (pcurrent == NULL) /* see if we have any jobs */ 536 return NULL; /* nope */ 537 538 if ((varp = adrof(STReditors)) != NULL) 539 vv = varp->vec; 540 else 541 vv = NULL; 542 543 retp = NULL; 544 for (pp = proclist.p_next; pp; pp = pp->p_next) 545 if (pp->p_procid == pp->p_jobid) { 546 547 /* 548 * Only foreground an edit session if it is suspended. Some GUI 549 * editors have may be happily running in a separate window, no 550 * point in foregrounding these if they're already running - webb 551 */ 552 pstatus = (int) (pp->p_flags & PALLSTATES); 553 if (pstatus != PINTERRUPTED && pstatus != PSTOPPED && 554 pstatus != PSIGNALED) 555 continue; 556 557 p = short2str(pp->p_command); 558 /* get the first word */ 559 for (cp = p; *cp && !isspace((unsigned char) *cp); cp++) 560 continue; 561 *cp = '\0'; 562 563 if ((cp = strrchr(p, '/')) != NULL) /* and it has a path */ 564 cp = cp + 1; /* then we want only the last part */ 565 else 566 cp = p; /* else we get all of it */ 567 568 /* if we find either in the current name, fg it */ 569 if (strncmp(ep, cp, epl) == 0 || 570 strncmp(vp, cp, vpl) == 0 || findvv(vv, cp)) { 571 572 /* 573 * If there is a choice, then choose the current process if 574 * available, or the previous process otherwise, or else 575 * anything will do - Robert Webb (robertw@mulga.cs.mu.oz.au). 576 */ 577 if (pp == pcurrent) 578 return pp; 579 else if (retp == NULL || pp == pprevious) 580 retp = pp; 581 } 582 } 583 584 return retp; /* Will be NULL if we didn't find a job */ 585 } 586 587 void 588 fg_proc_entry(struct process *pp) 589 { 590 jmp_buf_t osetexit; 591 int ohaderr; 592 Char oGettingInput; 593 size_t omark; 594 595 getexit(osetexit); 596 597 pintr_disabled++; 598 oGettingInput = GettingInput; 599 GettingInput = 0; 600 601 ohaderr = haderr; /* we need to ignore setting of haderr due to 602 * process getting stopped by a signal */ 603 omark = cleanup_push_mark(); 604 if (setexit() == 0) { /* come back here after pjwait */ 605 pendjob(); 606 (void) alarm(0); /* No autologout */ 607 alrmcatch_disabled = 1; 608 if (!pstart(pp, 1)) { 609 pp->p_procid = 0; 610 stderror(ERR_BADJOB, pp->p_command, strerror(errno)); 611 } 612 pjwait(pp); 613 } 614 setalarm(1); /* Autologout back on */ 615 cleanup_pop_mark(omark); 616 resexit(osetexit); 617 haderr = ohaderr; 618 GettingInput = oGettingInput; 619 620 disabled_cleanup(&pintr_disabled); 621 } 622 623 static char * 624 xgetpass(const char *prm) 625 { 626 static struct strbuf pass; /* = strbuf_INIT; */ 627 int fd; 628 sigset_t oset, set; 629 struct sigaction sa, osa; 630 631 sa.sa_handler = SIG_IGN; 632 sigemptyset(&sa.sa_mask); 633 sa.sa_flags = 0; 634 (void)sigaction(SIGINT, &sa, &osa); 635 636 sigemptyset(&set); 637 sigaddset(&set, SIGINT); 638 (void)sigprocmask(SIG_UNBLOCK, &set, &oset); 639 640 cleanup_push(&osa, sigint_cleanup); 641 cleanup_push(&oset, sigprocmask_cleanup); 642 (void) Rawmode(); /* Make sure, cause we want echo off */ 643 fd = xopen("/dev/tty", O_RDWR|O_LARGEFILE); 644 if (fd == -1) 645 fd = SHIN; 646 else 647 cleanup_push(&fd, open_cleanup); 648 649 xprintf("%s", prm); flush(); 650 pass.len = 0; 651 for (;;) { 652 char c; 653 654 if (xread(fd, &c, 1) < 1 || c == '\n') 655 break; 656 strbuf_append1(&pass, c); 657 } 658 strbuf_terminate(&pass); 659 660 cleanup_until(&osa); 661 662 return pass.s; 663 } 664 665 #ifndef NO_CRYPT 666 #if !HAVE_DECL_CRYPT 667 extern char *crypt (); 668 #endif 669 #ifdef HAVE_CRYPT_H 670 #include <crypt.h> 671 #endif 672 #endif 673 674 /* 675 * Ask the user for his login password to continue working 676 * On systems that have a shadow password, this will only 677 * work for root, but what can we do? 678 * 679 * If we fail to get the password, then we log the user out 680 * immediately 681 */ 682 /*ARGSUSED*/ 683 static void 684 auto_lock(void) 685 { 686 #ifndef NO_CRYPT 687 688 int i; 689 char *srpp = NULL; 690 struct passwd *pw; 691 692 #undef XCRYPT 693 694 #if defined(HAVE_AUTH_H) && defined(HAVE_GETAUTHUID) 695 696 struct authorization *apw; 697 extern char *crypt16 (const char *, const char *); 698 699 # define XCRYPT(pw, a, b) crypt16(a, b) 700 701 if ((pw = xgetpwuid(euid)) != NULL && /* effective user passwd */ 702 (apw = getauthuid(euid)) != NULL) /* enhanced ultrix passwd */ 703 srpp = apw->a_password; 704 705 #elif defined(HAVE_SHADOW_H) 706 707 struct spwd *spw; 708 709 # define XCRYPT(pw, a, b) crypt(a, b) 710 711 if ((pw = xgetpwuid(euid)) != NULL) { /* effective user passwd */ 712 errno = 0; 713 while ((spw = getspnam(pw->pw_name)) == NULL && errno == EINTR) { 714 handle_pending_signals(); 715 errno = 0; 716 } 717 if (spw != NULL) /* shadowed passwd */ 718 srpp = spw->sp_pwdp; 719 } 720 721 #else 722 723 724 #ifdef __CYGWIN__ 725 # define XCRYPT(pw, a, b) cygwin_xcrypt(pw, a, b) 726 #else 727 # define XCRYPT(pw, a, b) crypt(a, b) 728 #endif 729 730 #if !defined(__MVS__) 731 if ((pw = xgetpwuid(euid)) != NULL) /* effective user passwd */ 732 srpp = pw->pw_passwd; 733 #endif /* !MVS */ 734 735 #endif 736 737 if (srpp == NULL) { 738 auto_logout(); 739 /*NOTREACHED*/ 740 return; 741 } 742 743 setalarm(0); /* Not for locking any more */ 744 xputchar('\n'); 745 for (i = 0; i < 5; i++) { 746 const char *crpp; 747 char *pp; 748 #ifdef AFS 749 char *afsname; 750 Char *safs; 751 752 if ((safs = varval(STRafsuser)) != STRNULL) 753 afsname = short2str(safs); 754 else 755 if ((afsname = getenv("AFSUSER")) == NULL) 756 afsname = pw->pw_name; 757 #endif 758 pp = xgetpass("Password:"); 759 760 crpp = XCRYPT(pw, pp, srpp); 761 if ((crpp && strcmp(crpp, srpp) == 0) 762 #ifdef AFS 763 || (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, 764 afsname, /* name */ 765 NULL, /* instance */ 766 NULL, /* realm */ 767 pp, /* password */ 768 0, /* lifetime */ 769 0, 0, /* spare */ 770 NULL) /* reason */ 771 == 0) 772 #endif /* AFS */ 773 ) { 774 (void) memset(pp, 0, strlen(pp)); 775 if (GettingInput && !just_signaled) { 776 (void) Rawmode(); 777 ClearLines(); 778 ClearDisp(); 779 Refresh(); 780 } 781 just_signaled = 0; 782 return; 783 } 784 xprintf(CGETS(22, 2, "\nIncorrect passwd for %s\n"), pw->pw_name); 785 } 786 #endif /* NO_CRYPT */ 787 auto_logout(); 788 } 789 790 791 static void 792 auto_logout(void) 793 { 794 xprintf("auto-logout\n"); 795 /* Don't leave the tty in raw mode */ 796 if (editing) 797 (void) Cookedmode(); 798 xclose(SHIN); 799 setcopy(STRlogout, STRautomatic, VAR_READWRITE); 800 child = 1; 801 #ifdef TESLA 802 do_logout = 1; 803 #endif /* TESLA */ 804 GettingInput = FALSE; /* make flush() work to write hist files. Huber*/ 805 goodbye(NULL, NULL); 806 } 807 808 void 809 alrmcatch(void) 810 { 811 (*alm_fun)(); 812 setalarm(1); 813 } 814 815 /* 816 * Karl Kleinpaste, 21oct1983. 817 * Added precmd(), which checks for the alias 818 * precmd in aliases. If it's there, the alias 819 * is executed as a command. This is done 820 * after mailchk() and just before print- 821 * ing the prompt. Useful for things like printing 822 * one's current directory just before each command. 823 */ 824 void 825 precmd(void) 826 { 827 pintr_disabled++; 828 cleanup_push(&pintr_disabled, disabled_cleanup); 829 if (precmd_active) { /* an error must have been caught */ 830 aliasrun(2, STRunalias, STRprecmd); 831 xprintf("%s", CGETS(22, 3, "Faulty alias 'precmd' removed.\n")); 832 goto leave; 833 } 834 precmd_active = 1; 835 if (!whyles && adrof1(STRprecmd, &aliases)) 836 aliasrun(1, STRprecmd, NULL); 837 leave: 838 precmd_active = 0; 839 cleanup_until(&pintr_disabled); 840 } 841 842 void 843 postcmd(void) 844 { 845 pintr_disabled++; 846 cleanup_push(&pintr_disabled, disabled_cleanup); 847 if (postcmd_active) { /* an error must have been caught */ 848 aliasrun(2, STRunalias, STRpostcmd); 849 xprintf("%s", CGETS(22, 3, "Faulty alias 'postcmd' removed.\n")); 850 goto leave; 851 } 852 postcmd_active = 1; 853 if (!whyles && adrof1(STRpostcmd, &aliases)) 854 aliasrun(1, STRpostcmd, NULL); 855 leave: 856 postcmd_active = 0; 857 cleanup_until(&pintr_disabled); 858 } 859 860 /* 861 * Paul Placeway 11/24/87 Added cwd_cmd by hacking precmd() into 862 * submission... Run every time $cwd is set (after it is set). Useful 863 * for putting your machine and cwd (or anything else) in an xterm title 864 * space. 865 */ 866 void 867 cwd_cmd(void) 868 { 869 pintr_disabled++; 870 cleanup_push(&pintr_disabled, disabled_cleanup); 871 if (cwdcmd_active) { /* an error must have been caught */ 872 aliasrun(2, STRunalias, STRcwdcmd); 873 xprintf("%s", CGETS(22, 4, "Faulty alias 'cwdcmd' removed.\n")); 874 goto leave; 875 } 876 cwdcmd_active = 1; 877 if (!whyles && adrof1(STRcwdcmd, &aliases)) 878 aliasrun(1, STRcwdcmd, NULL); 879 leave: 880 cwdcmd_active = 0; 881 cleanup_until(&pintr_disabled); 882 } 883 884 /* 885 * Joachim Hoenig 07/16/91 Added beep_cmd, run every time tcsh wishes 886 * to beep the terminal bell. Useful for playing nice sounds instead. 887 */ 888 void 889 beep_cmd(void) 890 { 891 pintr_disabled++; 892 cleanup_push(&pintr_disabled, disabled_cleanup); 893 if (beepcmd_active) { /* an error must have been caught */ 894 aliasrun(2, STRunalias, STRbeepcmd); 895 xprintf("%s", CGETS(22, 5, "Faulty alias 'beepcmd' removed.\n")); 896 } 897 else { 898 beepcmd_active = 1; 899 if (!whyles && adrof1(STRbeepcmd, &aliases)) 900 aliasrun(1, STRbeepcmd, NULL); 901 } 902 beepcmd_active = 0; 903 cleanup_until(&pintr_disabled); 904 } 905 906 907 /* 908 * Karl Kleinpaste, 18 Jan 1984. 909 * Added period_cmd(), which executes the alias "periodic" every 910 * $tperiod minutes. Useful for occasional checking of msgs and such. 911 */ 912 void 913 period_cmd(void) 914 { 915 Char *vp; 916 time_t t, interval; 917 918 pintr_disabled++; 919 cleanup_push(&pintr_disabled, disabled_cleanup); 920 if (periodic_active) { /* an error must have been caught */ 921 aliasrun(2, STRunalias, STRperiodic); 922 xprintf("%s", CGETS(22, 6, "Faulty alias 'periodic' removed.\n")); 923 goto leave; 924 } 925 periodic_active = 1; 926 if (!whyles && adrof1(STRperiodic, &aliases)) { 927 vp = varval(STRtperiod); 928 if (vp == STRNULL) { 929 aliasrun(1, STRperiodic, NULL); 930 goto leave; 931 } 932 interval = getn(vp); 933 (void) time(&t); 934 if (t - t_period >= interval * 60) { 935 t_period = t; 936 aliasrun(1, STRperiodic, NULL); 937 } 938 } 939 leave: 940 periodic_active = 0; 941 cleanup_until(&pintr_disabled); 942 } 943 944 945 /* 946 * GrP Greg Parker May 2001 947 * Added job_cmd(), which is run every time a job is started or 948 * foregrounded. The command is passed a single argument, the string 949 * used to start the job originally. With precmd, useful for setting 950 * xterm titles. 951 * Cloned from cwd_cmd(). 952 */ 953 void 954 job_cmd(Char *args) 955 { 956 pintr_disabled++; 957 cleanup_push(&pintr_disabled, disabled_cleanup); 958 if (jobcmd_active) { /* an error must have been caught */ 959 aliasrun(2, STRunalias, STRjobcmd); 960 xprintf("%s", CGETS(22, 14, "Faulty alias 'jobcmd' removed.\n")); 961 goto leave; 962 } 963 jobcmd_active = 1; 964 if (!whyles && adrof1(STRjobcmd, &aliases)) { 965 struct process *pp = pcurrjob; /* put things back after the hook */ 966 aliasrun(2, STRjobcmd, args); 967 pcurrjob = pp; 968 } 969 leave: 970 jobcmd_active = 0; 971 cleanup_until(&pintr_disabled); 972 } 973 974 975 /* 976 * Karl Kleinpaste, 21oct1983. 977 * Set up a one-word alias command, for use for special things. 978 * This code is based on the mainline of process(). 979 */ 980 void 981 aliasrun(int cnt, Char *s1, Char *s2) 982 { 983 struct wordent w, *new1, *new2; /* for holding alias name */ 984 struct command *t = NULL; 985 jmp_buf_t osetexit; 986 int status; 987 size_t omark; 988 989 getexit(osetexit); 990 if (seterr) { 991 xfree(seterr); 992 seterr = NULL; /* don't repeatedly print err msg. */ 993 } 994 w.word = STRNULL; 995 new1 = xcalloc(1, sizeof w); 996 new1->word = Strsave(s1); 997 if (cnt == 1) { 998 /* build a lex list with one word. */ 999 w.next = w.prev = new1; 1000 new1->next = new1->prev = &w; 1001 } 1002 else { 1003 /* build a lex list with two words. */ 1004 new2 = xcalloc(1, sizeof w); 1005 new2->word = Strsave(s2); 1006 w.next = new2->prev = new1; 1007 new1->next = w.prev = new2; 1008 new1->prev = new2->next = &w; 1009 } 1010 cleanup_push(&w, lex_cleanup); 1011 1012 /* Save the old status */ 1013 status = getn(varval(STRstatus)); 1014 1015 /* expand aliases like process() does. */ 1016 alias(&w); 1017 /* build a syntax tree for the command. */ 1018 t = syntax(w.next, &w, 0); 1019 cleanup_push(t, syntax_cleanup); 1020 if (seterr) 1021 stderror(ERR_OLD); 1022 1023 psavejob(); 1024 cleanup_push(&cnt, psavejob_cleanup); /* cnt is used only as a marker */ 1025 1026 /* catch any errors here */ 1027 omark = cleanup_push_mark(); 1028 if (setexit() == 0) 1029 /* execute the parse tree. */ 1030 /* 1031 * From: Michael Schroeder <mlschroe@immd4.informatik.uni-erlangen.de> 1032 * was execute(t, tpgrp); 1033 */ 1034 execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL, TRUE); 1035 /* reset the error catcher to the old place */ 1036 cleanup_pop_mark(omark); 1037 resexit(osetexit); 1038 if (haderr) { 1039 haderr = 0; 1040 /* 1041 * Either precmd, or cwdcmd, or periodic had an error. Call it again so 1042 * that it is removed 1043 */ 1044 if (precmd_active) 1045 precmd(); 1046 if (postcmd_active) 1047 postcmd(); 1048 #ifdef notdef 1049 /* 1050 * XXX: On the other hand, just interrupting them causes an error too. 1051 * So if we hit ^C in the middle of cwdcmd or periodic the alias gets 1052 * removed. We don't want that. Note that we want to remove precmd 1053 * though, cause that could lead into an infinite loop. This should be 1054 * fixed correctly, but then haderr should give us the whole exit 1055 * status not just true or false. 1056 */ 1057 else if (cwdcmd_active) 1058 cwd_cmd(); 1059 else if (beepcmd_active) 1060 beep_cmd(); 1061 else if (periodic_active) 1062 period_cmd(); 1063 #endif /* notdef */ 1064 } 1065 cleanup_until(&w); 1066 pendjob(); 1067 /* Restore status */ 1068 setv(STRstatus, putn((tcsh_number_t)status), VAR_READWRITE); 1069 } 1070 1071 void 1072 setalarm(int lck) 1073 { 1074 struct varent *vp; 1075 Char *cp; 1076 unsigned alrm_time = 0, logout_time, lock_time; 1077 time_t cl, nl, sched_dif; 1078 1079 if ((vp = adrof(STRautologout)) != NULL && vp->vec != NULL) { 1080 if ((cp = vp->vec[0]) != 0) { 1081 if ((logout_time = (unsigned) atoi(short2str(cp)) * 60) > 0) { 1082 #ifdef SOLARIS2 1083 /* 1084 * Solaris alarm(2) uses a timer based in clock ticks 1085 * internally so it multiplies our value with CLK_TCK... 1086 * Of course that can overflow leading to unexpected 1087 * results, so we clip it here. Grr. Where is that 1088 * documented folks? 1089 */ 1090 if (logout_time >= 0x7fffffff / CLK_TCK) 1091 logout_time = 0x7fffffff / CLK_TCK; 1092 #endif /* SOLARIS2 */ 1093 alrm_time = logout_time; 1094 alm_fun = auto_logout; 1095 } 1096 } 1097 if ((cp = vp->vec[1]) != 0) { 1098 if ((lock_time = (unsigned) atoi(short2str(cp)) * 60) > 0) { 1099 if (lck) { 1100 if (alrm_time == 0 || lock_time < alrm_time) { 1101 alrm_time = lock_time; 1102 alm_fun = auto_lock; 1103 } 1104 } 1105 else /* lock_time always < alrm_time */ 1106 if (alrm_time) 1107 alrm_time -= lock_time; 1108 } 1109 } 1110 } 1111 if ((nl = sched_next()) != -1) { 1112 (void) time(&cl); 1113 sched_dif = nl > cl ? nl - cl : 0; 1114 if ((alrm_time == 0) || ((unsigned) sched_dif < alrm_time)) { 1115 alrm_time = ((unsigned) sched_dif) + 1; 1116 alm_fun = sched_run; 1117 } 1118 } 1119 alrmcatch_disabled = 0; 1120 (void) alarm(alrm_time); /* Autologout ON */ 1121 } 1122 1123 #undef RMDEBUG /* For now... */ 1124 1125 void 1126 rmstar(struct wordent *cp) 1127 { 1128 struct wordent *we, *args; 1129 struct wordent *tmp, *del; 1130 1131 #ifdef RMDEBUG 1132 static Char STRrmdebug[] = {'r', 'm', 'd', 'e', 'b', 'u', 'g', '\0'}; 1133 Char *tag; 1134 #endif /* RMDEBUG */ 1135 Char *charac; 1136 char c; 1137 int ask, doit, star = 0, silent = 0, opintr_disabled; 1138 1139 if (!adrof(STRrmstar)) 1140 return; 1141 #ifdef RMDEBUG 1142 tag = varval(STRrmdebug); 1143 #endif /* RMDEBUG */ 1144 we = cp->next; 1145 while (*we->word == ';' && we != cp) 1146 we = we->next; 1147 opintr_disabled = pintr_disabled; 1148 pintr_disabled = 0; 1149 while (we != cp) { 1150 #ifdef RMDEBUG 1151 if (*tag) 1152 xprintf(CGETS(22, 7, "parsing command line\n")); 1153 #endif /* RMDEBUG */ 1154 if (!Strcmp(we->word, STRrm)) { 1155 args = we->next; 1156 ask = (*args->word != '-'); 1157 while (*args->word == '-' && !silent) { /* check options */ 1158 for (charac = (args->word + 1); *charac && !silent; charac++) 1159 silent = (*charac == 'i' || *charac == 'f'); 1160 args = args->next; 1161 } 1162 ask = (ask || (!ask && !silent)); 1163 if (ask) { 1164 for (; !star && *args->word != ';' 1165 && args != cp; args = args->next) 1166 if (!Strcmp(args->word, STRstar)) 1167 star = 1; 1168 if (ask && star) { 1169 xprintf("%s", CGETS(22, 8, 1170 "Do you really want to delete all files? [n/y] ")); 1171 flush(); 1172 (void) force_read(SHIN, &c, 1); 1173 /* 1174 * Perhaps we should use the yesexpr from the 1175 * actual locale 1176 */ 1177 doit = (strchr(CGETS(22, 14, "Yy"), c) != NULL); 1178 while (c != '\n' && force_read(SHIN, &c, 1) == 1) 1179 continue; 1180 if (!doit) { 1181 /* remove the command instead */ 1182 #ifdef RMDEBUG 1183 if (*tag) 1184 xprintf(CGETS(22, 9, 1185 "skipping deletion of files!\n")); 1186 #endif /* RMDEBUG */ 1187 for (tmp = we; 1188 *tmp->word != '\n' && 1189 *tmp->word != ';' && tmp != cp;) { 1190 tmp->prev->next = tmp->next; 1191 tmp->next->prev = tmp->prev; 1192 xfree(tmp->word); 1193 del = tmp; 1194 tmp = tmp->next; 1195 xfree(del); 1196 } 1197 if (*tmp->word == ';') { 1198 tmp->prev->next = tmp->next; 1199 tmp->next->prev = tmp->prev; 1200 xfree(tmp->word); 1201 del = tmp; 1202 tmp = tmp->next; 1203 xfree(del); 1204 } 1205 we = tmp; 1206 continue; 1207 } 1208 } 1209 } 1210 } 1211 for (we = we->next; 1212 *we->word != ';' && we != cp; 1213 we = we->next) 1214 continue; 1215 if (*we->word == ';') 1216 we = we->next; 1217 } 1218 #ifdef RMDEBUG 1219 if (*tag) { 1220 xprintf(CGETS(22, 10, "command line now is:\n")); 1221 for (we = cp->next; we != cp; we = we->next) 1222 xprintf("%S ", we->word); 1223 } 1224 #endif /* RMDEBUG */ 1225 pintr_disabled = opintr_disabled; 1226 return; 1227 } 1228 1229 #ifdef BSDJOBS 1230 /* Check if command is in continue list 1231 and do a "aliasing" if it exists as a job in background */ 1232 1233 #undef CNDEBUG /* For now */ 1234 void 1235 continue_jobs(struct wordent *cp) 1236 { 1237 struct wordent *we; 1238 struct process *pp, *np; 1239 Char *cmd, *continue_list, *continue_args_list; 1240 1241 #ifdef CNDEBUG 1242 Char *tag; 1243 static Char STRcndebug[] = 1244 {'c', 'n', 'd', 'e', 'b', 'u', 'g', '\0'}; 1245 #endif /* CNDEBUG */ 1246 int in_cont_list, in_cont_arg_list; 1247 1248 1249 #ifdef CNDEBUG 1250 tag = varval(STRcndebug); 1251 #endif /* CNDEBUG */ 1252 continue_list = varval(STRcontinue); 1253 continue_args_list = varval(STRcontinue_args); 1254 if (*continue_list == '\0' && *continue_args_list == '\0') 1255 return; 1256 1257 we = cp->next; 1258 while (*we->word == ';' && we != cp) 1259 we = we->next; 1260 while (we != cp) { 1261 #ifdef CNDEBUG 1262 if (*tag) 1263 xprintf(CGETS(22, 11, "parsing command line\n")); 1264 #endif /* CNDEBUG */ 1265 cmd = we->word; 1266 in_cont_list = inlist(continue_list, cmd); 1267 in_cont_arg_list = inlist(continue_args_list, cmd); 1268 if (in_cont_list || in_cont_arg_list) { 1269 #ifdef CNDEBUG 1270 if (*tag) 1271 xprintf(CGETS(22, 12, "in one of the lists\n")); 1272 #endif /* CNDEBUG */ 1273 np = NULL; 1274 for (pp = proclist.p_next; pp; pp = pp->p_next) { 1275 if (prefix(cmd, pp->p_command)) { 1276 if (pp->p_index) { 1277 np = pp; 1278 break; 1279 } 1280 } 1281 } 1282 if (np) { 1283 insert(we, in_cont_arg_list); 1284 } 1285 } 1286 for (we = we->next; 1287 *we->word != ';' && we != cp; 1288 we = we->next) 1289 continue; 1290 if (*we->word == ';') 1291 we = we->next; 1292 } 1293 #ifdef CNDEBUG 1294 if (*tag) { 1295 xprintf(CGETS(22, 13, "command line now is:\n")); 1296 for (we = cp->next; we != cp; we = we->next) 1297 xprintf("%S ", we->word); 1298 } 1299 #endif /* CNDEBUG */ 1300 return; 1301 } 1302 1303 /* The actual "aliasing" of for backgrounds() is done here 1304 with the aid of insert_we(). */ 1305 static void 1306 insert(struct wordent *pl, int file_args) 1307 { 1308 struct wordent *now, *last; 1309 Char *cmd, *bcmd, *cp1, *cp2; 1310 size_t cmd_len; 1311 Char *upause = STRunderpause; 1312 size_t p_len = Strlen(upause); 1313 1314 cmd_len = Strlen(pl->word); 1315 cmd = xcalloc(1, (cmd_len + 1) * sizeof(Char)); 1316 (void) Strcpy(cmd, pl->word); 1317 /* Do insertions at beginning, first replace command word */ 1318 1319 if (file_args) { 1320 now = pl; 1321 xfree(now->word); 1322 now->word = xcalloc(1, 5 * sizeof(Char)); 1323 (void) Strcpy(now->word, STRecho); 1324 1325 now = xcalloc(1, sizeof(struct wordent)); 1326 now->word = xcalloc(1, 6 * sizeof(Char)); 1327 (void) Strcpy(now->word, STRbackqpwd); 1328 insert_we(now, pl); 1329 1330 for (last = now; *last->word != '\n' && *last->word != ';'; 1331 last = last->next) 1332 continue; 1333 1334 now = xcalloc(1, sizeof(struct wordent)); 1335 now->word = xcalloc(1, 2 * sizeof(Char)); 1336 (void) Strcpy(now->word, STRgt); 1337 insert_we(now, last->prev); 1338 1339 now = xcalloc(1, sizeof(struct wordent)); 1340 now->word = xcalloc(1, 2 * sizeof(Char)); 1341 (void) Strcpy(now->word, STRbang); 1342 insert_we(now, last->prev); 1343 1344 now = xcalloc(1, sizeof(struct wordent)); 1345 now->word = xcalloc(1, (cmd_len + p_len + 4) * sizeof(Char)); 1346 cp1 = now->word; 1347 cp2 = cmd; 1348 *cp1++ = '~'; 1349 *cp1++ = '/'; 1350 *cp1++ = '.'; 1351 while ((*cp1++ = *cp2++) != '\0') 1352 continue; 1353 cp1--; 1354 cp2 = upause; 1355 while ((*cp1++ = *cp2++) != '\0') 1356 continue; 1357 insert_we(now, last->prev); 1358 1359 now = xcalloc(1, sizeof(struct wordent)); 1360 now->word = xcalloc(1, 2 * sizeof(Char)); 1361 (void) Strcpy(now->word, STRsemi); 1362 insert_we(now, last->prev); 1363 bcmd = xcalloc(1, (cmd_len + 2) * sizeof(Char)); 1364 *bcmd = '%'; 1365 Strcpy(bcmd + 1, cmd); 1366 now = xcalloc(1, sizeof(struct wordent)); 1367 now->word = bcmd; 1368 insert_we(now, last->prev); 1369 } 1370 else { 1371 struct wordent *del; 1372 1373 now = pl; 1374 xfree(now->word); 1375 now->word = xcalloc(1, (cmd_len + 2) * sizeof(Char)); 1376 *now->word = '%'; 1377 Strcpy(now->word + 1, cmd); 1378 for (now = now->next; 1379 *now->word != '\n' && *now->word != ';' && now != pl;) { 1380 now->prev->next = now->next; 1381 now->next->prev = now->prev; 1382 xfree(now->word); 1383 del = now; 1384 now = now->next; 1385 xfree(del); 1386 } 1387 } 1388 } 1389 1390 static void 1391 insert_we(struct wordent *new, struct wordent *where) 1392 { 1393 1394 new->prev = where; 1395 new->next = where->next; 1396 where->next = new; 1397 new->next->prev = new; 1398 } 1399 1400 static int 1401 inlist(Char *list, Char *name) 1402 { 1403 Char *l, *n; 1404 1405 l = list; 1406 n = name; 1407 1408 while (*l && *n) { 1409 if (*l == *n) { 1410 l++; 1411 n++; 1412 if (*n == '\0' && (*l == ' ' || *l == '\0')) 1413 return (1); 1414 else 1415 continue; 1416 } 1417 else { 1418 while (*l && *l != ' ') 1419 l++; /* skip to blank */ 1420 while (*l && *l == ' ') 1421 l++; /* and find first nonblank character */ 1422 n = name; 1423 } 1424 } 1425 return (0); 1426 } 1427 1428 #endif /* BSDJOBS */ 1429 1430 1431 /* 1432 * Implement a small cache for tilde names. This is used primarily 1433 * to expand tilde names to directories, but also 1434 * we can find users from their home directories for the tilde 1435 * prompt, on machines where yp lookup is slow this can be a big win... 1436 * As with any cache this can run out of sync, rehash can sync it again. 1437 */ 1438 static struct tildecache { 1439 Char *user; 1440 Char *home; 1441 size_t hlen; 1442 } *tcache = NULL; 1443 1444 #define TILINCR 10 1445 size_t tlength = 0; 1446 static size_t tsize = TILINCR; 1447 1448 static int 1449 tildecompare(const void *xp1, const void *xp2) 1450 { 1451 const struct tildecache *p1, *p2; 1452 1453 p1 = xp1; 1454 p2 = xp2; 1455 return Strcmp(p1->user, p2->user); 1456 } 1457 1458 static Char * 1459 gethomedir(const Char *us) 1460 { 1461 struct passwd *pp; 1462 #ifdef HESIOD 1463 char **res, **res1, *cp; 1464 Char *rp; 1465 #endif /* HESIOD */ 1466 1467 pp = xgetpwnam(short2str(us)); 1468 #ifdef YPBUGS 1469 fix_yp_bugs(); 1470 #endif /* YPBUGS */ 1471 if (pp != NULL) { 1472 #if 0 1473 /* Don't return if root */ 1474 if (pp->pw_dir[0] == '/' && pp->pw_dir[1] == '\0') 1475 return NULL; 1476 else 1477 #endif 1478 return Strsave(str2short(pp->pw_dir)); 1479 } 1480 #ifdef HESIOD 1481 res = hes_resolve(short2str(us), "filsys"); 1482 rp = NULL; 1483 if (res != NULL) { 1484 if ((*res) != NULL) { 1485 /* 1486 * Look at the first token to determine how to interpret 1487 * the rest of it. 1488 * Yes, strtok is evil (it's not thread-safe), but it's also 1489 * easy to use. 1490 */ 1491 cp = strtok(*res, " "); 1492 if (strcmp(cp, "AFS") == 0) { 1493 /* next token is AFS pathname.. */ 1494 cp = strtok(NULL, " "); 1495 if (cp != NULL) 1496 rp = Strsave(str2short(cp)); 1497 } else if (strcmp(cp, "NFS") == 0) { 1498 cp = NULL; 1499 if ((strtok(NULL, " ")) && /* skip remote pathname */ 1500 (strtok(NULL, " ")) && /* skip host */ 1501 (strtok(NULL, " ")) && /* skip mode */ 1502 (cp = strtok(NULL, " "))) { 1503 rp = Strsave(str2short(cp)); 1504 } 1505 } 1506 } 1507 for (res1 = res; *res1; res1++) 1508 free(*res1); 1509 #if 0 1510 /* Don't return if root */ 1511 if (rp != NULL && rp[0] == '/' && rp[1] == '\0') { 1512 xfree(rp); 1513 rp = NULL; 1514 } 1515 #endif 1516 return rp; 1517 } 1518 #endif /* HESIOD */ 1519 return NULL; 1520 } 1521 1522 Char * 1523 gettilde(const Char *us) 1524 { 1525 struct tildecache *bp1, *bp2, *bp; 1526 Char *hd; 1527 1528 /* Ignore NIS special names */ 1529 if (*us == '+' || *us == '-') 1530 return NULL; 1531 1532 if (tcache == NULL) 1533 tcache = xmalloc(TILINCR * sizeof(struct tildecache)); 1534 /* 1535 * Binary search 1536 */ 1537 for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) { 1538 int i; 1539 1540 bp = bp1 + ((bp2 - bp1) >> 1); 1541 if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0) 1542 return (bp->home); 1543 if (i < 0) 1544 bp2 = bp; 1545 else 1546 bp1 = bp + 1; 1547 } 1548 /* 1549 * Not in the cache, try to get it from the passwd file 1550 */ 1551 hd = gethomedir(us); 1552 if (hd == NULL) 1553 return NULL; 1554 1555 /* 1556 * Update the cache 1557 */ 1558 tcache[tlength].user = Strsave(us); 1559 tcache[tlength].home = hd; 1560 tcache[tlength++].hlen = Strlen(hd); 1561 1562 qsort(tcache, tlength, sizeof(struct tildecache), tildecompare); 1563 1564 if (tlength == tsize) { 1565 tsize += TILINCR; 1566 tcache = xrealloc(tcache, tsize * sizeof(struct tildecache)); 1567 } 1568 return (hd); 1569 } 1570 1571 /* 1572 * Return the username if the directory path passed contains a 1573 * user's home directory in the tilde cache, otherwise return NULL 1574 * hm points to the place where the path became different. 1575 * Special case: Our own home directory. 1576 * If we are passed a null pointer, then we flush the cache. 1577 */ 1578 Char * 1579 getusername(Char **hm) 1580 { 1581 Char *h, *p; 1582 size_t i, j; 1583 1584 if (hm == NULL) { 1585 for (i = 0; i < tlength; i++) { 1586 xfree(tcache[i].home); 1587 xfree(tcache[i].user); 1588 } 1589 xfree(tcache); 1590 tlength = 0; 1591 tsize = TILINCR; 1592 tcache = NULL; 1593 return NULL; 1594 } 1595 p = *hm; 1596 if (((h = varval(STRhome)) != STRNULL) && 1597 (Strncmp(p, h, j = Strlen(h)) == 0) && 1598 (p[j] == '/' || p[j] == '\0')) { 1599 *hm = &p[j]; 1600 return STRNULL; 1601 } 1602 for (i = 0; i < tlength; i++) 1603 if ((Strncmp(p, tcache[i].home, (j = tcache[i].hlen)) == 0) && 1604 (p[j] == '/' || p[j] == '\0')) { 1605 *hm = &p[j]; 1606 return tcache[i].user; 1607 } 1608 return NULL; 1609 } 1610 1611 1612 /* 1613 * set the shell-level var to 1 or apply change to it. 1614 */ 1615 void 1616 shlvl(int val) 1617 { 1618 char *cp; 1619 1620 if ((cp = getenv("SHLVL")) != NULL) { 1621 1622 if (loginsh) 1623 val = 1; 1624 else 1625 val += atoi(cp); 1626 1627 if (val <= 0) { 1628 if (adrof(STRshlvl) != NULL) 1629 unsetv(STRshlvl); 1630 Unsetenv(STRKSHLVL); 1631 } 1632 else { 1633 Char *p; 1634 1635 p = Itoa(val, 0, 0); 1636 cleanup_push(p, xfree); 1637 setv(STRshlvl, p, VAR_READWRITE); 1638 cleanup_ignore(p); 1639 cleanup_until(p); 1640 tsetenv(STRKSHLVL, p); 1641 } 1642 } 1643 else { 1644 setcopy(STRshlvl, STR1, VAR_READWRITE); 1645 tsetenv(STRKSHLVL, STR1); 1646 } 1647 } 1648 1649 1650 /* fixio(): 1651 * Try to recover from a read error 1652 */ 1653 int 1654 fixio(int fd, int e) 1655 { 1656 switch (e) { 1657 case -1: /* Make sure that the code is reachable */ 1658 1659 #ifdef EWOULDBLOCK 1660 case EWOULDBLOCK: 1661 # define FDRETRY 1662 #endif /* EWOULDBLOCK */ 1663 1664 #if defined(POSIX) && defined(EAGAIN) 1665 # if !defined(EWOULDBLOCK) || EWOULDBLOCK != EAGAIN 1666 case EAGAIN: 1667 # define FDRETRY 1668 # endif /* !EWOULDBLOCK || EWOULDBLOCK != EAGAIN */ 1669 #endif /* POSIX && EAGAIN */ 1670 1671 e = -1; 1672 #ifdef FDRETRY 1673 # ifdef F_SETFL 1674 /* 1675 * Great! we have on suns 3 flavors and 5 names... 1676 * I hope that will cover everything. 1677 * I added some more defines... many systems have different defines. 1678 * Rather than dealing with getting the right includes, we'll just 1679 * cover all the known possibilities here. -- sterling@netcom.com 1680 */ 1681 # ifndef O_NONBLOCK 1682 # define O_NONBLOCK 0 1683 # endif /* O_NONBLOCK */ 1684 # ifndef O_NDELAY 1685 # define O_NDELAY 0 1686 # endif /* O_NDELAY */ 1687 # ifndef FNBIO 1688 # define FNBIO 0 1689 # endif /* FNBIO */ 1690 # ifndef _FNBIO 1691 # define _FNBIO 0 1692 # endif /* _FNBIO */ 1693 # ifndef FNONBIO 1694 # define FNONBIO 0 1695 # endif /* FNONBIO */ 1696 # ifndef FNONBLOCK 1697 # define FNONBLOCK 0 1698 # endif /* FNONBLOCK */ 1699 # ifndef _FNONBLOCK 1700 # define _FNONBLOCK 0 1701 # endif /* _FNONBLOCK */ 1702 # ifndef FNDELAY 1703 # define FNDELAY 0 1704 # endif /* FNDELAY */ 1705 # ifndef _FNDELAY 1706 # define _FNDELAY 0 1707 # endif /* _FNDELAY */ 1708 # ifndef FNDLEAY /* Some linux versions have this typo */ 1709 # define FNDLEAY 0 1710 # endif /* FNDLEAY */ 1711 if ((e = fcntl(fd, F_GETFL, 0)) == -1) 1712 return -1; 1713 1714 e &= ~(O_NDELAY|O_NONBLOCK|FNBIO|_FNBIO|FNONBIO|FNONBLOCK|_FNONBLOCK| 1715 FNDELAY|_FNDELAY|FNDLEAY); /* whew! */ 1716 if (fcntl(fd, F_SETFL, e) == -1) 1717 return -1; 1718 else 1719 e = 0; 1720 # endif /* F_SETFL */ 1721 1722 # ifdef FIONBIO 1723 e = 0; 1724 if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1) 1725 return -1; 1726 # endif /* FIONBIO */ 1727 1728 #endif /* FDRETRY */ 1729 return e; 1730 1731 case EINTR: 1732 return 0; 1733 1734 default: 1735 return -1; 1736 } 1737 } 1738 1739 /* collate(): 1740 * String collation 1741 */ 1742 int 1743 collate(const Char *a, const Char *b) 1744 { 1745 int rv; 1746 #ifdef SHORT_STRINGS 1747 /* This strips the quote bit as a side effect */ 1748 char *sa = strsave(short2str(a)); 1749 char *sb = strsave(short2str(b)); 1750 #else 1751 char *sa = strip(strsave(a)); 1752 char *sb = strip(strsave(b)); 1753 #endif /* SHORT_STRINGS */ 1754 1755 #if defined(NLS) && defined(HAVE_STRCOLL) 1756 errno = 0; /* strcoll sets errno, another brain-damage */ 1757 1758 rv = strcoll(sa, sb); 1759 1760 /* 1761 * We should be checking for errno != 0, but some systems 1762 * forget to reset errno to 0. So we only check for the 1763 * only documented valid errno value for strcoll [EINVAL] 1764 */ 1765 if (errno == EINVAL) { 1766 xfree(sa); 1767 xfree(sb); 1768 stderror(ERR_SYSTEM, "strcoll", strerror(errno)); 1769 } 1770 #else 1771 rv = strcmp(sa, sb); 1772 #endif /* NLS && HAVE_STRCOLL */ 1773 1774 xfree(sa); 1775 xfree(sb); 1776 1777 return rv; 1778 } 1779 1780 #ifdef HASHBANG 1781 /* 1782 * From: peter@zeus.dialix.oz.au (Peter Wemm) 1783 * If exec() fails look first for a #! [word] [word] .... 1784 * If it is, splice the header into the argument list and retry. 1785 */ 1786 #define HACKBUFSZ 1024 /* Max chars in #! vector */ 1787 int 1788 hashbang(int fd, Char ***vp) 1789 { 1790 struct blk_buf sarg = BLK_BUF_INIT; 1791 char lbuf[HACKBUFSZ], *p, *ws; 1792 #ifdef WINNT_NATIVE 1793 int fw = 0; /* found at least one word */ 1794 int first_word = 1; 1795 char *real; 1796 #endif /* WINNT_NATIVE */ 1797 1798 if (xread(fd, lbuf, HACKBUFSZ) <= 0) 1799 return -1; 1800 1801 ws = 0; /* word started = 0 */ 1802 1803 for (p = lbuf; p < &lbuf[HACKBUFSZ]; ) { 1804 switch (*p) { 1805 case ' ': 1806 case '\t': 1807 #if defined(WINNT_NATIVE) || defined (__CYGWIN__) 1808 case '\r': 1809 #endif /* WINNT_NATIVE || __CYGWIN__ */ 1810 if (ws) { /* a blank after a word.. save it */ 1811 *p = '\0'; 1812 #ifdef WINNT_NATIVE 1813 if (first_word) { 1814 real = hb_subst(ws); 1815 if (real != NULL) 1816 ws = real; 1817 } 1818 fw = 1; 1819 first_word = 0; 1820 #endif /* WINNT_NATIVE */ 1821 bb_append(&sarg, SAVE(ws)); 1822 ws = NULL; 1823 } 1824 p++; 1825 continue; 1826 1827 case '\0': /* Whoa!! what the hell happened */ 1828 goto err; 1829 1830 case '\n': /* The end of the line. */ 1831 if ( 1832 #ifdef WINNT_NATIVE 1833 fw || 1834 #endif /* WINNT_NATIVE */ 1835 ws) { /* terminate the last word */ 1836 *p = '\0'; 1837 #ifdef WINNT_NATIVE 1838 /* deal with the 1-word case */ 1839 if (first_word) { 1840 real = hb_subst(ws); 1841 if (real != NULL) 1842 ws = real; 1843 } 1844 #endif /* !WINNT_NATIVE */ 1845 if (ws) 1846 bb_append(&sarg, SAVE(ws)); 1847 } 1848 if (sarg.len > 0) { 1849 *vp = bb_finish(&sarg); 1850 return 0; 1851 } 1852 else 1853 goto err; 1854 1855 default: 1856 if (!ws) /* Start a new word? */ 1857 ws = p; 1858 p++; 1859 break; 1860 } 1861 } 1862 err: 1863 bb_cleanup(&sarg); 1864 return -1; 1865 } 1866 #endif /* HASHBANG */ 1867 1868 #ifdef REMOTEHOST 1869 1870 static void 1871 palarm(int snum) 1872 { 1873 USE(snum); 1874 _exit(1); 1875 } 1876 1877 static void 1878 getremotehost(int dest_fd) 1879 { 1880 const char *host = NULL; 1881 #ifdef INET6 1882 struct sockaddr_storage saddr; 1883 static char hbuf[NI_MAXHOST]; 1884 #else 1885 struct hostent* hp; 1886 struct sockaddr_in saddr; 1887 #endif 1888 socklen_t len = sizeof(saddr); 1889 1890 #ifdef INET6 1891 if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 1892 (saddr.ss_family == AF_INET6 || saddr.ss_family == AF_INET)) { 1893 int flag = NI_NUMERICHOST; 1894 1895 #ifdef NI_WITHSCOPEID 1896 flag |= NI_WITHSCOPEID; 1897 #endif 1898 getnameinfo((struct sockaddr *)&saddr, len, hbuf, sizeof(hbuf), 1899 NULL, 0, flag); 1900 host = hbuf; 1901 #else 1902 if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 1903 saddr.sin_family == AF_INET) { 1904 #if 0 1905 if ((hp = gethostbyaddr((char *)&saddr.sin_addr, sizeof(struct in_addr), 1906 AF_INET)) != NULL) 1907 host = hp->h_name; 1908 else 1909 #endif 1910 host = inet_ntoa(saddr.sin_addr); 1911 #endif 1912 } 1913 #ifdef HAVE_STRUCT_UTMP_UT_HOST 1914 else { 1915 char *ptr; 1916 char *name = utmphost(); 1917 /* Avoid empty names and local X displays */ 1918 if (name != NULL && *name != '\0' && *name != ':') { 1919 struct in_addr addr; 1920 char *sptr; 1921 1922 /* Look for host:display.screen */ 1923 /* 1924 * There is conflict with IPv6 address and X DISPLAY. So, 1925 * we assume there is no IPv6 address in utmp and don't 1926 * touch here. 1927 */ 1928 if ((sptr = strchr(name, ':')) != NULL) 1929 *sptr = '\0'; 1930 /* Leave IPv4 address as is */ 1931 /* 1932 * we use inet_addr here, not inet_aton because many systems 1933 * have not caught up yet. 1934 */ 1935 addr.s_addr = inet_addr(name); 1936 if (addr.s_addr != (unsigned int)~0) 1937 host = name; 1938 else { 1939 if (sptr != name) { 1940 #ifdef INET6 1941 char *s, *domain; 1942 char dbuf[MAXHOSTNAMELEN]; 1943 struct addrinfo hints, *res = NULL; 1944 1945 memset(&hints, 0, sizeof(hints)); 1946 hints.ai_family = PF_UNSPEC; 1947 hints.ai_socktype = SOCK_STREAM; 1948 hints.ai_flags = AI_PASSIVE | AI_CANONNAME; 1949 if (strlen(name) < utmphostsize()) 1950 { 1951 if (getaddrinfo(name, NULL, &hints, &res) != 0) 1952 res = NULL; 1953 } else if (gethostname(dbuf, sizeof(dbuf)) == 0 && 1954 (dbuf[sizeof(dbuf)-1] = '\0', /*FIXME: ugly*/ 1955 (domain = strchr(dbuf, '.')) != NULL)) { 1956 for (s = strchr(name, '.'); 1957 s != NULL; s = strchr(s + 1, '.')) { 1958 if (*(s + 1) != '\0' && 1959 (ptr = strstr(domain, s)) != NULL) { 1960 char *cbuf; 1961 1962 cbuf = strspl(name, ptr + strlen(s)); 1963 if (getaddrinfo(cbuf, NULL, &hints, &res) != 0) 1964 res = NULL; 1965 xfree(cbuf); 1966 break; 1967 } 1968 } 1969 } 1970 if (res != NULL) { 1971 if (res->ai_canonname != NULL) { 1972 strncpy(hbuf, res->ai_canonname, sizeof(hbuf)); 1973 hbuf[sizeof(hbuf) - 1] = '\0'; 1974 host = hbuf; 1975 } 1976 freeaddrinfo(res); 1977 } 1978 #else 1979 if ((hp = gethostbyname(name)) == NULL) { 1980 /* Try again eliminating the trailing domain */ 1981 if ((ptr = strchr(name, '.')) != NULL) { 1982 *ptr = '\0'; 1983 if ((hp = gethostbyname(name)) != NULL) 1984 host = hp->h_name; 1985 *ptr = '.'; 1986 } 1987 } 1988 else 1989 host = hp->h_name; 1990 #endif 1991 } 1992 } 1993 } 1994 } 1995 #endif 1996 1997 if (host) { 1998 size_t left; 1999 2000 left = strlen(host); 2001 while (left != 0) { 2002 ssize_t res; 2003 2004 res = xwrite(dest_fd, host, left); 2005 if (res < 0) 2006 _exit(1); 2007 host += res; 2008 left -= res; 2009 } 2010 } 2011 _exit(0); 2012 } 2013 2014 /* 2015 * From: <lesv@ppvku.ericsson.se> (Lennart Svensson) 2016 */ 2017 void 2018 remotehost(void) 2019 { 2020 struct sigaction sa; 2021 struct strbuf hostname = strbuf_INIT; 2022 int fds[2], wait_options, status; 2023 pid_t pid, wait_res; 2024 2025 sa.sa_handler = SIG_DFL; /* Make sure a zombie is created */ 2026 sigemptyset(&sa.sa_mask); 2027 sa.sa_flags = 0; 2028 sigaction(SIGCHLD, &sa, NULL); 2029 mypipe(fds); 2030 pid = fork(); 2031 if (pid == 0) { 2032 sigset_t set; 2033 xclose(fds[0]); 2034 /* Don't get stuck if the resolver does not work! */ 2035 signal(SIGALRM, palarm); 2036 sigemptyset(&set); 2037 sigaddset(&set, SIGALRM); 2038 (void)sigprocmask(SIG_UNBLOCK, &set, NULL); 2039 (void)alarm(2); 2040 getremotehost(fds[1]); 2041 /*NOTREACHED*/ 2042 } 2043 xclose(fds[1]); 2044 for (;;) { 2045 char buf[BUFSIZE]; 2046 ssize_t res; 2047 2048 res = xread(fds[0], buf, sizeof(buf)); 2049 if (res == -1) { 2050 hostname.len = 0; 2051 wait_options = WNOHANG; 2052 goto done; 2053 } 2054 if (res == 0) 2055 break; 2056 strbuf_appendn(&hostname, buf, res); 2057 } 2058 wait_options = 0; 2059 done: 2060 cleanup_push(&hostname, strbuf_cleanup); 2061 xclose(fds[0]); 2062 while ((wait_res = waitpid(pid, &status, wait_options)) == -1 2063 && errno == EINTR) 2064 handle_pending_signals(); 2065 if (hostname.len > 0 && wait_res == pid && WIFEXITED(status) 2066 && WEXITSTATUS(status) == 0) { 2067 strbuf_terminate(&hostname); 2068 tsetenv(STRREMOTEHOST, str2short(hostname.s)); 2069 } 2070 cleanup_until(&hostname); 2071 2072 #ifdef YPBUGS 2073 /* From: casper@fwi.uva.nl (Casper H.S. Dik), for Solaris 2.3 */ 2074 fix_yp_bugs(); 2075 #endif /* YPBUGS */ 2076 2077 } 2078 #endif /* REMOTEHOST */ 2079 2080 #ifndef WINNT_NATIVE 2081 /* 2082 * indicate if a terminal type is defined in terminfo/termcap 2083 * (by default the current term type). This allows ppl to look 2084 * for a working term type automatically in their login scripts 2085 * when using a terminal known as different things on different 2086 * platforms 2087 */ 2088 void 2089 dotermname(Char **v, struct command *c) 2090 { 2091 char *termtype; 2092 /* 2093 * Maximum size of a termcap record. We make it twice as large. 2094 */ 2095 char termcap_buffer[2048]; 2096 2097 USE(c); 2098 /* try to find which entry we should be looking for */ 2099 termtype = (v[1] == NULL ? getenv("TERM") : short2str(v[1])); 2100 if (termtype == NULL) { 2101 /* no luck - the user didn't provide one and none is 2102 * specified in the environment 2103 */ 2104 setcopy(STRstatus, STR1, VAR_READWRITE); 2105 return; 2106 } 2107 2108 /* 2109 * we use the termcap function - if we are using terminfo we 2110 * will end up with it's compatibility function 2111 * terminfo/termcap will be initialized with the new 2112 * type but we don't care because tcsh has cached all the things 2113 * it needs. 2114 */ 2115 if (tgetent(termcap_buffer, termtype) == 1) { 2116 xprintf("%s\n", termtype); 2117 setcopy(STRstatus, STR0, VAR_READWRITE); 2118 } else 2119 setcopy(STRstatus, STR1, VAR_READWRITE); 2120 } 2121 #endif /* WINNT_NATIVE */ 2122