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