1 /* $Header: /src/pub/tcsh/tc.func.c,v 3.107 2003/05/16 18:10:29 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("$Id: tc.func.c,v 3.107 2003/05/16 18:10:29 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 #endif /* WINNT_NATIVE */ 44 45 #ifdef AFS 46 #define PASSMAX 16 47 #include <afs/stds.h> 48 #include <afs/kautils.h> 49 long ka_UserAuthenticateGeneral(); 50 #else 51 #ifndef PASSMAX 52 #define PASSMAX 8 53 #endif 54 #endif /* AFS */ 55 56 #ifdef TESLA 57 extern int do_logout; 58 #endif /* TESLA */ 59 extern time_t t_period; 60 extern int just_signaled; 61 static bool precmd_active = 0; 62 static bool jobcmd_active = 0; /* GrP */ 63 static bool postcmd_active = 0; 64 static bool periodic_active = 0; 65 static bool cwdcmd_active = 0; /* PWP: for cwd_cmd */ 66 static bool beepcmd_active = 0; 67 static signalfun_t alm_fun = NULL; 68 69 static void auto_logout __P((int)); 70 static char *xgetpass __P((char *)); 71 static void auto_lock __P((int)); 72 #ifdef BSDJOBS 73 static void insert __P((struct wordent *, bool)); 74 static void insert_we __P((struct wordent *, struct wordent *)); 75 static int inlist __P((Char *, Char *)); 76 #endif /* BSDJOBS */ 77 struct tildecache; 78 static int tildecompare __P((struct tildecache *, struct tildecache *)); 79 static Char *gethomedir __P((Char *)); 80 #ifdef REMOTEHOST 81 static sigret_t palarm __P((int)); 82 static void getremotehost __P((void)); 83 #endif /* REMOTEHOST */ 84 85 /* 86 * Tops-C shell 87 */ 88 89 /* 90 * expand_lex: Take the given lex and put an expanded version of it in 91 * the string buf. First guy in lex list is ignored; last guy is ^J 92 * which we ignore. Only take lex'es from position 'from' to position 93 * 'to' inclusive 94 * 95 * Note: csh sometimes sets bit 8 in characters which causes all kinds 96 * of problems if we don't mask it here. Note: excl's in lexes have been 97 * un-back-slashed and must be re-back-slashed 98 * 99 * (PWP: NOTE: this returns a pointer to the END of the string expanded 100 * (in other words, where the NUL is).) 101 */ 102 /* PWP: this is a combination of the old sprlex() and the expand_lex from 103 the magic-space stuff */ 104 105 Char * 106 expand_lex(buf, bufsiz, sp0, from, to) 107 Char *buf; 108 size_t bufsiz; 109 struct wordent *sp0; 110 int from, to; 111 { 112 register struct wordent *sp; 113 register Char *s, *d, *e; 114 register Char prev_c; 115 register int i; 116 117 /* 118 * Make sure we have enough space to expand into. E.g. we may have 119 * "a|b" turn to "a | b" (from 3 to 5 characters) which is the worst 120 * case scenario (even "a>&! b" turns into "a > & ! b", i.e. 6 to 9 121 * characters -- am I missing any other cases?). 122 */ 123 bufsiz = bufsiz / 2; 124 125 buf[0] = '\0'; 126 prev_c = '\0'; 127 d = buf; 128 e = &buf[bufsiz]; /* for bounds checking */ 129 130 if (!sp0) 131 return (buf); /* null lex */ 132 if ((sp = sp0->next) == sp0) 133 return (buf); /* nada */ 134 if (sp == (sp0 = sp0->prev)) 135 return (buf); /* nada */ 136 137 for (i = 0; i < NCARGS; i++) { 138 if ((i >= from) && (i <= to)) { /* if in range */ 139 for (s = sp->word; *s && d < e; s++) { 140 /* 141 * bugfix by Michael Bloom: anything but the current history 142 * character {(PWP) and backslash} seem to be dealt with 143 * elsewhere. 144 */ 145 if ((*s & QUOTE) 146 && (((*s & TRIM) == HIST) || 147 (((*s & TRIM) == '\'') && (prev_c != '\\')) || 148 (((*s & TRIM) == '\"') && (prev_c != '\\')) || 149 (((*s & TRIM) == '\\') && (prev_c != '\\')))) { 150 *d++ = '\\'; 151 } 152 if (d < e) 153 *d++ = (*s & TRIM); 154 prev_c = *s; 155 } 156 if (d < e) 157 *d++ = ' '; 158 } 159 sp = sp->next; 160 if (sp == sp0) 161 break; 162 } 163 if (d > buf) 164 d--; /* get rid of trailing space */ 165 166 return (d); 167 } 168 169 Char * 170 sprlex(buf, bufsiz, sp0) 171 Char *buf; 172 size_t bufsiz; 173 struct wordent *sp0; 174 { 175 Char *cp; 176 177 cp = expand_lex(buf, bufsiz, sp0, 0, NCARGS); 178 *cp = '\0'; 179 return (buf); 180 } 181 182 183 Char * 184 Itoa(n, s, min_digits, attributes) 185 int n; 186 Char *s; 187 int min_digits, attributes; 188 { 189 /* 190 * The array size here is derived from 191 * log8(UINT_MAX) 192 * which is guaranteed to be enough for a decimal 193 * representation. We add 1 because integer divide 194 * rounds down. 195 */ 196 #ifndef CHAR_BIT 197 # define CHAR_BIT 8 198 #endif 199 Char buf[CHAR_BIT * sizeof(int) / 3 + 1]; 200 Char *p; 201 unsigned int un; /* handle most negative # too */ 202 int pad = (min_digits != 0); 203 204 if (sizeof(buf) - 1 < min_digits) 205 min_digits = sizeof(buf) - 1; 206 207 un = n; 208 if (n < 0) { 209 un = -n; 210 *s++ = '-'; 211 } 212 213 p = buf; 214 do { 215 *p++ = un % 10 + '0'; 216 un /= 10; 217 } while ((pad && --min_digits > 0) || un != 0); 218 219 while (p > buf) 220 *s++ = *--p | attributes; 221 222 *s = '\0'; 223 return s; 224 } 225 226 227 /*ARGSUSED*/ 228 void 229 dolist(v, c) 230 register Char **v; 231 struct command *c; 232 { 233 int i, k; 234 struct stat st; 235 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 236 extern bool dspmbyte_ls; 237 #endif 238 #ifdef COLOR_LS_F 239 extern bool color_context_ls; 240 #endif /* COLOR_LS_F */ 241 242 USE(c); 243 if (*++v == NULL) { 244 (void) t_search(STRNULL, NULL, LIST, 0, TW_ZERO, 0, STRNULL, 0); 245 return; 246 } 247 gflag = 0; 248 tglob(v); 249 if (gflag) { 250 v = globall(v); 251 if (v == 0) 252 stderror(ERR_NAME | ERR_NOMATCH); 253 } 254 else 255 v = gargv = saveblk(v); 256 trim(v); 257 for (k = 0; v[k] != NULL && v[k][0] != '-'; k++) 258 continue; 259 if (v[k]) { 260 /* 261 * We cannot process a flag therefore we let ls do it right. 262 */ 263 static Char STRls[] = {'l', 's', '\0'}; 264 static Char STRmCF[] = {'-', 'C', 'F', '\0', '\0' }; 265 Char *lspath; 266 struct command *t; 267 struct wordent cmd, *nextword, *lastword; 268 Char *cp; 269 struct varent *vp; 270 271 #ifdef BSDSIGS 272 sigmask_t omask = 0; 273 274 if (setintr) 275 omask = sigblock(sigmask(SIGINT)) & ~sigmask(SIGINT); 276 #else /* !BSDSIGS */ 277 (void) sighold(SIGINT); 278 #endif /* BSDSIGS */ 279 if (seterr) { 280 xfree((ptr_t) seterr); 281 seterr = NULL; 282 } 283 284 lspath = STRls; 285 STRmCF[1] = 'C'; 286 STRmCF[3] = '\0'; 287 /* Look at listflags, to add -A to the flags, to get a path 288 of ls if necessary */ 289 if ((vp = adrof(STRlistflags)) != NULL && vp->vec != NULL && 290 vp->vec[0] != STRNULL) { 291 if (vp->vec[1] != NULL && vp->vec[1][0] != '\0') 292 lspath = vp->vec[1]; 293 for (cp = vp->vec[0]; *cp; cp++) 294 switch (*cp) { 295 case 'x': 296 STRmCF[1] = 'x'; 297 break; 298 case 'a': 299 STRmCF[3] = 'a'; 300 break; 301 case 'A': 302 STRmCF[3] = 'A'; 303 break; 304 default: 305 break; 306 } 307 } 308 309 cmd.word = STRNULL; 310 lastword = &cmd; 311 nextword = (struct wordent *) xcalloc(1, sizeof cmd); 312 nextword->word = Strsave(lspath); 313 lastword->next = nextword; 314 nextword->prev = lastword; 315 lastword = nextword; 316 nextword = (struct wordent *) xcalloc(1, sizeof cmd); 317 nextword->word = Strsave(STRmCF); 318 lastword->next = nextword; 319 nextword->prev = lastword; 320 #if defined(KANJI) && defined(SHORT_STRINGS) && defined(DSPMBYTE) 321 if (dspmbyte_ls) { 322 lastword = nextword; 323 nextword = (struct wordent *) xcalloc(1, sizeof cmd); 324 nextword->word = Strsave(STRmmliteral); 325 lastword->next = nextword; 326 nextword->prev = lastword; 327 } 328 #endif 329 #ifdef COLOR_LS_F 330 if (color_context_ls) { 331 lastword = nextword; 332 nextword = (struct wordent *) xcalloc(1, sizeof cmd); 333 nextword->word = Strsave(STRmmcolormauto); 334 lastword->next = nextword; 335 nextword->prev = lastword; 336 } 337 #endif /* COLOR_LS_F */ 338 lastword = nextword; 339 for (cp = *v; cp; cp = *++v) { 340 nextword = (struct wordent *) xcalloc(1, sizeof cmd); 341 nextword->word = quote(Strsave(cp)); 342 lastword->next = nextword; 343 nextword->prev = lastword; 344 lastword = nextword; 345 } 346 lastword->next = &cmd; 347 cmd.prev = lastword; 348 349 /* build a syntax tree for the command. */ 350 t = syntax(cmd.next, &cmd, 0); 351 if (seterr) 352 stderror(ERR_OLD); 353 /* expand aliases like process() does */ 354 /* alias(&cmd); */ 355 /* execute the parse tree. */ 356 execute(t, tpgrp > 0 ? tpgrp : -1, NULL, NULL, FALSE); 357 /* done. free the lex list and parse tree. */ 358 freelex(&cmd), freesyn(t); 359 if (setintr) 360 #ifdef BSDSIGS 361 (void) sigsetmask(omask); 362 #else /* !BSDSIGS */ 363 (void) sigrelse(SIGINT); 364 #endif /* BSDSIGS */ 365 } 366 else { 367 Char *dp, *tmp, buf[MAXPATHLEN]; 368 369 for (k = 0, i = 0; v[k] != NULL; k++) { 370 tmp = dnormalize(v[k], symlinks == SYM_IGNORE); 371 dp = &tmp[Strlen(tmp) - 1]; 372 if (*dp == '/' && dp != tmp) 373 #ifdef apollo 374 if (dp != &tmp[1]) 375 #endif /* apollo */ 376 *dp = '\0'; 377 if (stat(short2str(tmp), &st) == -1) { 378 if (k != i) { 379 if (i != 0) 380 xputchar('\n'); 381 print_by_column(STRNULL, &v[i], k - i, FALSE); 382 } 383 xprintf("%S: %s.\n", tmp, strerror(errno)); 384 i = k + 1; 385 } 386 else if (S_ISDIR(st.st_mode)) { 387 Char *cp; 388 389 if (k != i) { 390 if (i != 0) 391 xputchar('\n'); 392 print_by_column(STRNULL, &v[i], k - i, FALSE); 393 } 394 if (k != 0 && v[1] != NULL) 395 xputchar('\n'); 396 xprintf("%S:\n", tmp); 397 for (cp = tmp, dp = buf; *cp; *dp++ = (*cp++ | QUOTE)) 398 continue; 399 if ( 400 #ifdef WINNT_NATIVE 401 (dp[-1] != (Char) (':' | QUOTE)) && 402 #endif /* WINNT_NATIVE */ 403 (dp[-1] != (Char) ('/' | QUOTE))) 404 *dp++ = '/'; 405 else 406 dp[-1] &= TRIM; 407 *dp = '\0'; 408 (void) t_search(buf, NULL, LIST, 0, TW_ZERO, 0, STRNULL, 0); 409 i = k + 1; 410 } 411 xfree((ptr_t) tmp); 412 } 413 if (k != i) { 414 if (i != 0) 415 xputchar('\n'); 416 print_by_column(STRNULL, &v[i], k - i, FALSE); 417 } 418 } 419 420 if (gargv) { 421 blkfree(gargv); 422 gargv = 0; 423 } 424 } 425 426 static char *defaulttell = "ALL"; 427 extern bool GotTermCaps; 428 429 /*ARGSUSED*/ 430 void 431 dotelltc(v, c) 432 register Char **v; 433 struct command *c; 434 { 435 USE(c); 436 if (!GotTermCaps) 437 GetTermCaps(); 438 439 /* 440 * Avoid a compiler bug on hpux 9.05 441 * Writing the following as func(a ? b : c) breaks 442 */ 443 if (v[1]) 444 TellTC(short2str(v[1])); 445 else 446 TellTC(defaulttell); 447 } 448 449 /*ARGSUSED*/ 450 void 451 doechotc(v, c) 452 register Char **v; 453 struct command *c; 454 { 455 if (!GotTermCaps) 456 GetTermCaps(); 457 EchoTC(++v); 458 } 459 460 /*ARGSUSED*/ 461 void 462 dosettc(v, c) 463 Char **v; 464 struct command *c; 465 { 466 char tv[2][BUFSIZE]; 467 468 if (!GotTermCaps) 469 GetTermCaps(); 470 471 (void) strcpy(tv[0], short2str(v[1])); 472 (void) strcpy(tv[1], short2str(v[2])); 473 SetTC(tv[0], tv[1]); 474 } 475 476 /* The dowhich() is by: 477 * Andreas Luik <luik@isaak.isa.de> 478 * I S A GmbH - Informationssysteme fuer computerintegrierte Automatisierung 479 * Azenberstr. 35 480 * D-7000 Stuttgart 1 481 * West-Germany 482 * Thanks!! 483 */ 484 int 485 cmd_expand(cmd, str) 486 Char *cmd; 487 Char *str; 488 { 489 struct wordent lexp[3]; 490 struct varent *vp; 491 int rv = TRUE; 492 493 lexp[0].next = &lexp[1]; 494 lexp[1].next = &lexp[2]; 495 lexp[2].next = &lexp[0]; 496 497 lexp[0].prev = &lexp[2]; 498 lexp[1].prev = &lexp[0]; 499 lexp[2].prev = &lexp[1]; 500 501 lexp[0].word = STRNULL; 502 lexp[2].word = STRret; 503 504 if ((vp = adrof1(cmd, &aliases)) != NULL && vp->vec != NULL) { 505 if (str == NULL) { 506 xprintf(CGETS(22, 1, "%S: \t aliased to "), cmd); 507 blkpr(vp->vec); 508 xputchar('\n'); 509 } 510 else 511 blkexpand(vp->vec, str); 512 } 513 else { 514 lexp[1].word = cmd; 515 rv = tellmewhat(lexp, str); 516 } 517 return rv; 518 } 519 520 521 /*ARGSUSED*/ 522 void 523 dowhich(v, c) 524 register Char **v; 525 struct command *c; 526 { 527 int rv = TRUE; 528 USE(c); 529 530 #ifdef notdef 531 /* 532 * We don't want to glob dowhich args because we lose quoteing 533 * E.g. which \ls if ls is aliased will not work correctly if 534 * we glob here. 535 */ 536 gflag = 0, tglob(v); 537 if (gflag) { 538 v = globall(v); 539 if (v == 0) 540 stderror(ERR_NAME | ERR_NOMATCH); 541 } 542 else { 543 v = gargv = saveblk(v); 544 trim(v); 545 } 546 #endif 547 548 while (*++v) 549 rv &= cmd_expand(*v, NULL); 550 551 if (!rv) 552 set(STRstatus, Strsave(STR1), VAR_READWRITE); 553 554 #ifdef notdef 555 /* Again look at the comment above; since we don't glob, we don't free */ 556 if (gargv) 557 blkfree(gargv), gargv = 0; 558 #endif 559 } 560 561 /* PWP: a hack to start up your stopped editor on a single keystroke */ 562 /* jbs - fixed hack so it worked :-) 3/28/89 */ 563 564 struct process * 565 find_stop_ed() 566 { 567 register struct process *pp, *retp; 568 register char *ep, *vp, *cp, *p; 569 int epl, vpl, pstatus; 570 571 if ((ep = getenv("EDITOR")) != NULL) { /* if we have a value */ 572 if ((p = strrchr(ep, '/')) != NULL) /* if it has a path */ 573 ep = p + 1; /* then we want only the last part */ 574 } 575 else 576 ep = "ed"; 577 578 if ((vp = getenv("VISUAL")) != NULL) { /* if we have a value */ 579 if ((p = strrchr(vp, '/')) != NULL) /* and it has a path */ 580 vp = p + 1; /* then we want only the last part */ 581 } 582 else 583 vp = "vi"; 584 585 for (vpl = 0; vp[vpl] && !Isspace(vp[vpl]); vpl++) 586 continue; 587 for (epl = 0; ep[epl] && !Isspace(ep[epl]); epl++) 588 continue; 589 590 if (pcurrent == NULL) /* see if we have any jobs */ 591 return NULL; /* nope */ 592 593 retp = NULL; 594 for (pp = proclist.p_next; pp; pp = pp->p_next) 595 if (pp->p_procid == pp->p_jobid) { 596 597 /* 598 * Only foreground an edit session if it is suspended. Some GUI 599 * editors have may be happily running in a separate window, no 600 * point in foregrounding these if they're already running - webb 601 */ 602 pstatus = (int) (pp->p_flags & PALLSTATES); 603 if (pstatus != PINTERRUPTED && pstatus != PSTOPPED && 604 pstatus != PSIGNALED) 605 continue; 606 607 p = short2str(pp->p_command); 608 /* get the first word */ 609 for (cp = p; *cp && !isspace((unsigned char) *cp); cp++) 610 continue; 611 *cp = '\0'; 612 613 if ((cp = strrchr(p, '/')) != NULL) /* and it has a path */ 614 cp = cp + 1; /* then we want only the last part */ 615 else 616 cp = p; /* else we get all of it */ 617 618 /* if we find either in the current name, fg it */ 619 if (strncmp(ep, cp, (size_t) epl) == 0 || 620 strncmp(vp, cp, (size_t) vpl) == 0) { 621 622 /* 623 * If there is a choice, then choose the current process if 624 * available, or the previous process otherwise, or else 625 * anything will do - Robert Webb (robertw@mulga.cs.mu.oz.au). 626 */ 627 if (pp == pcurrent) 628 return pp; 629 else if (retp == NULL || pp == pprevious) 630 retp = pp; 631 } 632 } 633 634 return retp; /* Will be NULL if we didn't find a job */ 635 } 636 637 void 638 fg_proc_entry(pp) 639 register struct process *pp; 640 { 641 #ifdef BSDSIGS 642 sigmask_t omask; 643 #endif 644 jmp_buf_t osetexit; 645 bool ohaderr; 646 Char oGettingInput; 647 648 getexit(osetexit); 649 650 #ifdef BSDSIGS 651 omask = sigblock(sigmask(SIGINT)); 652 #else 653 (void) sighold(SIGINT); 654 #endif 655 oGettingInput = GettingInput; 656 GettingInput = 0; 657 658 ohaderr = haderr; /* we need to ignore setting of haderr due to 659 * process getting stopped by a signal */ 660 if (setexit() == 0) { /* come back here after pjwait */ 661 pendjob(); 662 (void) alarm(0); /* No autologout */ 663 if (!pstart(pp, 1)) { 664 pp->p_procid = 0; 665 stderror(ERR_BADJOB, pp->p_command, strerror(errno)); 666 } 667 pjwait(pp); 668 } 669 setalarm(1); /* Autologout back on */ 670 resexit(osetexit); 671 haderr = ohaderr; 672 GettingInput = oGettingInput; 673 674 #ifdef BSDSIGS 675 (void) sigsetmask(omask); 676 #else /* !BSDSIGS */ 677 (void) sigrelse(SIGINT); 678 #endif /* BSDSIGS */ 679 680 } 681 682 static char * 683 xgetpass(prm) 684 char *prm; 685 { 686 static char pass[PASSMAX + 1]; 687 int fd, i; 688 signalfun_t sigint; 689 690 sigint = (signalfun_t) sigset(SIGINT, SIG_IGN); 691 (void) Rawmode(); /* Make sure, cause we want echo off */ 692 if ((fd = open("/dev/tty", O_RDWR|O_LARGEFILE)) == -1) 693 fd = SHIN; 694 695 xprintf("%s", prm); flush(); 696 for (i = 0;;) { 697 if (read(fd, &pass[i], 1) < 1 || pass[i] == '\n') 698 break; 699 if (i < PASSMAX) 700 i++; 701 } 702 703 pass[i] = '\0'; 704 705 if (fd != SHIN) 706 (void) close(fd); 707 (void) sigset(SIGINT, sigint); 708 709 return(pass); 710 } 711 712 /* 713 * Ask the user for his login password to continue working 714 * On systems that have a shadow password, this will only 715 * work for root, but what can we do? 716 * 717 * If we fail to get the password, then we log the user out 718 * immediately 719 */ 720 /*ARGSUSED*/ 721 static void 722 auto_lock(n) 723 int n; 724 { 725 #ifndef NO_CRYPT 726 727 int i; 728 char *srpp = NULL; 729 struct passwd *pw; 730 #ifdef POSIX 731 extern char *crypt __P((const char *, const char *)); 732 #else 733 extern char *crypt __P(()); 734 #endif 735 736 #undef XCRYPT 737 738 #if defined(PW_AUTH) && !defined(XCRYPT) 739 740 struct authorization *apw; 741 extern char *crypt16 __P((const char *, const char *)); 742 743 # define XCRYPT(a, b) crypt16(a, b) 744 745 if ((pw = getpwuid(euid)) != NULL && /* effective user passwd */ 746 (apw = getauthuid(euid)) != NULL) /* enhanced ultrix passwd */ 747 srpp = apw->a_password; 748 749 #endif /* PW_AUTH && !XCRYPT */ 750 751 #if defined(PW_SHADOW) && !defined(XCRYPT) 752 753 struct spwd *spw; 754 755 # define XCRYPT(a, b) crypt(a, b) 756 757 if ((pw = getpwuid(euid)) != NULL && /* effective user passwd */ 758 (spw = getspnam(pw->pw_name)) != NULL) /* shadowed passwd */ 759 srpp = spw->sp_pwdp; 760 761 #endif /* PW_SHADOW && !XCRYPT */ 762 763 #ifndef XCRYPT 764 765 #define XCRYPT(a, b) crypt(a, b) 766 767 #if !defined(__MVS__) 768 if ((pw = getpwuid(euid)) != NULL) /* effective user passwd */ 769 srpp = pw->pw_passwd; 770 #endif /* !MVS */ 771 772 #endif /* !XCRYPT */ 773 774 if (srpp == NULL) { 775 auto_logout(0); 776 /*NOTREACHED*/ 777 return; 778 } 779 780 setalarm(0); /* Not for locking any more */ 781 #ifdef BSDSIGS 782 (void) sigsetmask(sigblock(0) & ~(sigmask(SIGALRM))); 783 #else /* !BSDSIGS */ 784 (void) sigrelse(SIGALRM); 785 #endif /* BSDSIGS */ 786 xputchar('\n'); 787 for (i = 0; i < 5; i++) { 788 const char *crpp; 789 char *pp; 790 #ifdef AFS 791 char *afsname; 792 Char *safs; 793 794 if ((safs = varval(STRafsuser)) != STRNULL) 795 afsname = short2str(safs); 796 else 797 if ((afsname = getenv("AFSUSER")) == NULL) 798 afsname = pw->pw_name; 799 #endif 800 pp = xgetpass("Password:"); 801 802 crpp = XCRYPT(pp, srpp); 803 if ((strcmp(crpp, srpp) == 0) 804 #ifdef AFS 805 || (ka_UserAuthenticateGeneral(KA_USERAUTH_VERSION, 806 afsname, /* name */ 807 NULL, /* instance */ 808 NULL, /* realm */ 809 pp, /* password */ 810 0, /* lifetime */ 811 0, 0, /* spare */ 812 NULL) /* reason */ 813 == 0) 814 #endif /* AFS */ 815 ) { 816 (void) memset(pp, 0, PASSMAX); 817 if (GettingInput && !just_signaled) { 818 (void) Rawmode(); 819 ClearLines(); 820 ClearDisp(); 821 Refresh(); 822 } 823 just_signaled = 0; 824 return; 825 } 826 xprintf(CGETS(22, 2, "\nIncorrect passwd for %s\n"), pw->pw_name); 827 } 828 #endif /* NO_CRYPT */ 829 auto_logout(0); 830 USE(n); 831 } 832 833 834 static void 835 auto_logout(n) 836 int n; 837 { 838 USE(n); 839 xprintf("auto-logout\n"); 840 /* Don't leave the tty in raw mode */ 841 if (editing) 842 (void) Cookedmode(); 843 (void) close(SHIN); 844 set(STRlogout, Strsave(STRautomatic), VAR_READWRITE); 845 child = 1; 846 #ifdef TESLA 847 do_logout = 1; 848 #endif /* TESLA */ 849 GettingInput = FALSE; /* make flush() work to write hist files. Huber*/ 850 goodbye(NULL, NULL); 851 } 852 853 sigret_t 854 /*ARGSUSED*/ 855 alrmcatch(snum) 856 int snum; 857 { 858 #ifdef UNRELSIGS 859 if (snum) 860 (void) sigset(SIGALRM, alrmcatch); 861 #endif /* UNRELSIGS */ 862 863 (*alm_fun)(0); 864 865 setalarm(1); 866 #ifndef SIGVOID 867 return (snum); 868 #endif /* !SIGVOID */ 869 } 870 871 /* 872 * Karl Kleinpaste, 21oct1983. 873 * Added precmd(), which checks for the alias 874 * precmd in aliases. If it's there, the alias 875 * is executed as a command. This is done 876 * after mailchk() and just before print- 877 * ing the prompt. Useful for things like printing 878 * one's current directory just before each command. 879 */ 880 void 881 precmd() 882 { 883 #ifdef BSDSIGS 884 sigmask_t omask; 885 886 omask = sigblock(sigmask(SIGINT)); 887 #else /* !BSDSIGS */ 888 (void) sighold(SIGINT); 889 #endif /* BSDSIGS */ 890 if (precmd_active) { /* an error must have been caught */ 891 aliasrun(2, STRunalias, STRprecmd); 892 xprintf(CGETS(22, 3, "Faulty alias 'precmd' removed.\n")); 893 goto leave; 894 } 895 precmd_active = 1; 896 if (!whyles && adrof1(STRprecmd, &aliases)) 897 aliasrun(1, STRprecmd, NULL); 898 leave: 899 precmd_active = 0; 900 #ifdef BSDSIGS 901 (void) sigsetmask(omask); 902 #else /* !BSDSIGS */ 903 (void) sigrelse(SIGINT); 904 #endif /* BSDSIGS */ 905 } 906 907 void 908 postcmd() 909 { 910 #ifdef BSDSIGS 911 sigmask_t omask; 912 913 omask = sigblock(sigmask(SIGINT)); 914 #else /* !BSDSIGS */ 915 (void) sighold(SIGINT); 916 #endif /* BSDSIGS */ 917 if (postcmd_active) { /* an error must have been caught */ 918 aliasrun(2, STRunalias, STRpostcmd); 919 xprintf(CGETS(22, 3, "Faulty alias 'postcmd' removed.\n")); 920 goto leave; 921 } 922 postcmd_active = 1; 923 if (!whyles && adrof1(STRpostcmd, &aliases)) 924 aliasrun(1, STRpostcmd, NULL); 925 leave: 926 postcmd_active = 0; 927 #ifdef BSDSIGS 928 (void) sigsetmask(omask); 929 #else /* !BSDSIGS */ 930 (void) sigrelse(SIGINT); 931 #endif /* BSDSIGS */ 932 } 933 934 /* 935 * Paul Placeway 11/24/87 Added cwd_cmd by hacking precmd() into 936 * submission... Run every time $cwd is set (after it is set). Useful 937 * for putting your machine and cwd (or anything else) in an xterm title 938 * space. 939 */ 940 void 941 cwd_cmd() 942 { 943 #ifdef BSDSIGS 944 sigmask_t omask; 945 946 omask = sigblock(sigmask(SIGINT)); 947 #else /* !BSDSIGS */ 948 (void) sighold(SIGINT); 949 #endif /* BSDSIGS */ 950 if (cwdcmd_active) { /* an error must have been caught */ 951 aliasrun(2, STRunalias, STRcwdcmd); 952 xprintf(CGETS(22, 4, "Faulty alias 'cwdcmd' removed.\n")); 953 goto leave; 954 } 955 cwdcmd_active = 1; 956 if (!whyles && adrof1(STRcwdcmd, &aliases)) 957 aliasrun(1, STRcwdcmd, NULL); 958 leave: 959 cwdcmd_active = 0; 960 #ifdef BSDSIGS 961 (void) sigsetmask(omask); 962 #else /* !BSDSIGS */ 963 (void) sigrelse(SIGINT); 964 #endif /* BSDSIGS */ 965 } 966 967 /* 968 * Joachim Hoenig 07/16/91 Added beep_cmd, run every time tcsh wishes 969 * to beep the terminal bell. Useful for playing nice sounds instead. 970 */ 971 void 972 beep_cmd() 973 { 974 #ifdef BSDSIGS 975 sigmask_t omask; 976 977 omask = sigblock(sigmask(SIGINT)); 978 #else /* !BSDSIGS */ 979 (void) sighold(SIGINT); 980 #endif /* BSDSIGS */ 981 if (beepcmd_active) { /* an error must have been caught */ 982 aliasrun(2, STRunalias, STRbeepcmd); 983 xprintf(CGETS(22, 5, "Faulty alias 'beepcmd' removed.\n")); 984 } 985 else { 986 beepcmd_active = 1; 987 if (!whyles && adrof1(STRbeepcmd, &aliases)) 988 aliasrun(1, STRbeepcmd, NULL); 989 } 990 beepcmd_active = 0; 991 #ifdef BSDSIGS 992 (void) sigsetmask(omask); 993 #else /* !BSDSIGS */ 994 (void) sigrelse(SIGINT); 995 #endif /* BSDSIGS */ 996 } 997 998 999 /* 1000 * Karl Kleinpaste, 18 Jan 1984. 1001 * Added period_cmd(), which executes the alias "periodic" every 1002 * $tperiod minutes. Useful for occasional checking of msgs and such. 1003 */ 1004 void 1005 period_cmd() 1006 { 1007 register Char *vp; 1008 time_t t, interval; 1009 #ifdef BSDSIGS 1010 sigmask_t omask; 1011 1012 omask = sigblock(sigmask(SIGINT)); 1013 #else /* !BSDSIGS */ 1014 (void) sighold(SIGINT); 1015 #endif /* BSDSIGS */ 1016 if (periodic_active) { /* an error must have been caught */ 1017 aliasrun(2, STRunalias, STRperiodic); 1018 xprintf(CGETS(22, 6, "Faulty alias 'periodic' removed.\n")); 1019 goto leave; 1020 } 1021 periodic_active = 1; 1022 if (!whyles && adrof1(STRperiodic, &aliases)) { 1023 vp = varval(STRtperiod); 1024 if (vp == STRNULL) { 1025 aliasrun(1, STRperiodic, NULL); 1026 goto leave; 1027 } 1028 interval = getn(vp); 1029 (void) time(&t); 1030 if (t - t_period >= interval * 60) { 1031 t_period = t; 1032 aliasrun(1, STRperiodic, NULL); 1033 } 1034 } 1035 leave: 1036 periodic_active = 0; 1037 #ifdef BSDSIGS 1038 (void) sigsetmask(omask); 1039 #else /* !BSDSIGS */ 1040 (void) sigrelse(SIGINT); 1041 #endif /* BSDSIGS */ 1042 } 1043 1044 1045 /* 1046 * GrP Greg Parker May 2001 1047 * Added job_cmd(), which is run every time a job is started or 1048 * foregrounded. The command is passed a single argument, the string 1049 * used to start the job originally. With precmd, useful for setting 1050 * xterm titles. 1051 * Cloned from cwd_cmd(). 1052 */ 1053 void 1054 job_cmd(args) 1055 Char *args; 1056 { 1057 #ifdef BSDSIGS 1058 sigmask_t omask; 1059 1060 omask = sigblock(sigmask(SIGINT)); 1061 #else /* !BSDSIGS */ 1062 (void) sighold(SIGINT); 1063 #endif /* BSDSIGS */ 1064 if (jobcmd_active) { /* an error must have been caught */ 1065 aliasrun(2, STRunalias, STRjobcmd); 1066 xprintf(CGETS(22, 14, "Faulty alias 'jobcmd' removed.\n")); 1067 goto leave; 1068 } 1069 jobcmd_active = 1; 1070 if (!whyles && adrof1(STRjobcmd, &aliases)) { 1071 struct process *pp = pcurrjob; /* put things back after the hook */ 1072 aliasrun(2, STRjobcmd, args); 1073 pcurrjob = pp; 1074 } 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, TRUE); 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 && vp->vec != 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 #if 0 1579 /* Don't return if root */ 1580 if (pp->pw_dir[0] == '/' && pp->pw_dir[1] == '\0') 1581 return NULL; 1582 else 1583 #endif 1584 return Strsave(str2short(pp->pw_dir)); 1585 } 1586 #ifdef HESIOD 1587 res = hes_resolve(short2str(us), "filsys"); 1588 rp = NULL; 1589 if (res != NULL) { 1590 if ((*res) != NULL) { 1591 /* 1592 * Look at the first token to determine how to interpret 1593 * the rest of it. 1594 * Yes, strtok is evil (it's not thread-safe), but it's also 1595 * easy to use. 1596 */ 1597 cp = strtok(*res, " "); 1598 if (strcmp(cp, "AFS") == 0) { 1599 /* next token is AFS pathname.. */ 1600 cp = strtok(NULL, " "); 1601 if (cp != NULL) 1602 rp = Strsave(str2short(cp)); 1603 } else if (strcmp(cp, "NFS") == 0) { 1604 cp = NULL; 1605 if ((strtok(NULL, " ")) && /* skip remote pathname */ 1606 (strtok(NULL, " ")) && /* skip host */ 1607 (strtok(NULL, " ")) && /* skip mode */ 1608 (cp = strtok(NULL, " "))) { 1609 rp = Strsave(str2short(cp)); 1610 } 1611 } 1612 } 1613 for (res1 = res; *res1; res1++) 1614 free(*res1); 1615 #if 0 1616 /* Don't return if root */ 1617 if (rp != NULL && rp[0] == '/' && rp[1] == '\0') { 1618 xfree((ptr_t)rp); 1619 rp = NULL; 1620 } 1621 #endif 1622 return rp; 1623 } 1624 #endif /* HESIOD */ 1625 return NULL; 1626 } 1627 1628 Char * 1629 gettilde(us) 1630 Char *us; 1631 { 1632 struct tildecache *bp1, *bp2, *bp; 1633 Char *hd; 1634 1635 /* Ignore NIS special names */ 1636 if (*us == '+' || *us == '-') 1637 return NULL; 1638 1639 if (tcache == NULL) 1640 tcache = (struct tildecache *) xmalloc((size_t) (TILINCR * 1641 sizeof(struct tildecache))); 1642 /* 1643 * Binary search 1644 */ 1645 for (bp1 = tcache, bp2 = tcache + tlength; bp1 < bp2;) { 1646 register int i; 1647 1648 bp = bp1 + ((bp2 - bp1) >> 1); 1649 if ((i = *us - *bp->user) == 0 && (i = Strcmp(us, bp->user)) == 0) 1650 return (bp->home); 1651 if (i < 0) 1652 bp2 = bp; 1653 else 1654 bp1 = bp + 1; 1655 } 1656 /* 1657 * Not in the cache, try to get it from the passwd file 1658 */ 1659 hd = gethomedir(us); 1660 if (hd == NULL) 1661 return NULL; 1662 1663 /* 1664 * Update the cache 1665 */ 1666 tcache[tlength].user = Strsave(us); 1667 tcache[tlength].home = hd; 1668 tcache[tlength++].hlen = (int) Strlen(hd); 1669 1670 qsort((ptr_t) tcache, (size_t) tlength, sizeof(struct tildecache), 1671 (int (*) __P((const void *, const void *))) tildecompare); 1672 1673 if (tlength == tsize) { 1674 tsize += TILINCR; 1675 tcache = (struct tildecache *) xrealloc((ptr_t) tcache, 1676 (size_t) (tsize * 1677 sizeof(struct tildecache))); 1678 } 1679 return (hd); 1680 } 1681 1682 /* 1683 * Return the username if the directory path passed contains a 1684 * user's home directory in the tilde cache, otherwise return NULL 1685 * hm points to the place where the path became different. 1686 * Special case: Our own home directory. 1687 * If we are passed a null pointer, then we flush the cache. 1688 */ 1689 Char * 1690 getusername(hm) 1691 Char **hm; 1692 { 1693 Char *h, *p; 1694 int i, j; 1695 1696 if (hm == NULL) { 1697 for (i = 0; i < tlength; i++) { 1698 xfree((ptr_t) tcache[i].home); 1699 xfree((ptr_t) tcache[i].user); 1700 } 1701 xfree((ptr_t) tcache); 1702 tlength = 0; 1703 tsize = TILINCR; 1704 tcache = NULL; 1705 return NULL; 1706 } 1707 if (((h = varval(STRhome)) != STRNULL) && 1708 (Strncmp(p = *hm, h, (size_t) (j = (int) Strlen(h))) == 0) && 1709 (p[j] == '/' || p[j] == '\0')) { 1710 *hm = &p[j]; 1711 return STRNULL; 1712 } 1713 for (i = 0; i < tlength; i++) 1714 if ((Strncmp(p = *hm, tcache[i].home, (size_t) 1715 (j = tcache[i].hlen)) == 0) && (p[j] == '/' || p[j] == '\0')) { 1716 *hm = &p[j]; 1717 return tcache[i].user; 1718 } 1719 return NULL; 1720 } 1721 1722 #ifdef OBSOLETE 1723 /* 1724 * PWP: read a bunch of aliases out of a file QUICKLY. The format 1725 * is almost the same as the result of saying "alias > FILE", except 1726 * that saying "aliases > FILE" does not expand non-letters to printable 1727 * sequences. 1728 */ 1729 /*ARGSUSED*/ 1730 void 1731 doaliases(v, c) 1732 Char **v; 1733 struct command *c; 1734 { 1735 jmp_buf_t oldexit; 1736 Char **vec, *lp; 1737 int fd; 1738 Char buf[BUFSIZE], line[BUFSIZE]; 1739 char tbuf[BUFSIZE + 1], *tmp; 1740 extern bool output_raw; /* PWP: in sh.print.c */ 1741 1742 USE(c); 1743 v++; 1744 if (*v == 0) { 1745 output_raw = 1; 1746 plist(&aliases, VAR_ALL); 1747 output_raw = 0; 1748 return; 1749 } 1750 1751 gflag = 0, tglob(v); 1752 if (gflag) { 1753 v = globall(v); 1754 if (v == 0) 1755 stderror(ERR_NAME | ERR_NOMATCH); 1756 } 1757 else { 1758 v = gargv = saveblk(v); 1759 trim(v); 1760 } 1761 1762 if ((fd = open(tmp = short2str(*v), O_RDONLY|O_LARGEFILE)) < 0) 1763 stderror(ERR_NAME | ERR_SYSTEM, tmp, strerror(errno)); 1764 1765 getexit(oldexit); 1766 if (setexit() == 0) { 1767 for (;;) { 1768 Char *p = NULL; 1769 int n = 0; 1770 lp = line; 1771 for (;;) { 1772 if (n <= 0) { 1773 int i; 1774 1775 if ((n = read(fd, tbuf, BUFSIZE)) <= 0) { 1776 #ifdef convex 1777 stderror(ERR_SYSTEM, progname, strerror(errno)); 1778 #endif /* convex */ 1779 goto eof; 1780 } 1781 for (i = 0; i < n; i++) 1782 buf[i] = (Char) tbuf[i]; 1783 p = buf; 1784 } 1785 n--; 1786 if ((*lp++ = *p++) == '\n') { 1787 lp[-1] = '\0'; 1788 break; 1789 } 1790 } 1791 for (lp = line; *lp; lp++) { 1792 if (isspc(*lp)) { 1793 *lp++ = '\0'; 1794 while (isspc(*lp)) 1795 lp++; 1796 vec = (Char **) xmalloc((size_t) 1797 (2 * sizeof(Char **))); 1798 vec[0] = Strsave(lp); 1799 vec[1] = NULL; 1800 setq(strip(line), vec, &aliases, VAR_READWRITE); 1801 break; 1802 } 1803 } 1804 } 1805 } 1806 1807 eof: 1808 (void) close(fd); 1809 tw_cmd_free(); 1810 if (gargv) 1811 blkfree(gargv), gargv = 0; 1812 resexit(oldexit); 1813 } 1814 #endif /* OBSOLETE */ 1815 1816 1817 /* 1818 * set the shell-level var to 1 or apply change to it. 1819 */ 1820 void 1821 shlvl(val) 1822 int val; 1823 { 1824 char *cp; 1825 1826 if ((cp = getenv("SHLVL")) != NULL) { 1827 1828 if (loginsh) 1829 val = 1; 1830 else 1831 val += atoi(cp); 1832 1833 if (val <= 0) { 1834 if (adrof(STRshlvl) != NULL) 1835 unsetv(STRshlvl); 1836 Unsetenv(STRKSHLVL); 1837 } 1838 else { 1839 Char buff[BUFSIZE]; 1840 1841 (void) Itoa(val, buff, 0, 0); 1842 set(STRshlvl, Strsave(buff), VAR_READWRITE); 1843 tsetenv(STRKSHLVL, buff); 1844 } 1845 } 1846 else { 1847 set(STRshlvl, SAVE("1"), VAR_READWRITE); 1848 tsetenv(STRKSHLVL, str2short("1")); 1849 } 1850 } 1851 1852 1853 /* fixio(): 1854 * Try to recover from a read error 1855 */ 1856 int 1857 fixio(fd, e) 1858 int fd, e; 1859 { 1860 switch (e) { 1861 case -1: /* Make sure that the code is reachable */ 1862 1863 #ifdef EWOULDBLOCK 1864 case EWOULDBLOCK: 1865 # define FDRETRY 1866 #endif /* EWOULDBLOCK */ 1867 1868 #if defined(POSIX) && defined(EAGAIN) 1869 # if !defined(EWOULDBLOCK) || EWOULDBLOCK != EAGAIN 1870 case EAGAIN: 1871 # define FDRETRY 1872 # endif /* !EWOULDBLOCK || EWOULDBLOCK != EAGAIN */ 1873 #endif /* POSIX && EAGAIN */ 1874 1875 e = 0; 1876 #ifdef FDRETRY 1877 # ifdef F_SETFL 1878 /* 1879 * Great! we have on suns 3 flavors and 5 names... 1880 * I hope that will cover everything. 1881 * I added some more defines... many systems have different defines. 1882 * Rather than dealing with getting the right includes, we'll just 1883 * cover all the known possibilities here. -- sterling@netcom.com 1884 */ 1885 # ifndef O_NONBLOCK 1886 # define O_NONBLOCK 0 1887 # endif /* O_NONBLOCK */ 1888 # ifndef O_NDELAY 1889 # define O_NDELAY 0 1890 # endif /* O_NDELAY */ 1891 # ifndef FNBIO 1892 # define FNBIO 0 1893 # endif /* FNBIO */ 1894 # ifndef _FNBIO 1895 # define _FNBIO 0 1896 # endif /* _FNBIO */ 1897 # ifndef FNONBIO 1898 # define FNONBIO 0 1899 # endif /* FNONBIO */ 1900 # ifndef FNONBLOCK 1901 # define FNONBLOCK 0 1902 # endif /* FNONBLOCK */ 1903 # ifndef _FNONBLOCK 1904 # define _FNONBLOCK 0 1905 # endif /* _FNONBLOCK */ 1906 # ifndef FNDELAY 1907 # define FNDELAY 0 1908 # endif /* FNDELAY */ 1909 # ifndef _FNDELAY 1910 # define _FNDELAY 0 1911 # endif /* _FNDELAY */ 1912 # ifndef FNDLEAY /* Some linux versions have this typo */ 1913 # define FNDLEAY 0 1914 # endif /* FNDLEAY */ 1915 if ((e = fcntl(fd, F_GETFL, 0)) == -1) 1916 return -1; 1917 1918 e &= ~(O_NDELAY|O_NONBLOCK|FNBIO|_FNBIO|FNONBIO|FNONBLOCK|_FNONBLOCK| 1919 FNDELAY|_FNDELAY|FNDLEAY); /* whew! */ 1920 if (fcntl(fd, F_SETFL, e) == -1) 1921 return -1; 1922 else 1923 e = 1; 1924 # endif /* F_SETFL */ 1925 1926 # ifdef FIONBIO 1927 e = 0; 1928 if (ioctl(fd, FIONBIO, (ioctl_t) &e) == -1) 1929 return -1; 1930 else 1931 e = 1; 1932 # endif /* FIONBIO */ 1933 1934 #endif /* FDRETRY */ 1935 return e ? 0 : -1; 1936 1937 case EINTR: 1938 return 0; 1939 1940 default: 1941 return -1; 1942 } 1943 } 1944 1945 /* collate(): 1946 * String collation 1947 */ 1948 int 1949 collate(a, b) 1950 const Char *a; 1951 const Char *b; 1952 { 1953 int rv; 1954 #ifdef SHORT_STRINGS 1955 /* This strips the quote bit as a side effect */ 1956 char *sa = strsave(short2str(a)); 1957 char *sb = strsave(short2str(b)); 1958 #else 1959 char *sa = strip(strsave(a)); 1960 char *sb = strip(strsave(b)); 1961 #endif /* SHORT_STRINGS */ 1962 1963 #if defined(NLS) && !defined(NOSTRCOLL) 1964 errno = 0; /* strcoll sets errno, another brain-damage */ 1965 1966 rv = strcoll(sa, sb); 1967 1968 /* 1969 * We should be checking for errno != 0, but some systems 1970 * forget to reset errno to 0. So we only check for the 1971 * only documented valid errno value for strcoll [EINVAL] 1972 */ 1973 if (errno == EINVAL) { 1974 xfree((ptr_t) sa); 1975 xfree((ptr_t) sb); 1976 stderror(ERR_SYSTEM, "strcoll", strerror(errno)); 1977 } 1978 #else 1979 rv = strcmp(sa, sb); 1980 #endif /* NLS && !NOSTRCOLL */ 1981 1982 xfree((ptr_t) sa); 1983 xfree((ptr_t) sb); 1984 1985 return rv; 1986 } 1987 1988 #ifdef HASHBANG 1989 /* 1990 * From: peter@zeus.dialix.oz.au (Peter Wemm) 1991 * If exec() fails look first for a #! [word] [word] .... 1992 * If it is, splice the header into the argument list and retry. 1993 */ 1994 #define HACKBUFSZ 1024 /* Max chars in #! vector */ 1995 #define HACKVECSZ 128 /* Max words in #! vector */ 1996 int 1997 hashbang(fd, vp) 1998 int fd; 1999 Char ***vp; 2000 { 2001 unsigned char lbuf[HACKBUFSZ]; 2002 char *sargv[HACKVECSZ]; 2003 unsigned char *p, *ws; 2004 int sargc = 0; 2005 #ifdef WINNT_NATIVE 2006 int fw = 0; /* found at least one word */ 2007 int first_word = 0; 2008 #endif /* WINNT_NATIVE */ 2009 2010 if (read(fd, (char *) lbuf, HACKBUFSZ) <= 0) 2011 return -1; 2012 2013 ws = 0; /* word started = 0 */ 2014 2015 for (p = lbuf; p < &lbuf[HACKBUFSZ]; ) 2016 switch (*p) { 2017 case ' ': 2018 case '\t': 2019 #ifdef WINNT_NATIVE 2020 case '\r': 2021 #endif /* WINNT_NATIVE */ 2022 if (ws) { /* a blank after a word.. save it */ 2023 *p = '\0'; 2024 #ifndef WINNT_NATIVE 2025 if (sargc < HACKVECSZ - 1) 2026 sargv[sargc++] = ws; 2027 ws = NULL; 2028 #else /* WINNT_NATIVE */ 2029 if (sargc < HACKVECSZ - 1) { 2030 sargv[sargc] = first_word ? NULL: hb_subst(ws); 2031 if (sargv[sargc] == NULL) 2032 sargv[sargc] = ws; 2033 sargc++; 2034 } 2035 ws = NULL; 2036 fw = 1; 2037 first_word = 1; 2038 #endif /* WINNT_NATIVE */ 2039 } 2040 p++; 2041 continue; 2042 2043 case '\0': /* Whoa!! what the hell happened */ 2044 return -1; 2045 2046 case '\n': /* The end of the line. */ 2047 if ( 2048 #ifdef WINNT_NATIVE 2049 fw || 2050 #endif /* WINNT_NATIVE */ 2051 ws) { /* terminate the last word */ 2052 *p = '\0'; 2053 #ifndef WINNT_NATIVE 2054 if (sargc < HACKVECSZ - 1) 2055 sargv[sargc++] = ws; 2056 #else /* WINNT_NATIVE */ 2057 if (sargc < HACKVECSZ - 1) { /* deal with the 1-word case */ 2058 sargv[sargc] = first_word? NULL : hb_subst(ws); 2059 if (sargv[sargc] == NULL) 2060 sargv[sargc] = ws; 2061 sargc++; 2062 } 2063 #endif /* !WINNT_NATIVE */ 2064 } 2065 sargv[sargc] = NULL; 2066 ws = NULL; 2067 if (sargc > 0) { 2068 *vp = blk2short(sargv); 2069 return 0; 2070 } 2071 else 2072 return -1; 2073 2074 default: 2075 if (!ws) /* Start a new word? */ 2076 ws = p; 2077 p++; 2078 break; 2079 } 2080 return -1; 2081 } 2082 #endif /* HASHBANG */ 2083 2084 #ifdef REMOTEHOST 2085 2086 static sigret_t 2087 palarm(snum) 2088 int snum; 2089 { 2090 USE(snum); 2091 #ifdef UNRELSIGS 2092 if (snum) 2093 (void) sigset(snum, SIG_IGN); 2094 #endif /* UNRELSIGS */ 2095 (void) alarm(0); 2096 reset(); 2097 2098 #ifndef SIGVOID 2099 return (snum); 2100 #endif 2101 } 2102 2103 2104 static void 2105 getremotehost() 2106 { 2107 const char *host = NULL; 2108 #ifdef INET6 2109 struct sockaddr_storage saddr; 2110 socklen_t len = sizeof(struct sockaddr_storage); 2111 static char hbuf[NI_MAXHOST]; 2112 #else 2113 struct hostent* hp; 2114 struct sockaddr_in saddr; 2115 int len = sizeof(struct sockaddr_in); 2116 #endif 2117 #if defined(UTHOST) && !defined(HAVENOUTMP) 2118 char *sptr = NULL; 2119 #endif 2120 2121 #ifdef INET6 2122 if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 2123 (saddr.ss_family == AF_INET6 || saddr.ss_family == AF_INET)) { 2124 int flag = NI_NUMERICHOST; 2125 2126 #ifdef NI_WITHSCOPEID 2127 flag |= NI_WITHSCOPEID; 2128 #endif 2129 getnameinfo((struct sockaddr *)&saddr, len, hbuf, sizeof(hbuf), 2130 NULL, 0, flag); 2131 host = hbuf; 2132 #else 2133 if (getpeername(SHIN, (struct sockaddr *) &saddr, &len) != -1 && 2134 saddr.sin_family == AF_INET) { 2135 #if 0 2136 if ((hp = gethostbyaddr((char *)&saddr.sin_addr, sizeof(struct in_addr), 2137 AF_INET)) != NULL) 2138 host = hp->h_name; 2139 else 2140 #endif 2141 host = inet_ntoa(saddr.sin_addr); 2142 #endif 2143 } 2144 #if defined(UTHOST) && !defined(HAVENOUTMP) 2145 else { 2146 char *ptr; 2147 char *name = utmphost(); 2148 /* Avoid empty names and local X displays */ 2149 if (name != NULL && *name != '\0' && *name != ':') { 2150 struct in_addr addr; 2151 2152 /* Look for host:display.screen */ 2153 /* 2154 * There is conflict with IPv6 address and X DISPLAY. So, 2155 * we assume there is no IPv6 address in utmp and don't 2156 * touch here. 2157 */ 2158 if ((sptr = strchr(name, ':')) != NULL) 2159 *sptr = '\0'; 2160 /* Leave IPv4 address as is */ 2161 /* 2162 * we use inet_addr here, not inet_aton because many systems 2163 * have not caught up yet. 2164 */ 2165 addr.s_addr = inet_addr(name); 2166 if (addr.s_addr != (unsigned int)~0) 2167 host = name; 2168 else { 2169 if (sptr != name) { 2170 #ifdef INET6 2171 char *s, *domain; 2172 char dbuf[MAXHOSTNAMELEN], cbuf[MAXHOSTNAMELEN]; 2173 struct addrinfo hints, *res = NULL; 2174 2175 memset(&hints, 0, sizeof(hints)); 2176 hints.ai_family = PF_UNSPEC; 2177 hints.ai_socktype = SOCK_STREAM; 2178 hints.ai_flags = AI_PASSIVE | AI_CANONNAME; 2179 #if defined(UTHOST) && !defined(HAVENOUTMP) 2180 if (strlen(name) < utmphostsize()) 2181 #else 2182 if (name != NULL) 2183 #endif 2184 { 2185 if (getaddrinfo(name, NULL, &hints, &res) != 0) 2186 res = NULL; 2187 } else if (gethostname(dbuf, sizeof(dbuf) - 1) == 0 && 2188 (domain = strchr(dbuf, '.')) != NULL) { 2189 for (s = strchr(name, '.'); 2190 s != NULL; s = strchr(s + 1, '.')) { 2191 if (*(s + 1) != '\0' && 2192 (ptr = strstr(domain, s)) != NULL) { 2193 len = s - name; 2194 if (len + strlen(ptr) >= sizeof(cbuf)) 2195 break; 2196 strncpy(cbuf, name, len); 2197 strcpy(cbuf + len, ptr); 2198 if (getaddrinfo(cbuf, NULL, &hints, &res) != 0) 2199 res = NULL; 2200 break; 2201 } 2202 } 2203 } 2204 if (res != NULL) { 2205 if (res->ai_canonname != NULL) { 2206 strncpy(hbuf, res->ai_canonname, sizeof(hbuf)); 2207 host = hbuf; 2208 } 2209 freeaddrinfo(res); 2210 } 2211 #else 2212 if ((hp = gethostbyname(name)) == NULL) { 2213 /* Try again eliminating the trailing domain */ 2214 if ((ptr = strchr(name, '.')) != NULL) { 2215 *ptr = '\0'; 2216 if ((hp = gethostbyname(name)) != NULL) 2217 host = hp->h_name; 2218 *ptr = '.'; 2219 } 2220 } 2221 else 2222 host = hp->h_name; 2223 #endif 2224 } 2225 } 2226 } 2227 } 2228 #endif 2229 2230 if (host) 2231 tsetenv(STRREMOTEHOST, str2short(host)); 2232 2233 #if defined(UTHOST) && !defined(HAVENOUTMP) 2234 if (sptr) 2235 *sptr = ':'; 2236 #endif 2237 } 2238 2239 2240 /* 2241 * From: <lesv@ppvku.ericsson.se> (Lennart Svensson) 2242 */ 2243 void 2244 remotehost() 2245 { 2246 /* Don't get stuck if the resolver does not work! */ 2247 signalfun_t osig = sigset(SIGALRM, palarm); 2248 2249 jmp_buf_t osetexit; 2250 getexit(osetexit); 2251 2252 (void) alarm(2); 2253 2254 if (setexit() == 0) 2255 getremotehost(); 2256 2257 resexit(osetexit); 2258 2259 (void) alarm(0); 2260 (void) sigset(SIGALRM, osig); 2261 2262 #ifdef YPBUGS 2263 /* From: casper@fwi.uva.nl (Casper H.S. Dik), for Solaris 2.3 */ 2264 fix_yp_bugs(); 2265 #endif /* YPBUGS */ 2266 2267 } 2268 #endif /* REMOTEHOST */ 2269