1/* Copyright (c) 1993-2002 2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) 3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) 4 * Copyright (c) 1987 Oliver Laumann 5#ifdef HAVE_BRAILLE 6 * Modified by: 7 * Authors: Hadi Bargi Rangin bargi@dots.physics.orst.edu 8 * Bill Barry barryb@dots.physics.orst.edu 9 * Randy Lundquist randyl@dots.physics.orst.edu 10 * 11 * Modifications Copyright (c) 1995 by 12 * Science Access Project, Oregon State University. 13#endif 14 * 15 * This program is free software; you can redistribute it and/or modify 16 * it under the terms of the GNU General Public License as published by 17 * the Free Software Foundation; either version 2, or (at your option) 18 * any later version. 19 * 20 * This program is distributed in the hope that it will be useful, 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 23 * GNU General Public License for more details. 24 * 25 * You should have received a copy of the GNU General Public License 26 * along with this program (see the file COPYING); if not, write to the 27 * Free Software Foundation, Inc., 28 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 29 * 30 **************************************************************** 31 */ 32 33#include <sys/types.h> 34#include <ctype.h> 35 36#include <fcntl.h> 37 38#ifdef sgi 39# include <sys/sysmacros.h> 40#endif 41 42#include <sys/stat.h> 43#ifndef sun 44# include <sys/ioctl.h> 45#endif 46 47#ifndef SIGINT 48# include <signal.h> 49#endif 50 51#include "config.h" 52 53#ifdef SVR4 54# include <sys/stropts.h> 55#endif 56 57#if defined(SYSV) && !defined(ISC) 58# include <sys/utsname.h> 59#endif 60 61#if defined(sequent) || defined(SVR4) 62# include <sys/resource.h> 63#endif /* sequent || SVR4 */ 64 65#ifdef ISC 66# include <sys/tty.h> 67# include <sys/sioctl.h> 68# include <sys/pty.h> 69#endif /* ISC */ 70 71#if (defined(AUX) || defined(_AUX_SOURCE)) && defined(POSIX) 72# include <compat.h> 73#endif 74#if defined(USE_LOCALE) || defined(ENCODINGS) 75# include <locale.h> 76#endif 77#if defined(HAVE_NL_LANGINFO) && defined(ENCODINGS) 78# include <langinfo.h> 79#endif 80 81#include "screen.h" 82#ifdef HAVE_BRAILLE 83# include "braille.h" 84#endif 85 86#include "patchlevel.h" 87 88/* 89 * At the moment we only need the real password if the 90 * builtin lock is used. Therefore disable SHADOWPW if 91 * we do not really need it (kind of security thing). 92 */ 93#ifndef LOCK 94# undef SHADOWPW 95#endif 96 97#include <pwd.h> 98#ifdef SHADOWPW 99# include <shadow.h> 100#endif /* SHADOWPW */ 101 102#include "logfile.h" /* islogfile, logfflush */ 103 104#ifdef __APPLE__ 105#include <TargetConditionals.h> 106#if !TARGET_OS_EMBEDDED 107#include <vproc.h> 108#include <vproc_priv.h> 109#endif 110#endif 111 112#ifdef DEBUG 113FILE *dfp; 114#endif 115 116 117extern char Term[], screenterm[], **environ, Termcap[]; 118int force_vt = 1; 119int VBellWait, MsgWait, MsgMinWait, SilenceWait; 120 121extern struct acluser *users; 122extern struct display *displays, *display; 123 124 125extern int visual_bell; 126#ifdef COPY_PASTE 127extern unsigned char mark_key_tab[]; 128#endif 129extern char version[]; 130extern char DefaultShell[]; 131#ifdef ZMODEM 132extern char *zmodem_sendcmd; 133extern char *zmodem_recvcmd; 134#endif 135 136 137char *ShellProg; 138char *ShellArgs[2]; 139 140extern struct NewWindow nwin_undef, nwin_default, nwin_options; 141struct backtick; 142 143static struct passwd *getpwbyname __P((char *, struct passwd *)); 144static void SigChldHandler __P((void)); 145static sigret_t SigChld __P(SIGPROTOARG); 146static sigret_t SigInt __P(SIGPROTOARG); 147static sigret_t CoreDump __P(SIGPROTOARG); 148static sigret_t FinitHandler __P(SIGPROTOARG); 149static void DoWait __P((void)); 150static void serv_read_fn __P((struct event *, char *)); 151static void serv_select_fn __P((struct event *, char *)); 152static void logflush_fn __P((struct event *, char *)); 153static void backtick_filter __P((struct backtick *)); 154static void backtick_fn __P((struct event *, char *)); 155static char *runbacktick __P((struct backtick *, int *, time_t)); 156static int IsSymbol __P((char *, char *)); 157static char *ParseChar __P((char *, char *)); 158static int ParseEscape __P((char *)); 159static char *pad_expand __P((char *, char *, int, int)); 160#ifdef DEBUG 161static void fds __P((void)); 162#endif 163 164int nversion; /* numerical version, used for secondary DA */ 165 166/* the attacher */ 167struct passwd *ppp; 168char *attach_tty; 169char *attach_term; 170char *LoginName; 171struct mode attach_Mode; 172 173char SockPath[MAXPATHLEN + 2 * MAXSTR]; 174char *SockName; /* SockName is pointer in SockPath */ 175char *SockMatch = NULL; /* session id command line argument */ 176int ServerSocket = -1; 177struct event serv_read; 178struct event serv_select; 179struct event logflushev; 180 181char **NewEnv = NULL; 182 183char *RcFileName = NULL; 184char *home; 185 186char *screenlogfile; /* filename layout */ 187int log_flush = 10; /* flush interval in seconds */ 188int logtstamp_on = 0; /* tstamp disabled */ 189char *logtstamp_string; /* stamp layout */ 190int logtstamp_after = 120; /* first tstamp after 120s */ 191char *hardcopydir = NULL; 192char *BellString; 193char *VisualBellString; 194char *ActivityString; 195#ifdef COPY_PASTE 196char *BufferFile; 197#endif 198#ifdef POW_DETACH 199char *PowDetachString; 200#endif 201char *hstatusstring; 202char *captionstring; 203char *timestring; 204char *wliststr; 205char *wlisttit; 206int auto_detach = 1; 207int iflag, rflag, dflag, lsflag, quietflag, wipeflag, xflag; 208int cmdflag; 209int adaptflag; 210 211#ifdef MULTIUSER 212char *multi; 213char *multi_home; 214int multi_uid; 215int own_uid; 216int multiattach; 217int tty_mode; 218int tty_oldmode = -1; 219#endif 220 221char HostName[MAXSTR]; 222int MasterPid; 223int real_uid, real_gid, eff_uid, eff_gid; 224int default_startup; 225int ZombieKey_destroy, ZombieKey_resurrect; 226char *preselect = NULL; /* only used in Attach() */ 227 228#ifdef UTF8 229char *screenencodings; 230#endif 231 232#ifdef NETHACK 233int nethackflag = 0; 234#endif 235int maxwin = MAXWIN; 236 237 238struct layer *flayer; 239struct win *fore; 240struct win *windows; 241struct win *console_window; 242 243 244 245/* 246 * Do this last 247 */ 248#include "extern.h" 249 250char strnomem[] = "Out of memory."; 251 252 253static int InterruptPlease; 254static int GotSigChld; 255 256static int 257lf_secreopen(name, wantfd, l) 258char *name; 259int wantfd; 260struct logfile *l; 261{ 262 int got_fd; 263 264 close(wantfd); 265 if (((got_fd = secopen(name, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) || 266 lf_move_fd(got_fd, wantfd) < 0) 267 { 268 logfclose(l); 269 debug1("lf_secreopen: failed for %s\n", name); 270 return -1; 271 } 272 l->st->st_ino = l->st->st_dev = 0; 273 debug2("lf_secreopen: %d = %s\n", wantfd, name); 274 return 0; 275} 276 277/********************************************************************/ 278/********************************************************************/ 279/********************************************************************/ 280 281 282static struct passwd * 283getpwbyname(name, ppp) 284char *name; 285struct passwd *ppp; 286{ 287 int n; 288#ifdef SHADOWPW 289 struct spwd *sss = NULL; 290 static char *spw = NULL; 291#endif 292 293 if (!ppp && !(ppp = getpwnam(name))) 294 return NULL; 295 296 /* Do password sanity check..., allow ##user for SUN_C2 security */ 297#ifdef SHADOWPW 298pw_try_again: 299#endif 300 n = 0; 301 if (ppp->pw_passwd[0] == '#' && ppp->pw_passwd[1] == '#' && 302 strcmp(ppp->pw_passwd + 2, ppp->pw_name) == 0) 303 n = 13; 304 for (; n < 13; n++) 305 { 306 char c = ppp->pw_passwd[n]; 307 if (!(c == '.' || c == '/' || c == '$' || 308 (c >= '0' && c <= '9') || 309 (c >= 'a' && c <= 'z') || 310 (c >= 'A' && c <= 'Z'))) 311 break; 312 } 313 314#ifdef SHADOWPW 315 /* try to determine real password */ 316 if (n < 13 && sss == 0) 317 { 318 sss = getspnam(ppp->pw_name); 319 if (sss) 320 { 321 if (spw) 322 free(spw); 323 ppp->pw_passwd = spw = SaveStr(sss->sp_pwdp); 324 endspent(); /* this should delete all buffers ... */ 325 goto pw_try_again; 326 } 327 endspent(); /* this should delete all buffers ... */ 328 } 329#endif 330 if (n < 13) 331 ppp->pw_passwd = 0; 332#ifdef linux 333 if (ppp->pw_passwd && strlen(ppp->pw_passwd) == 13 + 11) 334 ppp->pw_passwd[13] = 0; /* beware of linux's long passwords */ 335#endif 336 337 return ppp; 338} 339 340 341int 342main(ac, av) 343int ac; 344char **av; 345{ 346 register int n; 347 char *ap; 348 char *av0; 349 char socknamebuf[2 * MAXSTR]; 350 int mflag = 0; 351 char *myname = (ac == 0) ? "screen" : av[0]; 352 char *SockDir; 353 struct stat st; 354#ifdef _MODE_T /* (jw) */ 355 mode_t oumask; 356#else 357 int oumask; 358#endif 359#if defined(SYSV) && !defined(ISC) 360 struct utsname utsnam; 361#endif 362 struct NewWindow nwin; 363 int detached = 0; /* start up detached */ 364#ifdef MULTIUSER 365 char *sockp; 366#endif 367 368#if (defined(AUX) || defined(_AUX_SOURCE)) && defined(POSIX) 369 setcompat(COMPAT_POSIX|COMPAT_BSDPROT); /* turn on seteuid support */ 370#endif 371#if defined(sun) && defined(SVR4) 372 { 373 /* Solaris' login blocks SIGHUP! This is _very bad_ */ 374 sigset_t sset; 375 sigemptyset(&sset); 376 sigprocmask(SIG_SETMASK, &sset, 0); 377 } 378#endif 379 380 /* 381 * First, close all unused descriptors 382 * (otherwise, we might have problems with the select() call) 383 */ 384 closeallfiles(0); 385#ifdef DEBUG 386 opendebug(1, 0); 387#endif 388 sprintf(version, "%d.%.2d.%.2d%s (%s) %s", REV, VERS, 389 PATCHLEVEL, STATE, ORIGIN, DATE); 390 nversion = REV * 10000 + VERS * 100 + PATCHLEVEL; 391 debug2("-- screen debug started %s (%s)\n", *av, version); 392#ifdef POSIX 393 debug("POSIX\n"); 394#endif 395#ifdef TERMIO 396 debug("TERMIO\n"); 397#endif 398#ifdef SYSV 399 debug("SYSV\n"); 400#endif 401#ifdef SYSVSIGS 402 debug("SYSVSIGS\n"); 403#endif 404#ifdef NAMEDPIPE 405 debug("NAMEDPIPE\n"); 406#endif 407#if defined(SIGWINCH) && defined(TIOCGWINSZ) 408 debug("Window size changing enabled\n"); 409#endif 410#ifdef HAVE_SETREUID 411 debug("SETREUID\n"); 412#endif 413#ifdef HAVE_SETEUID 414 debug("SETEUID\n"); 415#endif 416#ifdef hpux 417 debug("hpux\n"); 418#endif 419#ifdef USEBCOPY 420 debug("USEBCOPY\n"); 421#endif 422#ifdef UTMPOK 423 debug("UTMPOK\n"); 424#endif 425#ifdef LOADAV 426 debug("LOADAV\n"); 427#endif 428#ifdef NETHACK 429 debug("NETHACK\n"); 430#endif 431#ifdef TERMINFO 432 debug("TERMINFO\n"); 433#endif 434#ifdef SHADOWPW 435 debug("SHADOWPW\n"); 436#endif 437#ifdef NAME_MAX 438 debug1("NAME_MAX = %d\n", NAME_MAX); 439#endif 440 441 BellString = SaveStr("Bell in window %n"); 442 VisualBellString = SaveStr(" Wuff, Wuff!! "); 443 ActivityString = SaveStr("Activity in window %n"); 444 screenlogfile = SaveStr("screenlog.%n"); 445 logtstamp_string = SaveStr("-- %n:%t -- time-stamp -- %M/%d/%y %c:%s --\n"); 446 hstatusstring = SaveStr("%h"); 447 captionstring = SaveStr("%3n %t"); 448 timestring = SaveStr("%c:%s %M %d %H%? %l%?"); 449 wlisttit = SaveStr("Num Name%=Flags"); 450 wliststr = SaveStr("%3n %t%=%f"); 451#ifdef COPY_PASTE 452 BufferFile = SaveStr(DEFAULT_BUFFERFILE); 453#endif 454 ShellProg = NULL; 455#ifdef POW_DETACH 456 PowDetachString = 0; 457#endif 458 default_startup = (ac > 1) ? 0 : 1; 459 adaptflag = 0; 460 VBellWait = VBELLWAIT * 1000; 461 MsgWait = MSGWAIT * 1000; 462 MsgMinWait = MSGMINWAIT * 1000; 463 SilenceWait = SILENCEWAIT; 464#ifdef HAVE_BRAILLE 465 InitBraille(); 466#endif 467#ifdef ZMODEM 468 zmodem_sendcmd = SaveStr("!!! sz -vv -b "); 469 zmodem_recvcmd = SaveStr("!!! rz -vv -b -E"); 470#endif 471 472#ifdef COPY_PASTE 473 CompileKeys((char *)0, 0, mark_key_tab); 474#endif 475#ifdef UTF8 476 InitBuiltinTabs(); 477 screenencodings = SaveStr(SCREENENCODINGS); 478#endif 479 nwin = nwin_undef; 480 nwin_options = nwin_undef; 481 strcpy(screenterm, "screen"); 482 483 logreopen_register(lf_secreopen); 484 485 av0 = *av; 486 /* if this is a login screen, assume -RR */ 487 if (*av0 == '-') 488 { 489 rflag = 4; 490#ifdef MULTI 491 xflag = 1; 492#else 493 dflag = 1; 494#endif 495 ShellProg = SaveStr(DefaultShell); /* to prevent nasty circles */ 496 } 497 while (ac > 0) 498 { 499 ap = *++av; 500 if (--ac > 0 && *ap == '-') 501 { 502 if (ap[1] == '-' && ap[2] == 0) 503 { 504 av++; 505 ac--; 506 break; 507 } 508 if (ap[1] == '-' && !strcmp(ap, "--version")) 509 Panic(0, "Screen version %s", version); 510 if (ap[1] == '-' && !strcmp(ap, "--help")) 511 exit_with_usage(myname, NULL, NULL); 512 while (ap && *ap && *++ap) 513 { 514 switch (*ap) 515 { 516 case 'a': 517 nwin_options.aflag = 1; 518 break; 519 case 'A': 520 adaptflag = 1; 521 break; 522 case 'p': /* preselect */ 523 if (*++ap) 524 preselect = ap; 525 else 526 { 527 if (!--ac) 528 exit_with_usage(myname, "Specify a window to preselect with -p", NULL); 529 preselect = *++av; 530 } 531 ap = NULL; 532 break; 533#ifdef HAVE_BRAILLE 534 case 'B': 535 bd.bd_start_braille = 1; 536 break; 537#endif 538 case 'c': 539 if (*++ap) 540 RcFileName = ap; 541 else 542 { 543 if (--ac == 0) 544 exit_with_usage(myname, "Specify an alternate rc-filename with -c", NULL); 545 RcFileName = *++av; 546 } 547 ap = NULL; 548 break; 549 case 'e': 550 if (!*++ap) 551 { 552 if (--ac == 0) 553 exit_with_usage(myname, "Specify command characters with -e", NULL); 554 ap = *++av; 555 } 556 if (ParseEscape(ap)) 557 Panic(0, "Two characters are required with -e option, not '%s'.", ap); 558 ap = NULL; 559 break; 560 case 'f': 561 ap++; 562 switch (*ap++) 563 { 564 case 'n': 565 case '0': 566 nwin_options.flowflag = FLOW_NOW * 0; 567 break; 568 case '\0': 569 ap--; 570 /* FALLTHROUGH */ 571 case 'y': 572 case '1': 573 nwin_options.flowflag = FLOW_NOW * 1; 574 break; 575 case 'a': 576 nwin_options.flowflag = FLOW_AUTOFLAG; 577 break; 578 default: 579 exit_with_usage(myname, "Unknown flow option -%s", --ap); 580 } 581 break; 582 case 'h': 583 if (--ac == 0) 584 exit_with_usage(myname, NULL, NULL); 585 nwin_options.histheight = atoi(*++av); 586 if (nwin_options.histheight < 0) 587 exit_with_usage(myname, "-h: %s: negative scrollback size?", *av); 588 break; 589 case 'i': 590 iflag = 1; 591 break; 592 case 't': /* title, the former AkA == -k */ 593 if (--ac == 0) 594 exit_with_usage(myname, "Specify a new window-name with -t", NULL); 595 nwin_options.aka = *++av; 596 break; 597 case 'l': 598 ap++; 599 switch (*ap++) 600 { 601 case 'n': 602 case '0': 603 nwin_options.lflag = 0; 604 break; 605 case '\0': 606 ap--; 607 /* FALLTHROUGH */ 608 case 'y': 609 case '1': 610 nwin_options.lflag = 1; 611 break; 612 case 'a': 613 nwin_options.lflag = 3; 614 break; 615 case 's': /* -ls */ 616 case 'i': /* -list */ 617 lsflag = 1; 618 if (ac > 1 && !SockMatch) 619 { 620 SockMatch = *++av; 621 ac--; 622 } 623 ap = NULL; 624 break; 625 default: 626 exit_with_usage(myname, "%s: Unknown suboption to -l", --ap); 627 } 628 break; 629 case 'w': 630 lsflag = 1; 631 wipeflag = 1; 632 if (ac > 1 && !SockMatch) 633 { 634 SockMatch = *++av; 635 ac--; 636 } 637 break; 638 case 'L': 639 nwin_options.Lflag = 1; 640 break; 641 case 'm': 642 mflag = 1; 643 break; 644 case 'O': /* to be (or not to be?) deleted. jw. */ 645 force_vt = 0; 646 break; 647 case 'T': 648 if (--ac == 0) 649 exit_with_usage(myname, "Specify terminal-type with -T", NULL); 650 if (strlen(*++av) < 20) 651 strcpy(screenterm, *av); 652 else 653 Panic(0, "-T: terminal name too long. (max. 20 char)"); 654 nwin_options.term = screenterm; 655 break; 656 case 'q': 657 quietflag = 1; 658 break; 659 case 'r': 660 case 'R': 661#ifdef MULTI 662 case 'x': 663#endif 664 if (ac > 1 && *av[1] != '-' && !SockMatch) 665 { 666 SockMatch = *++av; 667 ac--; 668 debug2("rflag=%d, SockMatch=%s\n", dflag, SockMatch); 669 } 670#ifdef MULTI 671 if (*ap == 'x') 672 xflag = 1; 673#endif 674 if (rflag) 675 rflag = 2; 676 rflag += (*ap == 'R') ? 2 : 1; 677 break; 678#ifdef REMOTE_DETACH 679 case 'd': 680 dflag = 1; 681 /* FALLTHROUGH */ 682 case 'D': 683 if (!dflag) 684 dflag = 2; 685 if (ac == 2) 686 { 687 if (*av[1] != '-' && !SockMatch) 688 { 689 SockMatch = *++av; 690 ac--; 691 debug2("dflag=%d, SockMatch=%s\n", dflag, SockMatch); 692 } 693 } 694 break; 695#endif 696 case 's': 697 if (--ac == 0) 698 exit_with_usage(myname, "Specify shell with -s", NULL); 699 if (ShellProg) 700 free(ShellProg); 701 ShellProg = SaveStr(*++av); 702 debug1("ShellProg: '%s'\n", ShellProg); 703 break; 704 case 'S': 705 if (!SockMatch) 706 { 707 if (--ac == 0) 708 exit_with_usage(myname, "Specify session-name with -S", NULL); 709 SockMatch = *++av; 710 } 711 if (!*SockMatch) 712 exit_with_usage(myname, "Empty session-name?", NULL); 713 break; 714 case 'X': 715 cmdflag = 1; 716 break; 717 case 'v': 718 Panic(0, "Screen version %s", version); 719 /* NOTREACHED */ 720#ifdef UTF8 721 case 'U': 722 nwin_options.encoding = nwin_options.encoding == -1 ? UTF8 : 0; 723 break; 724#endif 725 default: 726 exit_with_usage(myname, "Unknown option %s", --ap); 727 } 728 } 729 } 730 else 731 break; 732 } 733 734 real_uid = getuid(); 735 real_gid = getgid(); 736 eff_uid = geteuid(); 737 eff_gid = getegid(); 738 if (eff_uid != real_uid) 739 { 740 /* if running with s-bit, we must install a special signal 741 * handler routine that resets the s-bit, so that we get a 742 * core file anyway. 743 */ 744#ifdef SIGBUS /* OOPS, linux has no bus errors! */ 745 signal(SIGBUS, CoreDump); 746#endif /* SIGBUS */ 747 signal(SIGSEGV, CoreDump); 748 } 749 750#ifdef USE_LOCALE 751 setlocale(LC_ALL, ""); 752#endif 753#ifdef ENCODINGS 754 if (nwin_options.encoding == -1) 755 { 756 /* ask locale if we should start in UTF-8 mode */ 757# ifdef HAVE_NL_LANGINFO 758# ifndef USE_LOCALE 759 setlocale(LC_CTYPE, ""); 760# endif 761 nwin_options.encoding = FindEncoding(nl_langinfo(CODESET)); 762 debug1("locale says encoding = %d\n", nwin_options.encoding); 763# else 764# ifdef UTF8 765 char *s; 766 if (((s = getenv("LC_ALL")) || (s = getenv("LC_CTYPE")) || 767 (s = getenv("LANG"))) && InStr(s, "UTF-8")) 768 nwin_options.encoding = UTF8; 769# endif 770 debug1("environment says encoding=%d\n", nwin_options.encoding); 771#endif 772 } 773#endif 774 if (SockMatch && strlen(SockMatch) >= MAXSTR) 775 Panic(0, "Ridiculously long socketname - try again."); 776 if (cmdflag && !rflag && !dflag && !xflag) 777 xflag = 1; 778 if (!cmdflag && dflag && mflag && !(rflag || xflag)) 779 detached = 1; 780 nwin = nwin_options; 781#ifdef ENCODINGS 782 nwin.encoding = nwin_undef.encoding; /* let screenrc overwrite it */ 783#endif 784 if (ac) 785 nwin.args = av; 786 787 /* make the write() calls return -1 on all errors */ 788#ifdef SIGXFSZ 789 /* 790 * Ronald F. Guilmette, Oct 29 '94, bug-gnu-utils@prep.ai.mit.edu: 791 * It appears that in System V Release 4, UNIX, if you are writing 792 * an output file and you exceed the currently set file size limit, 793 * you _don't_ just get the call to `write' returning with a 794 * failure code. Rather, you get a signal called `SIGXFSZ' which, 795 * if neither handled nor ignored, will cause your program to crash 796 * with a core dump. 797 */ 798 signal(SIGXFSZ, SIG_IGN); 799#endif /* SIGXFSZ */ 800 801#ifdef SIGPIPE 802 signal(SIGPIPE, SIG_IGN); 803#endif 804 805 if (!ShellProg) 806 { 807 register char *sh; 808 809 sh = getenv("SHELL"); 810 ShellProg = SaveStr(sh ? sh : DefaultShell); 811 } 812 ShellArgs[0] = ShellProg; 813 home = getenv("HOME"); 814 815#ifdef NETHACK 816 if (!(nethackflag = (getenv("NETHACKOPTIONS") != NULL))) 817 { 818 char nethackrc[MAXPATHLEN]; 819 820 if (home && (strlen(home) < (MAXPATHLEN - 20))) 821 { 822 sprintf(nethackrc,"%s/.nethackrc", home); 823 nethackflag = !access(nethackrc, F_OK); 824 } 825 } 826#endif 827 828#ifdef MULTIUSER 829 own_uid = multi_uid = real_uid; 830 if (SockMatch && (sockp = index(SockMatch, '/'))) 831 { 832 if (eff_uid) 833 Panic(0, "Must run suid root for multiuser support."); 834 *sockp = 0; 835 multi = SockMatch; 836 SockMatch = sockp + 1; 837 if (*multi) 838 { 839 struct passwd *mppp; 840 if ((mppp = getpwnam(multi)) == (struct passwd *)0) 841 Panic(0, "Cannot identify account '%s'.", multi); 842 multi_uid = mppp->pw_uid; 843 multi_home = SaveStr(mppp->pw_dir); 844 if (strlen(multi_home) > MAXPATHLEN - 10) 845 Panic(0, "home directory path too long"); 846# ifdef MULTI 847 /* always fake multi attach mode */ 848 if (rflag || lsflag) 849 xflag = 1; 850# endif /* MULTI */ 851 detached = 0; 852 multiattach = 1; 853 } 854 } 855 if (SockMatch && *SockMatch == 0) 856 SockMatch = 0; 857#endif /* MULTIUSER */ 858 859 if ((LoginName = getlogin()) && LoginName[0] != '\0') 860 { 861 if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0) 862 if ((int)ppp->pw_uid != real_uid) 863 ppp = (struct passwd *) 0; 864 } 865 if (ppp == 0) 866 { 867 if ((ppp = getpwuid(real_uid)) == 0) 868 { 869 Panic(0, "getpwuid() can't identify your account!"); 870 exit(1); 871 } 872 LoginName = ppp->pw_name; 873 } 874 LoginName = SaveStr(LoginName); 875 876 ppp = getpwbyname(LoginName, ppp); 877 878#if !defined(SOCKDIR) && defined(MULTIUSER) 879 if (multi && !multiattach) 880 { 881 if (home && strcmp(home, ppp->pw_dir)) 882 Panic(0, "$HOME must match passwd entry for multiuser screens."); 883 } 884#endif 885 886 if (home == 0 || *home == '\0') 887 home = ppp->pw_dir; 888 if (strlen(LoginName) > 20) 889 Panic(0, "LoginName too long - sorry."); 890#ifdef MULTIUSER 891 if (multi && strlen(multi) > 20) 892 Panic(0, "Screen owner name too long - sorry."); 893#endif 894 if (strlen(home) > MAXPATHLEN - 25) 895 Panic(0, "$HOME too long - sorry."); 896 897 attach_tty = ""; 898 if (!detached && !lsflag && !cmdflag && !(dflag && !mflag && !rflag && !xflag)) 899 { 900 /* ttyname implies isatty */ 901 if (!(attach_tty = ttyname(0))) 902 Panic(0, "Must be connected to a terminal."); 903 if (strlen(attach_tty) >= MAXPATHLEN) 904 Panic(0, "TtyName too long - sorry."); 905 if (stat(attach_tty, &st)) 906 Panic(errno, "Cannot access '%s'", attach_tty); 907#ifdef MULTIUSER 908 tty_mode = (int)st.st_mode & 0777; 909#endif 910 if ((n = secopen(attach_tty, O_RDWR | O_NONBLOCK, 0)) < 0) 911 Panic(0, "Cannot open your terminal '%s' - please check.", attach_tty); 912 close(n); 913 debug1("attach_tty is %s\n", attach_tty); 914 if ((attach_term = getenv("TERM")) == 0 || *attach_term == 0) 915 Panic(0, "Please set a terminal type."); 916 if (strlen(attach_term) > sizeof(D_termname) - 1) 917 Panic(0, "$TERM too long - sorry."); 918 GetTTY(0, &attach_Mode); 919#ifdef DEBUGGGGGGGGGGGGGGG 920 DebugTTY(&attach_Mode); 921#endif /* DEBUG */ 922 } 923 924#ifdef _MODE_T 925 oumask = umask(0); /* well, unsigned never fails? jw. */ 926#else 927 if ((oumask = (int)umask(0)) == -1) 928 Panic(errno, "Cannot change umask to zero"); 929#endif 930 SockDir = getenv("SCREENDIR"); 931 if (SockDir) 932 { 933 if (strlen(SockDir) >= MAXPATHLEN - 1) 934 Panic(0, "Ridiculously long $SCREENDIR - try again."); 935#ifdef MULTIUSER 936 if (multi) 937 Panic(0, "No $SCREENDIR with multi screens, please."); 938#endif 939 } 940#ifdef __APPLE__ 941 else if (!multi && real_uid == eff_uid) { 942 static char DarwinSockDir[PATH_MAX]; 943 if (confstr(_CS_DARWIN_USER_TEMP_DIR, DarwinSockDir, sizeof(DarwinSockDir))) { 944 strlcat(DarwinSockDir, ".screen", sizeof(DarwinSockDir)); 945 SockDir = DarwinSockDir; 946 } 947 } 948#endif /* __APPLE__ */ 949 950#ifdef MULTIUSER 951 if (multiattach) 952 { 953# ifndef SOCKDIR 954 sprintf(SockPath, "%s/.screen", multi_home); 955 SockDir = SockPath; 956# else 957 SockDir = SOCKDIR; 958 sprintf(SockPath, "%s/S-%s", SockDir, multi); 959# endif 960 } 961 else 962#endif 963 { 964#ifndef SOCKDIR 965 if (SockDir == 0) 966 { 967 sprintf(SockPath, "%s/.screen", home); 968 SockDir = SockPath; 969 } 970#endif 971 if (SockDir) 972 { 973 if (access(SockDir, F_OK)) 974 { 975 debug1("SockDir '%s' missing ...\n", SockDir); 976 if (UserContext() > 0) 977 { 978 if (mkdir(SockDir, 0700)) 979 UserReturn(0); 980 UserReturn(1); 981 } 982 if (UserStatus() <= 0) 983 Panic(0, "Cannot make directory '%s'.", SockDir); 984 } 985 if (SockDir != SockPath) 986 strcpy(SockPath, SockDir); 987 } 988#ifdef SOCKDIR 989 else 990 { 991 SockDir = SOCKDIR; 992 if (lstat(SockDir, &st)) 993 { 994 n = (eff_uid == 0 && (real_uid || eff_gid == real_gid)) ? 0755 : 995 (eff_gid != real_gid) ? 0775 : 996#ifdef S_ISVTX 997 0777|S_ISVTX; 998#else 999 0777; 1000#endif 1001 if (mkdir(SockDir, n) == -1) 1002 Panic(errno, "Cannot make directory '%s'", SockDir); 1003 } 1004 else 1005 { 1006 if (!S_ISDIR(st.st_mode)) 1007 Panic(0, "'%s' must be a directory.", SockDir); 1008 if (eff_uid == 0 && real_uid && (int)st.st_uid != eff_uid) 1009 Panic(0, "Directory '%s' must be owned by root.", SockDir); 1010 n = (eff_uid == 0 && (real_uid || (st.st_mode & 0775) != 0775)) ? 0755 : 1011 (eff_gid == (int)st.st_gid && eff_gid != real_gid) ? 0775 : 1012 0777; 1013 if (((int)st.st_mode & 0777) != n) 1014 Panic(0, "Directory '%s' must have mode %03o.", SockDir, n); 1015 } 1016 sprintf(SockPath, "%s/S-%s", SockDir, LoginName); 1017 if (access(SockPath, F_OK)) 1018 { 1019 if (mkdir(SockPath, 0700) == -1) 1020 Panic(errno, "Cannot make directory '%s'", SockPath); 1021 (void) chown(SockPath, real_uid, real_gid); 1022 } 1023 } 1024#endif 1025 } 1026 1027 if (stat(SockPath, &st) == -1) 1028 Panic(errno, "Cannot access %s", SockPath); 1029 else 1030 if (!S_ISDIR(st.st_mode)) 1031 Panic(0, "%s is not a directory.", SockPath); 1032#ifdef MULTIUSER 1033 if (multi) 1034 { 1035 if ((int)st.st_uid != multi_uid) 1036 Panic(0, "%s is not the owner of %s.", multi, SockPath); 1037 } 1038 else 1039#endif 1040 { 1041 if ((int)st.st_uid != real_uid) 1042 Panic(0, "You are not the owner of %s.", SockPath); 1043 } 1044 if ((st.st_mode & 0777) != 0700) 1045 Panic(0, "Directory %s must have mode 700.", SockPath); 1046 if (SockMatch && index(SockMatch, '/')) 1047 Panic(0, "Bad session name '%s'", SockMatch); 1048 SockName = SockPath + strlen(SockPath) + 1; 1049 *SockName = 0; 1050 (void) umask(oumask); 1051 debug2("SockPath: %s SockMatch: %s\n", SockPath, SockMatch ? SockMatch : "NULL"); 1052 1053#if defined(SYSV) && !defined(ISC) 1054 if (uname(&utsnam) == -1) 1055 Panic(errno, "uname"); 1056 strncpy(HostName, utsnam.nodename, sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1); 1057 HostName[sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1] = '\0'; 1058#else 1059 (void) gethostname(HostName, MAXSTR); 1060 HostName[MAXSTR - 1] = '\0'; 1061#endif 1062 if ((ap = index(HostName, '.')) != NULL) 1063 *ap = '\0'; 1064 1065 if (lsflag) 1066 { 1067 int i, fo, oth; 1068 1069#ifdef MULTIUSER 1070 if (multi) 1071 real_uid = multi_uid; 1072#endif 1073 setgid(real_gid); 1074 setuid(real_uid); 1075 eff_uid = real_uid; 1076 eff_gid = real_gid; 1077 i = FindSocket((int *)NULL, &fo, &oth, SockMatch); 1078 if (quietflag) 1079 exit(8 + (fo ? ((oth || i) ? 2 : 1) : 0) + i); 1080 if (fo == 0) 1081 Panic(0, "No Sockets found in %s.\n", SockPath); 1082 Panic(0, "%d Socket%s in %s.\n", fo, fo > 1 ? "s" : "", SockPath); 1083 /* NOTREACHED */ 1084 } 1085 signal(SIG_BYE, AttacherFinit); /* prevent races */ 1086 if (cmdflag) 1087 { 1088 char *sty = 0; 1089 1090 /* attach_tty is not mandatory */ 1091 if ((attach_tty = ttyname(0)) == 0) 1092 attach_tty = ""; 1093 if (strlen(attach_tty) >= MAXPATHLEN) 1094 Panic(0, "TtyName too long - sorry."); 1095 if (!*av) 1096 Panic(0, "Please specify a command."); 1097 setgid(real_gid); 1098 setuid(real_uid); 1099 eff_uid = real_uid; 1100 eff_gid = real_gid; 1101 if (!mflag && !SockMatch) 1102 { 1103 sty = getenv("STY"); 1104 if (sty && *sty == 0) 1105 sty = 0; 1106 } 1107 SendCmdMessage(sty, SockMatch, av); 1108 exit(0); 1109 } 1110 else if (rflag || xflag) 1111 { 1112 debug("screen -r: - is there anybody out there?\n"); 1113 if (Attach(MSG_ATTACH)) 1114 { 1115 Attacher(); 1116 /* NOTREACHED */ 1117 } 1118#ifdef MULTIUSER 1119 if (multiattach) 1120 Panic(0, "Can't create sessions of other users."); 1121#endif 1122 debug("screen -r: backend not responding -- still crying\n"); 1123 } 1124 else if (dflag && !mflag) 1125 { 1126 (void) Attach(MSG_DETACH); 1127 Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : "")); 1128 eexit(0); 1129 /* NOTREACHED */ 1130 } 1131 if (!SockMatch && !mflag) 1132 { 1133 register char *sty; 1134 1135 if ((sty = getenv("STY")) != 0 && *sty != '\0') 1136 { 1137 setgid(real_gid); 1138 setuid(real_uid); 1139 eff_uid = real_uid; 1140 eff_gid = real_gid; 1141 nwin_options.args = av; 1142 SendCreateMsg(sty, &nwin); 1143 exit(0); 1144 /* NOTREACHED */ 1145 } 1146 } 1147 nwin_compose(&nwin_default, &nwin_options, &nwin_default); 1148 1149 if (!detached || dflag != 2) 1150 MasterPid = fork(); 1151 else 1152 MasterPid = 0; 1153 1154 switch (MasterPid) 1155 { 1156 case -1: 1157 Panic(errno, "fork"); 1158 /* NOTREACHED */ 1159 case 0: 1160 break; 1161 default: 1162 if (detached) 1163 exit(0); 1164 if (SockMatch) 1165 sprintf(socknamebuf, "%d.%s", MasterPid, SockMatch); 1166 else 1167 sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty), HostName); 1168 for (ap = socknamebuf; *ap; ap++) 1169 if (*ap == '/') 1170 *ap = '-'; 1171#ifdef NAME_MAX 1172 if (strlen(socknamebuf) > NAME_MAX) 1173 socknamebuf[NAME_MAX] = 0; 1174#endif 1175 sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf); 1176 setgid(real_gid); 1177 setuid(real_uid); 1178 eff_uid = real_uid; 1179 eff_gid = real_gid; 1180 Attacher(); 1181 /* NOTREACHED */ 1182 } 1183 1184 if (DefaultEsc == -1) 1185 DefaultEsc = Ctrl('a'); 1186 if (DefaultMetaEsc == -1) 1187 DefaultMetaEsc = 'a'; 1188 1189 ap = av0 + strlen(av0) - 1; 1190 while (ap >= av0) 1191 { 1192 if (!strncmp("screen", ap, 6)) 1193 { 1194 strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */ 1195 break; 1196 } 1197 ap--; 1198 } 1199 if (ap < av0) 1200 *av0 = 'S'; 1201 1202#ifdef DEBUG 1203 { 1204 char buf[256]; 1205 1206 if (dfp && dfp != stderr) 1207 fclose(dfp); 1208 sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, (int)getpid()); 1209 if ((dfp = fopen(buf, "w")) == NULL) 1210 dfp = stderr; 1211 else 1212 (void) chmod(buf, 0666); 1213 } 1214#endif 1215 if (!detached) 1216 { 1217 /* reopen tty. must do this, because fd 0 may be RDONLY */ 1218 if ((n = secopen(attach_tty, O_RDWR, 0)) < 0) 1219 Panic(0, "Cannot reopen '%s' - please check.", attach_tty); 1220 } 1221 else 1222 n = -1; 1223 freopen("/dev/null", "r", stdin); 1224 freopen("/dev/null", "w", stdout); 1225 1226#ifdef DEBUG 1227 if (dfp != stderr) 1228#endif 1229 freopen("/dev/null", "w", stderr); 1230 debug("-- screen.back debug started\n"); 1231 1232#if defined(__APPLE__) && !TARGET_OS_EMBEDDED 1233 if (_vprocmgr_detach_from_console(0) != NULL) 1234 errx(1, "can't detach from console"); 1235#endif 1236 1237 /* 1238 * This guarantees that the session owner is listed, even when we 1239 * start detached. From now on we should not refer to 'LoginName' 1240 * any more, use users->u_name instead. 1241 */ 1242 if (UserAdd(LoginName, (char *)0, (struct acluser **)0) < 0) 1243 Panic(0, "Could not create user info"); 1244 if (!detached) 1245 { 1246 if (MakeDisplay(LoginName, attach_tty, attach_term, n, getppid(), &attach_Mode) == 0) 1247 Panic(0, "Could not alloc display"); 1248#ifdef ENCODINGS 1249 D_encoding = nwin_options.encoding > 0 ? nwin_options.encoding : 0; 1250 debug1("D_encoding = %d\n", D_encoding); 1251#endif 1252 } 1253 1254 if (SockMatch) 1255 { 1256 /* user started us with -S option */ 1257 sprintf(socknamebuf, "%d.%s", (int)getpid(), SockMatch); 1258 } 1259 else 1260 { 1261 sprintf(socknamebuf, "%d.%s.%s", (int)getpid(), stripdev(attach_tty), 1262 HostName); 1263 } 1264 for (ap = socknamebuf; *ap; ap++) 1265 if (*ap == '/') 1266 *ap = '-'; 1267#ifdef NAME_MAX 1268 if (strlen(socknamebuf) > NAME_MAX) 1269 { 1270 debug2("Socketname %s truncated to %d chars\n", socknamebuf, NAME_MAX); 1271 socknamebuf[NAME_MAX] = 0; 1272 } 1273#endif 1274 sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf); 1275 1276 ServerSocket = MakeServerSocket(); 1277 InitKeytab(); 1278#ifdef ETCSCREENRC 1279# ifdef ALLOW_SYSSCREENRC 1280 if ((ap = getenv("SYSSCREENRC"))) 1281 StartRc(ap); 1282 else 1283# endif 1284 StartRc(ETCSCREENRC); 1285#endif 1286 StartRc(RcFileName); 1287# ifdef UTMPOK 1288# ifndef UTNOKEEP 1289 InitUtmp(); 1290# endif /* UTNOKEEP */ 1291# endif /* UTMPOK */ 1292 if (display) 1293 { 1294 if (InitTermcap(0, 0)) 1295 { 1296 debug("Could not init termcap - exiting\n"); 1297 fcntl(D_userfd, F_SETFL, 0); /* Flush sets FNBLOCK */ 1298 freetty(); 1299 if (D_userpid) 1300 Kill(D_userpid, SIG_BYE); 1301 eexit(1); 1302 } 1303 MakeDefaultCanvas(); 1304 InitTerm(0); 1305#ifdef UTMPOK 1306 RemoveLoginSlot(); 1307#endif 1308 } 1309 else 1310 MakeTermcap(1); 1311#ifdef LOADAV 1312 InitLoadav(); 1313#endif /* LOADAV */ 1314 MakeNewEnv(); 1315 signal(SIGHUP, SigHup); 1316 signal(SIGINT, FinitHandler); 1317 signal(SIGQUIT, FinitHandler); 1318 signal(SIGTERM, FinitHandler); 1319#ifdef BSDJOBS 1320 signal(SIGTTIN, SIG_IGN); 1321 signal(SIGTTOU, SIG_IGN); 1322#endif 1323 1324 if (display) 1325 { 1326 brktty(D_userfd); 1327 SetMode(&D_OldMode, &D_NewMode, D_flow, iflag); 1328 /* Note: SetMode must be called _before_ FinishRc. */ 1329 SetTTY(D_userfd, &D_NewMode); 1330 if (fcntl(D_userfd, F_SETFL, FNBLOCK)) 1331 Msg(errno, "Warning: NBLOCK fcntl failed"); 1332 } 1333 else 1334 brktty(-1); /* just try */ 1335 signal(SIGCHLD, SigChld); 1336#ifdef ETCSCREENRC 1337# ifdef ALLOW_SYSSCREENRC 1338 if ((ap = getenv("SYSSCREENRC"))) 1339 FinishRc(ap); 1340 else 1341# endif 1342 FinishRc(ETCSCREENRC); 1343#endif 1344 FinishRc(RcFileName); 1345 1346 debug2("UID %d EUID %d\n", (int)getuid(), (int)geteuid()); 1347 if (windows == NULL) 1348 { 1349 debug("We open one default window, as screenrc did not specify one.\n"); 1350 if (MakeWindow(&nwin) == -1) 1351 { 1352 Msg(0, "Sorry, could not find a PTY."); 1353 sleep(5); 1354 Finit(0); 1355 /* NOTREACHED */ 1356 } 1357 } 1358 1359#ifdef HAVE_BRAILLE 1360 StartBraille(); 1361#endif 1362 1363 if (display && default_startup) 1364 display_copyright(); 1365 signal(SIGINT, SigInt); 1366 if (rflag && (rflag & 1) == 0) 1367 { 1368 Msg(0, "New screen..."); 1369 rflag = 0; 1370 } 1371 1372 serv_read.type = EV_READ; 1373 serv_read.fd = ServerSocket; 1374 serv_read.handler = serv_read_fn; 1375 evenq(&serv_read); 1376 1377 serv_select.pri = -10; 1378 serv_select.type = EV_ALWAYS; 1379 serv_select.handler = serv_select_fn; 1380 evenq(&serv_select); 1381 1382 logflushev.type = EV_TIMEOUT; 1383 logflushev.handler = logflush_fn; 1384 1385 sched(); 1386 /* NOTREACHED */ 1387 return 0; 1388} 1389 1390void 1391WindowDied(p) 1392struct win *p; 1393{ 1394 if (ZombieKey_destroy) 1395 { 1396 char buf[100], *s; 1397 time_t now; 1398 1399 (void) time(&now); 1400 s = ctime(&now); 1401 if (s && *s) 1402 s[strlen(s) - 1] = '\0'; 1403 debug3("window %d (%s) going into zombie state fd %d", 1404 p->w_number, p->w_title, p->w_ptyfd); 1405#ifdef UTMPOK 1406 if (p->w_slot != (slot_t)0 && p->w_slot != (slot_t)-1) 1407 { 1408 RemoveUtmp(p); 1409 p->w_slot = 0; /* "detached" */ 1410 } 1411#endif 1412 CloseDevice(p); 1413 1414 p->w_pid = 0; 1415 ResetWindow(p); 1416 /* p->w_y = p->w_bot; */ 1417 p->w_y = MFindUsedLine(p, p->w_bot, 1); 1418 sprintf(buf, "\n\r=== Window terminated (%s) ===", s ? s : "?"); 1419 WriteString(p, buf, strlen(buf)); 1420 WindowChanged(p, 'f'); 1421 } 1422 else 1423 KillWindow(p); 1424#ifdef UTMPOK 1425 CarefulUtmp(); 1426#endif 1427} 1428 1429static void 1430SigChldHandler() 1431{ 1432 struct stat st; 1433#ifdef DEBUG 1434 fds(); 1435#endif 1436 while (GotSigChld) 1437 { 1438 GotSigChld = 0; 1439 DoWait(); 1440#ifdef SYSVSIGS 1441 signal(SIGCHLD, SigChld); 1442#endif 1443 } 1444 if (stat(SockPath, &st) == -1) 1445 { 1446 debug1("SigChldHandler: Yuck! cannot stat '%s'\n", SockPath); 1447 if (!RecoverSocket()) 1448 { 1449 debug("SCREEN cannot recover from corrupt Socket, bye\n"); 1450 Finit(1); 1451 } 1452 else 1453 debug1("'%s' reconstructed\n", SockPath); 1454 } 1455 else 1456 debug2("SigChldHandler: stat '%s' o.k. (%03o)\n", SockPath, (int)st.st_mode); 1457} 1458 1459static sigret_t 1460SigChld SIGDEFARG 1461{ 1462 debug("SigChld()\n"); 1463 GotSigChld = 1; 1464 SIGRETURN; 1465} 1466 1467sigret_t 1468SigHup SIGDEFARG 1469{ 1470 /* Hangup all displays */ 1471 while ((display = displays) != 0) 1472 Hangup(); 1473 SIGRETURN; 1474} 1475 1476/* 1477 * the backend's Interrupt handler 1478 * we cannot insert the intrc directly, as we never know 1479 * if fore is valid. 1480 */ 1481static sigret_t 1482SigInt SIGDEFARG 1483{ 1484#if HAZARDOUS 1485 char ibuf; 1486 1487 debug("SigInt()\n"); 1488 if (fore && displays) 1489 { 1490# if defined(TERMIO) || defined(POSIX) 1491 ibuf = displays->d_OldMode.tio.c_cc[VINTR]; 1492# else 1493 ibuf = displays->d_OldMode.m_tchars.t_intrc; 1494# endif 1495 fore->w_inlen = 0; 1496 write(fore->w_ptyfd, &ibuf, 1); 1497 } 1498#else 1499 signal(SIGINT, SigInt); 1500 debug("SigInt() careful\n"); 1501 InterruptPlease = 1; 1502#endif 1503 SIGRETURN; 1504} 1505 1506static sigret_t 1507CoreDump SIGDEFARG 1508{ 1509 struct display *disp; 1510 char buf[80]; 1511 1512#if defined(SYSVSIGS) && defined(SIGHASARG) 1513 signal(sigsig, SIG_IGN); 1514#endif 1515 setgid(getgid()); 1516 setuid(getuid()); 1517 unlink("core"); 1518#ifdef SIGHASARG 1519 sprintf(buf, "\r\n[screen caught signal %d.%s]\r\n", sigsig, 1520#else 1521 sprintf(buf, "\r\n[screen caught a fatal signal.%s]\r\n", 1522#endif 1523#if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW) 1524 "" 1525#else /* SHADOWPW && !DEBUG */ 1526 " (core dumped)" 1527#endif /* SHADOWPW && !DEBUG */ 1528 ); 1529 for (disp = displays; disp; disp = disp->d_next) 1530 { 1531 fcntl(disp->d_userfd, F_SETFL, 0); 1532 SetTTY(disp->d_userfd, &D_OldMode); 1533 write(disp->d_userfd, buf, strlen(buf)); 1534 Kill(disp->d_userpid, SIG_BYE); 1535 } 1536#if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW) 1537 Kill(getpid(), SIGKILL); 1538 eexit(11); 1539#else /* SHADOWPW && !DEBUG */ 1540 abort(); 1541#endif /* SHADOWPW && !DEBUG */ 1542 SIGRETURN; 1543} 1544 1545static void 1546DoWait() 1547{ 1548 register int pid; 1549 struct win *p, *next; 1550#ifdef BSDWAIT 1551 union wait wstat; 1552#else 1553 int wstat; 1554#endif 1555 1556#ifdef BSDJOBS 1557# ifndef BSDWAIT 1558 while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0) 1559# else 1560# ifdef USE_WAIT2 1561 /* 1562 * From: rouilj@sni-usa.com (John Rouillard) 1563 * note that WUNTRACED is not documented to work, but it is defined in 1564 * /usr/include/sys/wait.h, so it may work 1565 */ 1566 while ((pid = wait2(&wstat, WNOHANG | WUNTRACED )) > 0) 1567# else /* USE_WAIT2 */ 1568 while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0) 1569# endif /* USE_WAIT2 */ 1570# endif 1571#else /* BSDJOBS */ 1572 while ((pid = wait(&wstat)) < 0) 1573 if (errno != EINTR) 1574 break; 1575 if (pid > 0) 1576#endif /* BSDJOBS */ 1577 { 1578 for (p = windows; p; p = next) 1579 { 1580 next = p->w_next; 1581 if (pid == p->w_pid) 1582 { 1583#ifdef BSDJOBS 1584 if (WIFSTOPPED(wstat)) 1585 { 1586 debug3("Window %d pid %d: WIFSTOPPED (sig %d)\n", p->w_number, p->w_pid, WSTOPSIG(wstat)); 1587#ifdef SIGTTIN 1588 if (WSTOPSIG(wstat) == SIGTTIN) 1589 { 1590 Msg(0, "Suspended (tty input)"); 1591 continue; 1592 } 1593#endif 1594#ifdef SIGTTOU 1595 if (WSTOPSIG(wstat) == SIGTTOU) 1596 { 1597 Msg(0, "Suspended (tty output)"); 1598 continue; 1599 } 1600#endif 1601 /* Try to restart process */ 1602 Msg(0, "Child has been stopped, restarting."); 1603 if (killpg(p->w_pid, SIGCONT)) 1604 kill(p->w_pid, SIGCONT); 1605 } 1606 else 1607#endif 1608 { 1609 WindowDied(p); 1610 } 1611 break; 1612 } 1613#ifdef PSEUDOS 1614 if (p->w_pwin && pid == p->w_pwin->p_pid) 1615 { 1616 debug2("pseudo of win Nr %d died. pid == %d\n", p->w_number, p->w_pwin->p_pid); 1617 FreePseudowin(p); 1618 break; 1619 } 1620#endif 1621 } 1622 if (p == 0) 1623 { 1624 debug1("pid %d not found - hope that's ok\n", pid); 1625 } 1626 } 1627} 1628 1629 1630static sigret_t 1631FinitHandler SIGDEFARG 1632{ 1633#ifdef SIGHASARG 1634 debug1("FinitHandler called, sig %d.\n", sigsig); 1635#else 1636 debug("FinitHandler called.\n"); 1637#endif 1638 Finit(1); 1639 SIGRETURN; 1640} 1641 1642void 1643Finit(i) 1644int i; 1645{ 1646 struct win *p, *next; 1647 1648 signal(SIGCHLD, SIG_DFL); 1649 signal(SIGHUP, SIG_IGN); 1650 debug1("Finit(%d);\n", i); 1651 for (p = windows; p; p = next) 1652 { 1653 next = p->w_next; 1654 FreeWindow(p); 1655 } 1656 if (ServerSocket != -1) 1657 { 1658 debug1("we unlink(%s)\n", SockPath); 1659#ifdef USE_SETEUID 1660 xseteuid(real_uid); 1661 xsetegid(real_gid); 1662#endif 1663 (void) unlink(SockPath); 1664#ifdef USE_SETEUID 1665 xseteuid(eff_uid); 1666 xsetegid(eff_gid); 1667#endif 1668 } 1669 for (display = displays; display; display = display->d_next) 1670 { 1671 if (D_status) 1672 RemoveStatus(); 1673 FinitTerm(); 1674#ifdef UTMPOK 1675 RestoreLoginSlot(); 1676#endif 1677 AddStr("[screen is terminating]\r\n"); 1678 Flush(); 1679 SetTTY(D_userfd, &D_OldMode); 1680 fcntl(D_userfd, F_SETFL, 0); 1681 freetty(); 1682 Kill(D_userpid, SIG_BYE); 1683 } 1684 /* 1685 * we _cannot_ call eexit(i) here, 1686 * instead of playing with the Socket above. Sigh. 1687 */ 1688 exit(i); 1689} 1690 1691void 1692eexit(e) 1693int e; 1694{ 1695 debug("eexit\n"); 1696 if (ServerSocket != -1) 1697 { 1698 debug1("we unlink(%s)\n", SockPath); 1699 setgid(real_gid); 1700 setuid(real_uid); 1701 (void) unlink(SockPath); 1702 } 1703 exit(e); 1704} 1705 1706void 1707Hangup() 1708{ 1709 if (display == 0) 1710 return; 1711 debug1("Hangup %x\n", display); 1712 if (D_userfd >= 0) 1713 { 1714 close(D_userfd); 1715 D_userfd = -1; 1716 } 1717 if (auto_detach || displays->d_next) 1718 Detach(D_HANGUP); 1719 else 1720 Finit(0); 1721} 1722 1723/* 1724 * Detach now has the following modes: 1725 *D_DETACH SIG_BYE detach backend and exit attacher 1726 *D_HANGUP SIG_BYE detach backend and exit attacher 1727 *D_STOP SIG_STOP stop attacher (and detach backend) 1728 *D_REMOTE SIG_BYE remote detach -- reattach to new attacher 1729 *D_POWER SIG_POWER_BYE power detach -- attacher kills his parent 1730 *D_REMOTE_POWER SIG_POWER_BYE remote power detach -- both 1731 *D_LOCK SIG_LOCK lock the attacher 1732 * (jw) 1733 * we always remove our utmp slots. (even when "lock" or "stop") 1734 * Note: Take extra care here, we may be called by interrupt! 1735 */ 1736void 1737Detach(mode) 1738int mode; 1739{ 1740 int sign = 0, pid; 1741 struct canvas *cv; 1742 struct win *p; 1743 1744 if (display == 0) 1745 return; 1746 1747 signal(SIGHUP, SIG_IGN); 1748 debug1("Detach(%d)\n", mode); 1749 if (D_status) 1750 RemoveStatus(); 1751 FinitTerm(); 1752 if (!display) 1753 return; 1754 switch (mode) 1755 { 1756 case D_HANGUP: 1757 sign = SIG_BYE; 1758 break; 1759 case D_DETACH: 1760 AddStr("[detached]\r\n"); 1761 sign = SIG_BYE; 1762 break; 1763#ifdef BSDJOBS 1764 case D_STOP: 1765 sign = SIG_STOP; 1766 break; 1767#endif 1768#ifdef REMOTE_DETACH 1769 case D_REMOTE: 1770 AddStr("[remote detached]\r\n"); 1771 sign = SIG_BYE; 1772 break; 1773#endif 1774#ifdef POW_DETACH 1775 case D_POWER: 1776 AddStr("[power detached]\r\n"); 1777 if (PowDetachString) 1778 { 1779 AddStr(PowDetachString); 1780 AddStr("\r\n"); 1781 } 1782 sign = SIG_POWER_BYE; 1783 break; 1784#ifdef REMOTE_DETACH 1785 case D_REMOTE_POWER: 1786 AddStr("[remote power detached]\r\n"); 1787 if (PowDetachString) 1788 { 1789 AddStr(PowDetachString); 1790 AddStr("\r\n"); 1791 } 1792 sign = SIG_POWER_BYE; 1793 break; 1794#endif 1795#endif 1796 case D_LOCK: 1797 ClearAll(); 1798 sign = SIG_LOCK; 1799 /* tell attacher to lock terminal with a lockprg. */ 1800 break; 1801 } 1802#ifdef UTMPOK 1803 if (displays->d_next == 0) 1804 { 1805 for (p = windows; p; p = p->w_next) 1806 { 1807 if (p->w_slot != (slot_t) -1 && !(p->w_lflag & 2)) 1808 { 1809 RemoveUtmp(p); 1810 /* 1811 * Set the slot to 0 to get the window 1812 * logged in again. 1813 */ 1814 p->w_slot = (slot_t) 0; 1815 } 1816 } 1817 } 1818 if (mode != D_HANGUP) 1819 RestoreLoginSlot(); 1820#endif 1821 if (displays->d_next == 0 && console_window) 1822 { 1823 if (TtyGrabConsole(console_window->w_ptyfd, 0, "detach")) 1824 { 1825 debug("could not release console - killing window\n"); 1826 KillWindow(console_window); 1827 display = displays; /* restore display */ 1828 } 1829 } 1830 if (D_fore) 1831 { 1832#ifdef MULTIUSER 1833 ReleaseAutoWritelock(display, D_fore); 1834#endif 1835 D_user->u_detachwin = D_fore->w_number; 1836 D_user->u_detachotherwin = D_other ? D_other->w_number : -1; 1837 } 1838 for (cv = D_cvlist; cv; cv = cv->c_next) 1839 { 1840 p = Layer2Window(cv->c_layer); 1841 SetCanvasWindow(cv, 0); 1842 if (p) 1843 WindowChanged(p, 'u'); 1844 } 1845 1846 pid = D_userpid; 1847 debug2("display: %#x displays: %#x\n", (unsigned int)display, (unsigned int)displays); 1848 FreeDisplay(); 1849 if (displays == 0) 1850 /* Flag detached-ness */ 1851 (void) chsock(); 1852 /* 1853 * tell father what to do. We do that after we 1854 * freed the tty, thus getty feels more comfortable on hpux 1855 * if it was a power detach. 1856 */ 1857 Kill(pid, sign); 1858 debug2("Detach: Signal %d to Attacher(%d)!\n", sign, pid); 1859 debug("Detach returns, we are successfully detached.\n"); 1860 signal(SIGHUP, SigHup); 1861} 1862 1863static int 1864IsSymbol(e, s) 1865char *e, *s; 1866{ 1867 register int l; 1868 1869 l = strlen(s); 1870 return strncmp(e, s, l) == 0 && e[l] == '='; 1871} 1872 1873void 1874MakeNewEnv() 1875{ 1876 register char **op, **np; 1877 static char stybuf[MAXSTR]; 1878 1879 for (op = environ; *op; ++op) 1880 ; 1881 if (NewEnv) 1882 free((char *)NewEnv); 1883 NewEnv = np = (char **) malloc((unsigned) (op - environ + 7 + 1) * sizeof(char **)); 1884 if (!NewEnv) 1885 Panic(0, strnomem); 1886 sprintf(stybuf, "STY=%s", strlen(SockName) <= MAXSTR - 5 ? SockName : "?"); 1887 *np++ = stybuf; /* NewEnv[0] */ 1888 *np++ = Term; /* NewEnv[1] */ 1889 np++; /* room for SHELL */ 1890#ifdef TIOCSWINSZ 1891 np += 2; /* room for TERMCAP and WINDOW */ 1892#else 1893 np += 4; /* room for TERMCAP WINDOW LINES COLUMNS */ 1894#endif 1895 1896 for (op = environ; *op; ++op) 1897 { 1898 if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP") 1899 && !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW") 1900 && !IsSymbol(*op, "SCREENCAP") && !IsSymbol(*op, "SHELL") 1901 && !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS") 1902 ) 1903 *np++ = *op; 1904 } 1905 *np = 0; 1906} 1907 1908void 1909/*VARARGS2*/ 1910#if defined(USEVARARGS) && defined(__STDC__) 1911Msg(int err, char *fmt, VA_DOTS) 1912#else 1913Msg(err, fmt, VA_DOTS) 1914int err; 1915char *fmt; 1916VA_DECL 1917#endif 1918{ 1919 VA_LIST(ap) 1920 char buf[MAXPATHLEN*2]; 1921 char *p = buf; 1922 1923 VA_START(ap, fmt); 1924 fmt = DoNLS(fmt); 1925 (void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap)); 1926 VA_END(ap); 1927 if (err) 1928 { 1929 p += strlen(p); 1930 *p++ = ':'; 1931 *p++ = ' '; 1932 strncpy(p, strerror(err), buf + sizeof(buf) - p - 1); 1933 buf[sizeof(buf) - 1] = 0; 1934 } 1935 debug2("Msg('%s') (%#x);\n", buf, (unsigned int)display); 1936 1937 if (display && displays) 1938 MakeStatus(buf); 1939 else if (displays) 1940 { 1941 for (display = displays; display; display = display->d_next) 1942 MakeStatus(buf); 1943 } 1944 else if (display) 1945 { 1946 /* no displays but a display - must have forked. 1947 * send message to backend! 1948 */ 1949 char *tty = D_usertty; 1950 struct display *olddisplay = display; 1951 display = 0; /* only send once */ 1952 SendErrorMsg(tty, buf); 1953 display = olddisplay; 1954 } 1955 else 1956 printf("%s\r\n", buf); 1957} 1958 1959/* 1960 * Call FinitTerm for all displays, write a message to each and call eexit(); 1961 */ 1962void 1963/*VARARGS2*/ 1964#if defined(USEVARARGS) && defined(__STDC__) 1965Panic(int err, char *fmt, VA_DOTS) 1966#else 1967Panic(err, fmt, VA_DOTS) 1968int err; 1969char *fmt; 1970VA_DECL 1971#endif 1972{ 1973 VA_LIST(ap) 1974 char buf[MAXPATHLEN*2]; 1975 char *p = buf; 1976 1977 VA_START(ap, fmt); 1978 fmt = DoNLS(fmt); 1979 (void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap)); 1980 VA_END(ap); 1981 if (err) 1982 { 1983 p += strlen(p); 1984 *p++ = ':'; 1985 *p++ = ' '; 1986 strncpy(p, strerror(err), buf + sizeof(buf) - p - 1); 1987 buf[sizeof(buf) - 1] = 0; 1988 } 1989 debug3("Panic('%s'); display=%x displays=%x\n", buf, display, displays); 1990 if (displays == 0 && display == 0) 1991 printf("%s\r\n", buf); 1992 else if (displays == 0) 1993 { 1994 /* no displays but a display - must have forked. 1995 * send message to backend! 1996 */ 1997 char *tty = D_usertty; 1998 display = 0; 1999 SendErrorMsg(tty, buf); 2000 sleep(2); 2001 _exit(1); 2002 } 2003 else 2004 for (display = displays; display; display = display->d_next) 2005 { 2006 if (D_status) 2007 RemoveStatus(); 2008 FinitTerm(); 2009 Flush(); 2010#ifdef UTMPOK 2011 RestoreLoginSlot(); 2012#endif 2013 SetTTY(D_userfd, &D_OldMode); 2014 fcntl(D_userfd, F_SETFL, 0); 2015 write(D_userfd, buf, strlen(buf)); 2016 write(D_userfd, "\n", 1); 2017 freetty(); 2018 if (D_userpid) 2019 Kill(D_userpid, SIG_BYE); 2020 } 2021#ifdef MULTIUSER 2022 if (tty_oldmode >= 0) 2023 { 2024# ifdef USE_SETEUID 2025 if (setuid(own_uid)) 2026 xseteuid(own_uid); /* may be a loop. sigh. */ 2027# else 2028 setuid(own_uid); 2029# endif 2030 debug1("Panic: changing back modes from %s\n", attach_tty); 2031 chmod(attach_tty, tty_oldmode); 2032 } 2033#endif 2034 eexit(1); 2035} 2036 2037 2038/* 2039 * '^' is allowed as an escape mechanism for control characters. jw. 2040 * 2041 * Added time insertion using ideas/code from /\ndy Jones 2042 * (andy@lingua.cltr.uq.OZ.AU) - thanks a lot! 2043 * 2044 */ 2045 2046#ifndef USE_LOCALE 2047static const char days[] = "SunMonTueWedThuFriSat"; 2048static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec"; 2049#endif 2050 2051static char winmsg_buf[MAXSTR]; 2052#define MAX_WINMSG_REND 16 /* rendition changes */ 2053static int winmsg_rend[MAX_WINMSG_REND]; 2054static int winmsg_rendpos[MAX_WINMSG_REND]; 2055static int winmsg_numrend; 2056 2057static char * 2058pad_expand(buf, p, numpad, padlen) 2059char *buf; 2060char *p; 2061int numpad; 2062int padlen; 2063{ 2064 char *pn, *pn2; 2065 int i, r; 2066 2067 padlen = padlen - (p - buf); /* space for rent */ 2068 if (padlen < 0) 2069 padlen = 0; 2070 pn2 = pn = p + padlen; 2071 r = winmsg_numrend; 2072 while (p >= buf) 2073 { 2074 if (r && p - buf == winmsg_rendpos[r - 1]) 2075 { 2076 winmsg_rendpos[--r] = pn - buf; 2077 continue; 2078 } 2079 *pn-- = *p; 2080 if (*p-- == 127) 2081 { 2082 pn[1] = ' '; 2083 i = numpad > 0 ? (padlen + numpad - 1) / numpad : 0; 2084 padlen -= i; 2085 while (i-- > 0) 2086 *pn-- = ' '; 2087 numpad--; 2088 } 2089 } 2090 return pn2; 2091} 2092 2093struct backtick { 2094 struct backtick *next; 2095 int num; 2096 int tick; 2097 int lifespan; 2098 time_t bestbefore; 2099 char result[MAXSTR]; 2100 char **cmdv; 2101 struct event ev; 2102 char *buf; 2103 int bufi; 2104}; 2105 2106struct backtick *backticks; 2107 2108static void 2109backtick_filter(bt) 2110struct backtick *bt; 2111{ 2112 char *p, *q; 2113 int c; 2114 2115 for (p = q = bt->result; (c = (unsigned char)*p++) != 0;) 2116 { 2117 if (c == '\t') 2118 c = ' '; 2119 if (c >= ' ' || c == '\005') 2120 *q++ = c; 2121 } 2122 *q = 0; 2123} 2124 2125static void 2126backtick_fn(ev, data) 2127struct event *ev; 2128char *data; 2129{ 2130 struct backtick *bt; 2131 int i, j, k, l; 2132 2133 bt = (struct backtick *)data; 2134 debug1("backtick_fn for #%d\n", bt->num); 2135 i = bt->bufi; 2136 l = read(ev->fd, bt->buf + i, MAXSTR - i); 2137 if (l <= 0) 2138 { 2139 debug1("EOF on backtick #%d\n", bt->num); 2140 evdeq(ev); 2141 close(ev->fd); 2142 ev->fd = -1; 2143 return; 2144 } 2145 debug1("read %d bytes\n", l); 2146 i += l; 2147 for (j = 0; j < l; j++) 2148 if (bt->buf[i - j - 1] == '\n') 2149 break; 2150 if (j < l) 2151 { 2152 for (k = i - j - 2; k >= 0; k--) 2153 if (bt->buf[k] == '\n') 2154 break; 2155 k++; 2156 bcopy(bt->buf + k, bt->result, i - j - k); 2157 bt->result[i - j - k - 1] = 0; 2158 backtick_filter(bt); 2159 WindowChanged(0, '`'); 2160 } 2161 if (j == l && i == MAXSTR) 2162 { 2163 j = MAXSTR/2; 2164 l = j + 1; 2165 } 2166 if (j < l) 2167 { 2168 if (j) 2169 bcopy(bt->buf + i - j, bt->buf, j); 2170 i = j; 2171 } 2172 bt->bufi = i; 2173} 2174 2175void 2176setbacktick(num, lifespan, tick, cmdv) 2177int num; 2178int lifespan; 2179int tick; 2180char **cmdv; 2181{ 2182 struct backtick **btp, *bt; 2183 char **v; 2184 2185 debug1("setbacktick called for backtick #%d\n", num); 2186 for (btp = &backticks; (bt = *btp) != 0; btp = &bt->next) 2187 if (bt->num == num) 2188 break; 2189 if (!bt && !cmdv) 2190 return; 2191 if (bt) 2192 { 2193 for (v = bt->cmdv; *v; v++) 2194 free(*v); 2195 free(bt->cmdv); 2196 if (bt->buf) 2197 free(bt->buf); 2198 if (bt->ev.fd >= 0) 2199 close(bt->ev.fd); 2200 evdeq(&bt->ev); 2201 } 2202 if (bt && !cmdv) 2203 { 2204 *btp = bt->next; 2205 free(bt); 2206 return; 2207 } 2208 if (!bt) 2209 { 2210 bt = (struct backtick *)malloc(sizeof *bt); 2211 if (!bt) 2212 { 2213 Msg(0, strnomem); 2214 return; 2215 } 2216 bzero(bt, sizeof(*bt)); 2217 bt->next = 0; 2218 *btp = bt; 2219 } 2220 bt->num = num; 2221 bt->tick = tick; 2222 bt->lifespan = lifespan; 2223 bt->bestbefore = 0; 2224 bt->result[0] = 0; 2225 bt->buf = 0; 2226 bt->bufi = 0; 2227 bt->cmdv = cmdv; 2228 bt->ev.fd = -1; 2229 if (bt->tick == 0 && bt->lifespan == 0) 2230 { 2231 debug("setbacktick: continuous mode\n"); 2232 bt->buf = (char *)malloc(MAXSTR); 2233 if (bt->buf == 0) 2234 { 2235 Msg(0, strnomem); 2236 setbacktick(num, 0, 0, (char **)0); 2237 return; 2238 } 2239 bt->ev.type = EV_READ; 2240 bt->ev.fd = readpipe(bt->cmdv); 2241 bt->ev.handler = backtick_fn; 2242 bt->ev.data = (char *)bt; 2243 if (bt->ev.fd >= 0) 2244 evenq(&bt->ev); 2245 } 2246} 2247 2248static char * 2249runbacktick(bt, tickp, now) 2250struct backtick *bt; 2251int *tickp; 2252time_t now; 2253{ 2254 int f, i, l, j; 2255 time_t now2; 2256 2257 debug1("runbacktick called for backtick #%d\n", bt->num); 2258 if (bt->tick && (!*tickp || bt->tick < *tickp)) 2259 *tickp = bt->tick; 2260 if ((bt->lifespan == 0 && bt->tick == 0) || now < bt->bestbefore) 2261 { 2262 debug1("returning old result (%d)\n", bt->lifespan); 2263 return bt->result; 2264 } 2265 f = readpipe(bt->cmdv); 2266 if (f == -1) 2267 return bt->result; 2268 i = 0; 2269 while ((l = read(f, bt->result + i, sizeof(bt->result) - i)) > 0) 2270 { 2271 debug1("runbacktick: read %d bytes\n", l); 2272 i += l; 2273 for (j = 1; j < l; j++) 2274 if (bt->result[i - j - 1] == '\n') 2275 break; 2276 if (j == l && i == sizeof(bt->result)) 2277 { 2278 j = sizeof(bt->result) / 2; 2279 l = j + 1; 2280 } 2281 if (j < l) 2282 { 2283 bcopy(bt->result + i - j, bt->result, j); 2284 i = j; 2285 } 2286 } 2287 close(f); 2288 bt->result[sizeof(bt->result) - 1] = '\n'; 2289 if (i && bt->result[i - 1] == '\n') 2290 i--; 2291 debug1("runbacktick: finished, %d bytes\n", i); 2292 bt->result[i] = 0; 2293 backtick_filter(bt); 2294 (void)time(&now2); 2295 bt->bestbefore = now2 + bt->lifespan; 2296 return bt->result; 2297} 2298 2299char * 2300MakeWinMsgEv(str, win, esc, padlen, ev, rec) 2301char *str; 2302struct win *win; 2303int esc; 2304int padlen; 2305struct event *ev; 2306int rec; 2307{ 2308 static int tick; 2309 char *s = str; 2310 register char *p = winmsg_buf; 2311 register int ctrl; 2312 struct timeval now; 2313 struct tm *tm; 2314 int l, i, r; 2315 int num; 2316 int zeroflg; 2317 int longflg; 2318 int minusflg; 2319 int plusflg; 2320 int qmflag = 0, omflag = 0, qmnumrend = 0; 2321 char *qmpos = 0; 2322 int numpad = 0; 2323 int lastpad = 0; 2324 int truncpos = -1; 2325 int truncper = 0; 2326 int trunclong = 0; 2327 struct backtick *bt; 2328 2329 if (winmsg_numrend >= 0) 2330 winmsg_numrend = 0; 2331 else 2332 winmsg_numrend = -winmsg_numrend; 2333 2334 tick = 0; 2335 tm = 0; 2336 ctrl = 0; 2337 gettimeofday(&now, NULL); 2338 for (; *s && (l = winmsg_buf + MAXSTR - 1 - p) > 0; s++, p++) 2339 { 2340 *p = *s; 2341 if (ctrl) 2342 { 2343 ctrl = 0; 2344 if (*s != '^' && *s >= 64) 2345 *p &= 0x1f; 2346 continue; 2347 } 2348 if (*s != esc) 2349 { 2350 if (esc == '%') 2351 { 2352 switch (*s) 2353 { 2354#if 0 2355 case '~': 2356 *p = BELL; 2357 break; 2358#endif 2359 case '^': 2360 ctrl = 1; 2361 *p-- = '^'; 2362 break; 2363 default: 2364 break; 2365 } 2366 } 2367 continue; 2368 } 2369 if (*++s == esc) /* double escape ? */ 2370 continue; 2371 if ((plusflg = *s == '+') != 0) 2372 s++; 2373 if ((minusflg = *s == '-') != 0) 2374 s++; 2375 if ((zeroflg = *s == '0') != 0) 2376 s++; 2377 num = 0; 2378 while(*s >= '0' && *s <= '9') 2379 num = num * 10 + (*s++ - '0'); 2380 if ((longflg = *s == 'L') != 0) 2381 s++; 2382 switch (*s) 2383 { 2384 case '?': 2385 p--; 2386 if (qmpos) 2387 { 2388 if ((!qmflag && !omflag) || omflag == 1) 2389 { 2390 p = qmpos; 2391 if (qmnumrend < winmsg_numrend) 2392 winmsg_numrend = qmnumrend; 2393 } 2394 qmpos = 0; 2395 break; 2396 } 2397 qmpos = p; 2398 qmnumrend = winmsg_numrend; 2399 qmflag = omflag = 0; 2400 break; 2401 case ':': 2402 p--; 2403 if (!qmpos) 2404 break; 2405 if (qmflag && omflag != 1) 2406 { 2407 omflag = 1; 2408 qmpos = p; 2409 qmnumrend = winmsg_numrend; 2410 } 2411 else 2412 { 2413 p = qmpos; 2414 if (qmnumrend < winmsg_numrend) 2415 winmsg_numrend = qmnumrend; 2416 omflag = -1; 2417 } 2418 break; 2419 case 'd': case 'D': case 'm': case 'M': case 'y': case 'Y': 2420 case 'a': case 'A': case 's': case 'c': case 'C': 2421 if (l < 4) 2422 break; 2423 if (tm == 0) 2424 { 2425 time_t nowsec = now.tv_sec; 2426 tm = localtime(&nowsec); 2427 } 2428 qmflag = 1; 2429 if (!tick || tick > 3600) 2430 tick = 3600; 2431 switch (*s) 2432 { 2433 case 'd': 2434 sprintf(p, "%02d", tm->tm_mday % 100); 2435 break; 2436 case 'D': 2437#ifdef USE_LOCALE 2438 strftime(p, l, (longflg ? "%A" : "%a"), tm); 2439#else 2440 sprintf(p, "%3.3s", days + 3 * tm->tm_wday); 2441#endif 2442 break; 2443 case 'm': 2444 sprintf(p, "%02d", tm->tm_mon + 1); 2445 break; 2446 case 'M': 2447#ifdef USE_LOCALE 2448 strftime(p, l, (longflg ? "%B" : "%b"), tm); 2449#else 2450 sprintf(p, "%3.3s", months + 3 * tm->tm_mon); 2451#endif 2452 break; 2453 case 'y': 2454 sprintf(p, "%02d", tm->tm_year % 100); 2455 break; 2456 case 'Y': 2457 sprintf(p, "%04d", tm->tm_year + 1900); 2458 break; 2459 case 'a': 2460 sprintf(p, tm->tm_hour >= 12 ? "pm" : "am"); 2461 break; 2462 case 'A': 2463 sprintf(p, tm->tm_hour >= 12 ? "PM" : "AM"); 2464 break; 2465 case 's': 2466 sprintf(p, "%02d", tm->tm_sec); 2467 tick = 1; 2468 break; 2469 case 'c': 2470 sprintf(p, zeroflg ? "%02d:%02d" : "%2d:%02d", tm->tm_hour, tm->tm_min); 2471 if (!tick || tick > 60) 2472 tick = 60; 2473 break; 2474 case 'C': 2475 sprintf(p, zeroflg ? "%02d:%02d" : "%2d:%02d", (tm->tm_hour + 11) % 12 + 1, tm->tm_min); 2476 if (!tick || tick > 60) 2477 tick = 60; 2478 break; 2479 default: 2480 break; 2481 } 2482 p += strlen(p) - 1; 2483 break; 2484 case 'l': 2485#ifdef LOADAV 2486 *p = 0; 2487 if (l > 20) 2488 AddLoadav(p); 2489 if (*p) 2490 { 2491 qmflag = 1; 2492 p += strlen(p) - 1; 2493 } 2494 else 2495 *p = '?'; 2496 if (!tick || tick > 60) 2497 tick = 60; 2498#else 2499 *p = '?'; 2500#endif 2501 p += strlen(p) - 1; 2502 break; 2503 case '`': 2504 case 'h': 2505 if (rec >= 10 || (*s == 'h' && (win == 0 || win->w_hstatus == 0 || *win->w_hstatus == 0))) 2506 { 2507 p--; 2508 break; 2509 } 2510 if (*s == '`') 2511 { 2512 for (bt = backticks; bt; bt = bt->next) 2513 if (bt->num == num) 2514 break; 2515 if (bt == 0) 2516 { 2517 p--; 2518 break; 2519 } 2520 } 2521 { 2522 char savebuf[sizeof(winmsg_buf)]; 2523 int oldtick = tick; 2524 int oldnumrend = winmsg_numrend; 2525 2526 *p = 0; 2527 strcpy(savebuf, winmsg_buf); 2528 winmsg_numrend = -winmsg_numrend; 2529 MakeWinMsgEv(*s == 'h' ? win->w_hstatus : runbacktick(bt, &oldtick, now.tv_sec), win, '\005', 0, (struct event *)0, rec + 1); 2530 debug2("oldtick=%d tick=%d\n", oldtick, tick); 2531 if (!tick || oldtick < tick) 2532 tick = oldtick; 2533 if ((int)strlen(winmsg_buf) < l) 2534 strcat(savebuf, winmsg_buf); 2535 strcpy(winmsg_buf, savebuf); 2536 while (oldnumrend < winmsg_numrend) 2537 winmsg_rendpos[oldnumrend++] += p - winmsg_buf; 2538 if (*p) 2539 qmflag = 1; 2540 p += strlen(p) - 1; 2541 } 2542 break; 2543 case 'w': 2544 case 'W': 2545 { 2546 struct win *oldfore = 0; 2547 char *ss; 2548 2549 if (display) 2550 { 2551 oldfore = D_fore; 2552 D_fore = win; 2553 } 2554 ss = AddWindows(p, l - 1, (*s == 'w' ? 0 : 1) | (longflg ? 0 : 2) | (plusflg ? 4 : 0), win ? win->w_number : -1); 2555 if (minusflg) 2556 *ss = 0; 2557 if (display) 2558 D_fore = oldfore; 2559 } 2560 if (*p) 2561 qmflag = 1; 2562 p += strlen(p) - 1; 2563 break; 2564 case 'u': 2565 *p = 0; 2566 if (win) 2567 AddOtherUsers(p, l - 1, win); 2568 if (*p) 2569 qmflag = 1; 2570 p += strlen(p) - 1; 2571 break; 2572 case 'f': 2573 *p = 0; 2574 if (win) 2575 AddWindowFlags(p, l - 1, win); 2576 if (*p) 2577 qmflag = 1; 2578 p += strlen(p) - 1; 2579 break; 2580 case 't': 2581 *p = 0; 2582 if (win && (int)strlen(win->w_title) < l) 2583 { 2584 strcpy(p, win->w_title); 2585 if (*p) 2586 qmflag = 1; 2587 } 2588 p += strlen(p) - 1; 2589 break; 2590 case '{': 2591 { 2592 char rbuf[128]; 2593 s++; 2594 for (i = 0; i < 127; i++) 2595 if (s[i] && s[i] != '}') 2596 rbuf[i] = s[i]; 2597 else 2598 break; 2599 if (s[i] == '}' && winmsg_numrend < MAX_WINMSG_REND) 2600 { 2601 r = -1; 2602 rbuf[i] = 0; 2603 debug1("MakeWinMsg attrcolor %s\n", rbuf); 2604 if (i != 1 || rbuf[0] != '-') 2605 r = ParseAttrColor(rbuf, (char *)0, 0); 2606 if (r != -1 || (i == 1 && rbuf[0] == '-')) 2607 { 2608 winmsg_rend[winmsg_numrend] = r; 2609 winmsg_rendpos[winmsg_numrend] = p - winmsg_buf; 2610 winmsg_numrend++; 2611 } 2612 } 2613 s += i; 2614 p--; 2615 } 2616 break; 2617 case 'H': 2618 *p = 0; 2619 if ((int)strlen(HostName) < l) 2620 { 2621 strcpy(p, HostName); 2622 if (*p) 2623 qmflag = 1; 2624 } 2625 p += strlen(p) - 1; 2626 break; 2627 case 'F': 2628 p--; 2629 /* small hack */ 2630 if (display && ((ev && ev == &D_forecv->c_captev) || (!ev && win && win == D_fore))) 2631 qmflag = 1; 2632 break; 2633 case '>': 2634 truncpos = p - winmsg_buf; 2635 truncper = num > 100 ? 100 : num; 2636 trunclong = longflg; 2637 p--; 2638 break; 2639 case '=': 2640 case '<': 2641 *p = ' '; 2642 if (num || zeroflg || plusflg || longflg || (*s != '=')) 2643 { 2644 /* expand all pads */ 2645 if (minusflg) 2646 { 2647 num = (plusflg ? lastpad : padlen) - num; 2648 if (!plusflg && padlen == 0) 2649 num = p - winmsg_buf; 2650 plusflg = 0; 2651 } 2652 else if (!zeroflg) 2653 { 2654 if (*s != '=' && num == 0 && !plusflg) 2655 num = 100; 2656 if (num > 100) 2657 num = 100; 2658 if (padlen == 0) 2659 num = p - winmsg_buf; 2660 else 2661 num = (padlen - (plusflg ? lastpad : 0)) * num / 100; 2662 } 2663 if (num < 0) 2664 num = 0; 2665 if (plusflg) 2666 num += lastpad; 2667 if (num > MAXSTR - 1) 2668 num = MAXSTR - 1; 2669 if (numpad) 2670 p = pad_expand(winmsg_buf, p, numpad, num); 2671 numpad = 0; 2672 if (p - winmsg_buf > num && !longflg) 2673 { 2674 int left, trunc; 2675 2676 if (truncpos == -1) 2677 { 2678 truncpos = lastpad; 2679 truncper = 0; 2680 } 2681 trunc = lastpad + truncper * (num - lastpad) / 100; 2682 if (trunc > num) 2683 trunc = num; 2684 if (trunc < lastpad) 2685 trunc = lastpad; 2686 left = truncpos - trunc; 2687 if (left > p - winmsg_buf - num) 2688 left = p - winmsg_buf - num; 2689 debug1("lastpad = %d, ", lastpad); 2690 debug3("truncpos = %d, trunc = %d, left = %d\n", truncpos, trunc, left); 2691 if (left > 0) 2692 { 2693 if (left + lastpad > p - winmsg_buf) 2694 left = p - winmsg_buf - lastpad; 2695 if (p - winmsg_buf - lastpad - left > 0) 2696 bcopy(winmsg_buf + lastpad + left, winmsg_buf + lastpad, p - winmsg_buf - lastpad - left); 2697 p -= left; 2698 r = winmsg_numrend; 2699 while (r && winmsg_rendpos[r - 1] > lastpad) 2700 { 2701 r--; 2702 winmsg_rendpos[r] -= left; 2703 if (winmsg_rendpos[r] < lastpad) 2704 winmsg_rendpos[r] = lastpad; 2705 } 2706 if (trunclong) 2707 { 2708 if (p - winmsg_buf > lastpad) 2709 winmsg_buf[lastpad] = '.'; 2710 if (p - winmsg_buf > lastpad + 1) 2711 winmsg_buf[lastpad + 1] = '.'; 2712 if (p - winmsg_buf > lastpad + 2) 2713 winmsg_buf[lastpad + 2] = '.'; 2714 } 2715 } 2716 if (p - winmsg_buf > num) 2717 { 2718 p = winmsg_buf + num; 2719 if (trunclong) 2720 { 2721 if (num - 1 >= lastpad) 2722 p[-1] = '.'; 2723 if (num - 2 >= lastpad) 2724 p[-2] = '.'; 2725 if (num - 3 >= lastpad) 2726 p[-3] = '.'; 2727 } 2728 r = winmsg_numrend; 2729 while (r && winmsg_rendpos[r - 1] > num) 2730 winmsg_rendpos[--r] = num; 2731 } 2732 truncpos = -1; 2733 trunclong = 0; 2734 if (lastpad > p - winmsg_buf) 2735 lastpad = p - winmsg_buf; 2736 debug1("lastpad now %d\n", lastpad); 2737 } 2738 if (*s == '=') 2739 { 2740 while (p - winmsg_buf < num) 2741 *p++ = ' '; 2742 lastpad = p - winmsg_buf; 2743 truncpos = -1; 2744 trunclong = 0; 2745 debug1("lastpad2 now %d\n", lastpad); 2746 } 2747 p--; 2748 } 2749 else if (padlen) 2750 { 2751 *p = 127; /* internal pad representation */ 2752 numpad++; 2753 } 2754 break; 2755 case 'n': 2756 s++; 2757 /* FALLTHROUGH */ 2758 default: 2759 s--; 2760 if (l > 10 + num) 2761 { 2762 if (num == 0) 2763 num = 1; 2764 if (!win) 2765 sprintf(p, "%*s", num, num > 1 ? "--" : "-"); 2766 else 2767 sprintf(p, "%*d", num, win->w_number); 2768 qmflag = 1; 2769 p += strlen(p) - 1; 2770 } 2771 break; 2772 } 2773 } 2774 if (qmpos && !qmflag) 2775 p = qmpos + 1; 2776 *p = '\0'; 2777 if (numpad) 2778 { 2779 if (padlen > MAXSTR - 1) 2780 padlen = MAXSTR - 1; 2781 p = pad_expand(winmsg_buf, p, numpad, padlen); 2782 } 2783 if (ev) 2784 { 2785 evdeq(ev); /* just in case */ 2786 ev->timeout.tv_sec = 0; 2787 ev->timeout.tv_usec = 0; 2788 } 2789 if (ev && tick) 2790 { 2791 now.tv_usec = 100000; 2792 if (tick == 1) 2793 now.tv_sec++; 2794 else 2795 now.tv_sec += tick - (now.tv_sec % tick); 2796 ev->timeout = now; 2797 debug2("NEW timeout %d %d\n", ev->timeout.tv_sec, tick); 2798 } 2799 return winmsg_buf; 2800} 2801 2802char * 2803MakeWinMsg(s, win, esc) 2804char *s; 2805struct win *win; 2806int esc; 2807{ 2808 return MakeWinMsgEv(s, win, esc, 0, (struct event *)0, 0); 2809} 2810 2811int 2812PutWinMsg(s, start, max) 2813char *s; 2814int start, max; 2815{ 2816 int i, p, l, r, n; 2817 struct mchar rend; 2818 struct mchar rendstack[MAX_WINMSG_REND]; 2819 int rendstackn = 0; 2820 2821 if (s != winmsg_buf) 2822 return 0; 2823 rend = D_rend; 2824 p = 0; 2825 l = strlen(s); 2826 debug2("PutWinMsg %s start attr %x\n", s, rend.attr); 2827 for (i = 0; i < winmsg_numrend && max > 0; i++) 2828 { 2829 if (p > winmsg_rendpos[i] || winmsg_rendpos[i] > l) 2830 break; 2831 if (p < winmsg_rendpos[i]) 2832 { 2833 n = winmsg_rendpos[i] - p; 2834 if (n > max) 2835 n = max; 2836 max -= n; 2837 p += n; 2838 while(n-- > 0) 2839 { 2840 if (start-- > 0) 2841 s++; 2842 else 2843 PUTCHARLP(*s++); 2844 } 2845 } 2846 r = winmsg_rend[i]; 2847 if (r == -1) 2848 { 2849 if (rendstackn > 0) 2850 rend = rendstack[--rendstackn]; 2851 } 2852 else 2853 { 2854 rendstack[rendstackn++] = rend; 2855 ApplyAttrColor(r, &rend); 2856 } 2857 SetRendition(&rend); 2858 } 2859 if (p < l) 2860 { 2861 n = l - p; 2862 if (n > max) 2863 n = max; 2864 while(n-- > 0) 2865 { 2866 if (start-- > 0) 2867 s++; 2868 else 2869 PUTCHARLP(*s++); 2870 } 2871 } 2872 return 1; 2873} 2874 2875 2876#ifdef DEBUG 2877static void 2878fds1(i, j) 2879int i, j; 2880{ 2881 while (i < j) 2882 { 2883 debug1("%d ", i); 2884 i++; 2885 } 2886 if ((j = open("/dev/null", 0)) >= 0) 2887 { 2888 fds1(i + 1, j); 2889 close(j); 2890 } 2891 else 2892 { 2893 while (dup(++i) < 0 && errno != EBADF) 2894 debug1("%d ", i); 2895 debug1(" [%d]\n", i); 2896 } 2897} 2898 2899static void 2900fds() 2901{ 2902 debug("fds: "); 2903 fds1(-1, -1); 2904} 2905#endif 2906 2907static void 2908serv_read_fn(ev, data) 2909struct event *ev; 2910char *data; 2911{ 2912 debug("Knock - knock!\n"); 2913 ReceiveMsg(); 2914} 2915 2916static void 2917serv_select_fn(ev, data) 2918struct event *ev; 2919char *data; 2920{ 2921 struct win *p; 2922 2923 debug("serv_select_fn called\n"); 2924 /* XXX: messages?? */ 2925 if (GotSigChld) 2926 { 2927 SigChldHandler(); 2928 } 2929 if (InterruptPlease) 2930 { 2931 debug("Backend received interrupt\n"); 2932 /* This approach is rather questionable in a multi-display 2933 * environment */ 2934 if (fore && displays) 2935 { 2936#if defined(TERMIO) || defined(POSIX) 2937 char ibuf = displays->d_OldMode.tio.c_cc[VINTR]; 2938#else 2939 char ibuf = displays->d_OldMode.m_tchars.t_intrc; 2940#endif 2941#ifdef PSEUDOS 2942 write(W_UWP(fore) ? fore->w_pwin->p_ptyfd : fore->w_ptyfd, 2943 &ibuf, 1); 2944 debug1("Backend wrote interrupt to %d", fore->w_number); 2945 debug1("%s\n", W_UWP(fore) ? " (pseudowin)" : ""); 2946#else 2947 write(fore->w_ptyfd, &ibuf, 1); 2948 debug1("Backend wrote interrupt to %d\n", fore->w_number); 2949#endif 2950 } 2951 InterruptPlease = 0; 2952 } 2953 2954 for (p = windows; p; p = p->w_next) 2955 { 2956 if (p->w_bell == BELL_FOUND || p->w_bell == BELL_VISUAL) 2957 { 2958 struct canvas *cv; 2959 int visual = p->w_bell == BELL_VISUAL || visual_bell; 2960 p->w_bell = BELL_ON; 2961 for (display = displays; display; display = display->d_next) 2962 { 2963 for (cv = D_cvlist; cv; cv = cv->c_next) 2964 if (cv->c_layer->l_bottom == &p->w_layer) 2965 break; 2966 if (cv == 0) 2967 { 2968 p->w_bell = BELL_DONE; 2969 Msg(0, "%s", MakeWinMsg(BellString, p, '%')); 2970 } 2971 else if (visual && !D_VB && (!D_status || !D_status_bell)) 2972 { 2973 Msg(0, "%s", VisualBellString); 2974 if (D_status) 2975 { 2976 D_status_bell = 1; 2977 debug1("using vbell timeout %d\n", VBellWait); 2978 SetTimeout(&D_statusev, VBellWait ); 2979 } 2980 } 2981 } 2982 /* don't annoy the user with two messages */ 2983 if (p->w_monitor == MON_FOUND) 2984 p->w_monitor = MON_DONE; 2985 WindowChanged(p, 'f'); 2986 } 2987 if (p->w_monitor == MON_FOUND) 2988 { 2989 struct canvas *cv; 2990 p->w_monitor = MON_ON; 2991 for (display = displays; display; display = display->d_next) 2992 { 2993 for (cv = D_cvlist; cv; cv = cv->c_next) 2994 if (cv->c_layer->l_bottom == &p->w_layer) 2995 break; 2996 if (cv) 2997 continue; /* user already sees window */ 2998#ifdef MULTIUSER 2999 if (!(ACLBYTE(p->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id))) 3000 continue; /* user doesn't care */ 3001#endif 3002 Msg(0, "%s", MakeWinMsg(ActivityString, p, '%')); 3003 p->w_monitor = MON_DONE; 3004 } 3005 WindowChanged(p, 'f'); 3006 } 3007 } 3008 3009 for (display = displays; display; display = display->d_next) 3010 { 3011 struct canvas *cv; 3012 if (D_status == STATUS_ON_WIN) 3013 continue; 3014 /* XXX: should use display functions! */ 3015 for (cv = D_cvlist; cv; cv = cv->c_next) 3016 { 3017 int lx, ly; 3018 3019 /* normalize window, see resize.c */ 3020 lx = cv->c_layer->l_x; 3021 ly = cv->c_layer->l_y; 3022 if (lx == cv->c_layer->l_width) 3023 lx--; 3024 if (ly + cv->c_yoff < cv->c_ys) 3025 { 3026 int i, n = cv->c_ys - (ly + cv->c_yoff); 3027 cv->c_yoff = cv->c_ys - ly; 3028 RethinkViewportOffsets(cv); 3029 if (n > cv->c_layer->l_height) 3030 n = cv->c_layer->l_height; 3031 CV_CALL(cv, 3032 LScrollV(flayer, -n, 0, flayer->l_height - 1, 0); 3033 LayRedisplayLine(-1, -1, -1, 1); 3034 for (i = 0; i < n; i++) 3035 LayRedisplayLine(i, 0, flayer->l_width - 1, 1); 3036 if (cv == cv->c_display->d_forecv) 3037 LaySetCursor(); 3038 ); 3039 } 3040 else if (ly + cv->c_yoff > cv->c_ye) 3041 { 3042 int i, n = ly + cv->c_yoff - cv->c_ye; 3043 cv->c_yoff = cv->c_ye - ly; 3044 RethinkViewportOffsets(cv); 3045 if (n > cv->c_layer->l_height) 3046 n = cv->c_layer->l_height; 3047 CV_CALL(cv, 3048 LScrollV(flayer, n, 0, cv->c_layer->l_height - 1, 0); 3049 LayRedisplayLine(-1, -1, -1, 1); 3050 for (i = 0; i < n; i++) 3051 LayRedisplayLine(i + flayer->l_height - n, 0, flayer->l_width - 1, 1); 3052 if (cv == cv->c_display->d_forecv) 3053 LaySetCursor(); 3054 ); 3055 } 3056 if (lx + cv->c_xoff < cv->c_xs) 3057 { 3058 int i, n = cv->c_xs - (lx + cv->c_xoff); 3059 if (n < (cv->c_xe - cv->c_xs + 1) / 2) 3060 n = (cv->c_xe - cv->c_xs + 1) / 2; 3061 if (cv->c_xoff + n > cv->c_xs) 3062 n = cv->c_xs - cv->c_xoff; 3063 cv->c_xoff += n; 3064 RethinkViewportOffsets(cv); 3065 if (n > cv->c_layer->l_width) 3066 n = cv->c_layer->l_width; 3067 CV_CALL(cv, 3068 LayRedisplayLine(-1, -1, -1, 1); 3069 for (i = 0; i < flayer->l_height; i++) 3070 { 3071 LScrollH(flayer, -n, i, 0, flayer->l_width - 1, 0, 0); 3072 LayRedisplayLine(i, 0, n - 1, 1); 3073 } 3074 if (cv == cv->c_display->d_forecv) 3075 LaySetCursor(); 3076 ); 3077 } 3078 else if (lx + cv->c_xoff > cv->c_xe) 3079 { 3080 int i, n = lx + cv->c_xoff - cv->c_xe; 3081 if (n < (cv->c_xe - cv->c_xs + 1) / 2) 3082 n = (cv->c_xe - cv->c_xs + 1) / 2; 3083 if (cv->c_xoff - n + cv->c_layer->l_width - 1 < cv->c_xe) 3084 n = cv->c_xoff + cv->c_layer->l_width - 1 - cv->c_xe; 3085 cv->c_xoff -= n; 3086 RethinkViewportOffsets(cv); 3087 if (n > cv->c_layer->l_width) 3088 n = cv->c_layer->l_width; 3089 CV_CALL(cv, 3090 LayRedisplayLine(-1, -1, -1, 1); 3091 for (i = 0; i < flayer->l_height; i++) 3092 { 3093 LScrollH(flayer, n, i, 0, flayer->l_width - 1, 0, 0); 3094 LayRedisplayLine(i, flayer->l_width - n, flayer->l_width - 1, 1); 3095 } 3096 if (cv == cv->c_display->d_forecv) 3097 LaySetCursor(); 3098 ); 3099 } 3100 } 3101 } 3102 3103 for (display = displays; display; display = display->d_next) 3104 { 3105 if (D_status == STATUS_ON_WIN || D_cvlist == 0 || D_cvlist->c_next == 0) 3106 continue; 3107 debug1("serv_select_fn: Restore on cv %#x\n", (int)D_forecv); 3108 CV_CALL(D_forecv, LayRestore();LaySetCursor()); 3109 } 3110} 3111 3112static void 3113logflush_fn(ev, data) 3114struct event *ev; 3115char *data; 3116{ 3117 struct win *p; 3118 char *buf; 3119 int n; 3120 3121 if (!islogfile(NULL)) 3122 return; /* no more logfiles */ 3123 logfflush(NULL); 3124 n = log_flush ? log_flush : (logtstamp_after + 4) / 5; 3125 if (n) 3126 { 3127 SetTimeout(ev, n * 1000); 3128 evenq(ev); /* re-enqueue ourself */ 3129 } 3130 if (!logtstamp_on) 3131 return; 3132 /* write fancy time-stamp */ 3133 for (p = windows; p; p = p->w_next) 3134 { 3135 if (!p->w_log) 3136 continue; 3137 p->w_logsilence += n; 3138 if (p->w_logsilence < logtstamp_after) 3139 continue; 3140 if (p->w_logsilence - n >= logtstamp_after) 3141 continue; 3142 buf = MakeWinMsg(logtstamp_string, p, '%'); 3143 logfwrite(p->w_log, buf, strlen(buf)); 3144 } 3145} 3146 3147/* 3148 * Interprets ^?, ^@ and other ^-control-char notation. 3149 * Interprets \ddd octal notation 3150 * 3151 * The result is placed in *cp, p is advanced behind the parsed expression and 3152 * returned. 3153 */ 3154static char * 3155ParseChar(p, cp) 3156char *p, *cp; 3157{ 3158 if (*p == 0) 3159 return 0; 3160 if (*p == '^' && p[1]) 3161 { 3162 if (*++p == '?') 3163 *cp = '\177'; 3164 else if (*p >= '@') 3165 *cp = Ctrl(*p); 3166 else 3167 return 0; 3168 ++p; 3169 } 3170 else if (*p == '\\' && *++p <= '7' && *p >= '0') 3171 { 3172 *cp = 0; 3173 do 3174 *cp = *cp * 8 + *p - '0'; 3175 while (*++p <= '7' && *p >= '0'); 3176 } 3177 else 3178 *cp = *p++; 3179 return p; 3180} 3181 3182static int 3183ParseEscape(p) 3184char *p; 3185{ 3186 unsigned char buf[2]; 3187 3188 if (*p == 0) 3189 SetEscape((struct acluser *)0, -1, -1); 3190 else 3191 { 3192 if ((p = ParseChar(p, (char *)buf)) == NULL || 3193 (p = ParseChar(p, (char *)buf+1)) == NULL || *p) 3194 return -1; 3195 SetEscape((struct acluser *)0, buf[0], buf[1]); 3196 } 3197 return 0; 3198} 3199 3200