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