Show the session name of the screen after detach
[screen-lua.git] / src / screen.c
blob8160a73935f50f1c7ef79134451321f48676b356
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
11 * Modifications Copyright (c) 1995 by
12 * Science Access Project, Oregon State University.
13 #endif
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.
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.
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
30 ****************************************************************
33 #include <sys/types.h>
34 #include <ctype.h>
36 #include <fcntl.h>
38 #ifdef sgi
39 # include <sys/sysmacros.h>
40 #endif
42 #include <sys/stat.h>
43 #ifndef sun
44 # include <sys/ioctl.h>
45 #endif
47 #ifndef SIGINT
48 # include <signal.h>
49 #endif
51 #include "config.h"
53 #ifdef HAVE_STROPTS_H
54 # include <sys/stropts.h>
55 #endif
57 #if defined(SYSV) && !defined(ISC)
58 # include <sys/utsname.h>
59 #endif
61 #if defined(sequent) || defined(SVR4)
62 # include <sys/resource.h>
63 #endif /* sequent || SVR4 */
65 #ifdef ISC
66 # include <sys/tty.h>
67 # include <sys/sioctl.h>
68 # include <sys/pty.h>
69 #endif /* ISC */
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
81 #include "screen.h"
82 #ifdef HAVE_BRAILLE
83 # include "braille.h"
84 #endif
86 #include "patchlevel.h"
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).
93 #ifndef LOCK
94 # undef SHADOWPW
95 #endif
97 #include <pwd.h>
98 #ifdef SHADOWPW
99 # include <shadow.h>
100 #endif /* SHADOWPW */
102 #include "logfile.h" /* islogfile, logfflush */
104 #ifdef DEBUG
105 FILE *dfp;
106 #endif
109 extern char Term[], screenterm[], **environ, Termcap[];
110 int force_vt = 1;
111 int VBellWait, MsgWait, MsgMinWait, SilenceWait;
113 extern struct acluser *users;
114 extern struct display *displays, *display;
117 extern int visual_bell;
118 #ifdef COPY_PASTE
119 extern unsigned char mark_key_tab[];
120 #endif
121 extern char version[];
122 extern char DefaultShell[];
123 #ifdef ZMODEM
124 extern char *zmodem_sendcmd;
125 extern char *zmodem_recvcmd;
126 #endif
127 extern struct layout *layout_last;
130 char *ShellProg;
131 char *ShellArgs[2];
133 extern struct NewWindow nwin_undef, nwin_default, nwin_options;
134 struct backtick;
136 static struct passwd *getpwbyname __P((char *, struct passwd *));
137 static void SigChldHandler __P((void));
138 static sigret_t SigChld __P(SIGPROTOARG);
139 static sigret_t SigInt __P(SIGPROTOARG);
140 static sigret_t CoreDump __P(SIGPROTOARG);
141 static sigret_t FinitHandler __P(SIGPROTOARG);
142 static void DoWait __P((void));
143 static void serv_read_fn __P((struct event *, char *));
144 static void serv_select_fn __P((struct event *, char *));
145 static void logflush_fn __P((struct event *, char *));
146 static void backtick_filter __P((struct backtick *));
147 static void backtick_fn __P((struct event *, char *));
148 static char *runbacktick __P((struct backtick *, int *, time_t));
149 static int IsSymbol __P((char *, char *));
150 static char *ParseChar __P((char *, char *));
151 static int ParseEscape __P((char *));
152 static char *pad_expand __P((char *, char *, int, int));
153 #ifdef DEBUG
154 static void fds __P((void));
155 #endif
157 int nversion; /* numerical version, used for secondary DA */
159 /* the attacher */
160 struct passwd *ppp;
161 char *attach_tty;
162 int attach_fd = -1;
163 char *attach_term;
164 char *LoginName;
165 struct mode attach_Mode;
167 char SockPath[MAXPATHLEN + 2 * MAXSTR];
168 char *SockName; /* SockName is pointer in SockPath */
169 char *SockMatch = NULL; /* session id command line argument */
170 int ServerSocket = -1;
171 struct event serv_read;
172 struct event serv_select;
173 struct event logflushev;
175 char **NewEnv = NULL;
177 char *RcFileName = NULL;
178 char *home;
180 char *screenlogfile; /* filename layout */
181 int log_flush = 10; /* flush interval in seconds */
182 int logtstamp_on = 0; /* tstamp disabled */
183 char *logtstamp_string; /* stamp layout */
184 int logtstamp_after = 120; /* first tstamp after 120s */
185 char *hardcopydir = NULL;
186 char *BellString;
187 char *VisualBellString;
188 char *ActivityString;
189 #ifdef COPY_PASTE
190 char *BufferFile;
191 #endif
192 #ifdef POW_DETACH
193 char *PowDetachString;
194 #endif
195 char *hstatusstring;
196 char *captionstring;
197 char *timestring;
198 char *wliststr;
199 char *wlisttit;
200 int auto_detach = 1;
201 int iflag, rflag, dflag, lsflag, quietflag, wipeflag, xflag;
202 int cmdflag;
203 int adaptflag;
205 #ifdef MULTIUSER
206 char *multi;
207 char *multi_home;
208 int multi_uid;
209 int own_uid;
210 int multiattach;
211 int tty_mode;
212 int tty_oldmode = -1;
213 #endif
215 char HostName[MAXSTR];
216 int MasterPid, PanicPid;
217 int real_uid, real_gid, eff_uid, eff_gid;
218 int default_startup;
219 int ZombieKey_destroy, ZombieKey_resurrect, ZombieKey_onerror;
220 char *preselect = NULL; /* only used in Attach() */
222 #ifdef UTF8
223 char *screenencodings;
224 #endif
226 #ifdef DW_CHARS
227 int cjkwidth;
228 #endif
230 #ifdef NETHACK
231 int nethackflag = 0;
232 #endif
233 int maxwin = MAXWIN;
236 struct layer *flayer;
237 struct win *fore;
238 struct win *windows;
239 struct win *console_window;
244 * Do this last
246 #include "extern.h"
248 char strnomem[] = "Out of memory.";
251 static int InterruptPlease;
252 static int GotSigChld;
254 static int
255 lf_secreopen(name, wantfd, l)
256 char *name;
257 int wantfd;
258 struct logfile *l;
260 int got_fd;
262 close(wantfd);
263 if (((got_fd = secopen(name, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) ||
264 lf_move_fd(got_fd, wantfd) < 0)
266 logfclose(l);
267 debug1("lf_secreopen: failed for %s\n", name);
268 return -1;
270 l->st->st_ino = l->st->st_dev = 0;
271 debug2("lf_secreopen: %d = %s\n", wantfd, name);
272 return 0;
275 /********************************************************************/
276 /********************************************************************/
277 /********************************************************************/
280 static struct passwd *
281 getpwbyname(name, ppp)
282 char *name;
283 struct passwd *ppp;
285 int n;
286 #ifdef SHADOWPW
287 struct spwd *sss = NULL;
288 static char *spw = NULL;
289 #endif
291 if (!ppp && !(ppp = getpwnam(name)))
292 return NULL;
294 /* Do password sanity check..., allow ##user for SUN_C2 security */
295 #ifdef SHADOWPW
296 pw_try_again:
297 #endif
298 n = 0;
299 if (ppp->pw_passwd[0] == '#' && ppp->pw_passwd[1] == '#' &&
300 strcmp(ppp->pw_passwd + 2, ppp->pw_name) == 0)
301 n = 13;
302 for (; n < 13; n++)
304 char c = ppp->pw_passwd[n];
305 if (!(c == '.' || c == '/' || c == '$' ||
306 (c >= '0' && c <= '9') ||
307 (c >= 'a' && c <= 'z') ||
308 (c >= 'A' && c <= 'Z')))
309 break;
312 #ifdef SHADOWPW
313 /* try to determine real password */
314 if (n < 13 && sss == 0)
316 sss = getspnam(ppp->pw_name);
317 if (sss)
319 if (spw)
320 free(spw);
321 ppp->pw_passwd = spw = SaveStr(sss->sp_pwdp);
322 endspent(); /* this should delete all buffers ... */
323 goto pw_try_again;
325 endspent(); /* this should delete all buffers ... */
327 #endif
328 if (n < 13)
329 ppp->pw_passwd = 0;
330 #ifdef linux
331 if (ppp->pw_passwd && strlen(ppp->pw_passwd) == 13 + 11)
332 ppp->pw_passwd[13] = 0; /* beware of linux's long passwords */
333 #endif
335 return ppp;
338 static char *
339 locale_name(void)
341 static char *s;
343 if (!s)
345 s = getenv("LC_ALL");
346 if (s == NULL)
347 s = getenv("LC_CTYPE");
348 if (s == NULL)
349 s = getenv("LANG");
351 return s;
355 main(ac, av)
356 int ac;
357 char **av;
359 register int n;
360 char *ap;
361 char *av0;
362 char socknamebuf[2 * MAXSTR];
363 int mflag = 0;
364 char *myname = (ac == 0) ? "screen" : av[0];
365 char *SockDir;
366 struct stat st;
367 #ifdef _MODE_T /* (jw) */
368 mode_t oumask;
369 #else
370 int oumask;
371 #endif
372 #if defined(SYSV) && !defined(ISC)
373 struct utsname utsnam;
374 #endif
375 struct NewWindow nwin;
376 int detached = 0; /* start up detached */
377 #ifdef MULTIUSER
378 char *sockp;
379 #endif
380 char *sty = 0;
382 #if (defined(AUX) || defined(_AUX_SOURCE)) && defined(POSIX)
383 setcompat(COMPAT_POSIX|COMPAT_BSDPROT); /* turn on seteuid support */
384 #endif
385 #if defined(sun) && defined(SVR4)
387 /* Solaris' login blocks SIGHUP! This is _very bad_ */
388 sigset_t sset;
389 sigemptyset(&sset);
390 sigprocmask(SIG_SETMASK, &sset, 0);
392 #endif
395 * First, close all unused descriptors
396 * (otherwise, we might have problems with the select() call)
398 closeallfiles(0);
399 #ifdef DEBUG
400 opendebug(1, 0);
401 #endif
402 sprintf(version, "%d.%.2d.%.2d%s (%s) %s", REV, VERS,
403 PATCHLEVEL, STATE, ORIGIN, DATE);
404 nversion = REV * 10000 + VERS * 100 + PATCHLEVEL;
405 debug2("-- screen debug started %s (%s)\n", *av, version);
406 #ifdef POSIX
407 debug("POSIX\n");
408 #endif
409 #ifdef TERMIO
410 debug("TERMIO\n");
411 #endif
412 #ifdef SYSV
413 debug("SYSV\n");
414 #endif
415 #ifdef SYSVSIGS
416 debug("SYSVSIGS\n");
417 #endif
418 #ifdef NAMEDPIPE
419 debug("NAMEDPIPE\n");
420 #endif
421 #if defined(SIGWINCH) && defined(TIOCGWINSZ)
422 debug("Window size changing enabled\n");
423 #endif
424 #ifdef HAVE_SETREUID
425 debug("SETREUID\n");
426 #endif
427 #ifdef HAVE_SETEUID
428 debug("SETEUID\n");
429 #endif
430 #ifdef hpux
431 debug("hpux\n");
432 #endif
433 #ifdef USEBCOPY
434 debug("USEBCOPY\n");
435 #endif
436 #ifdef UTMPOK
437 debug("UTMPOK\n");
438 #endif
439 #ifdef LOADAV
440 debug("LOADAV\n");
441 #endif
442 #ifdef NETHACK
443 debug("NETHACK\n");
444 #endif
445 #ifdef TERMINFO
446 debug("TERMINFO\n");
447 #endif
448 #ifdef SHADOWPW
449 debug("SHADOWPW\n");
450 #endif
451 #ifdef NAME_MAX
452 debug1("NAME_MAX = %d\n", NAME_MAX);
453 #endif
455 BellString = SaveStr("Bell in window %n");
456 VisualBellString = SaveStr(" Wuff, Wuff!! ");
457 ActivityString = SaveStr("Activity in window %n");
458 screenlogfile = SaveStr("screenlog.%n");
459 logtstamp_string = SaveStr("-- %n:%t -- time-stamp -- %M/%d/%y %c:%s --\n");
460 hstatusstring = SaveStr("%h");
461 captionstring = SaveStr("%3n %t");
462 timestring = SaveStr("%c:%s %M %d %H%? %l%?");
463 wlisttit = SaveStr("Num Name%=Flags");
464 wliststr = SaveStr("%3n %t%=%f");
465 #ifdef COPY_PASTE
466 BufferFile = SaveStr(DEFAULT_BUFFERFILE);
467 #endif
468 ShellProg = NULL;
469 #ifdef POW_DETACH
470 PowDetachString = 0;
471 #endif
472 default_startup = (ac > 1) ? 0 : 1;
473 adaptflag = 0;
474 VBellWait = VBELLWAIT * 1000;
475 MsgWait = MSGWAIT * 1000;
476 MsgMinWait = MSGMINWAIT * 1000;
477 SilenceWait = SILENCEWAIT;
478 #ifdef HAVE_BRAILLE
479 InitBraille();
480 #endif
481 #ifdef ZMODEM
482 zmodem_sendcmd = SaveStr("!!! sz -vv -b ");
483 zmodem_recvcmd = SaveStr("!!! rz -vv -b -E");
484 #endif
486 #ifdef COPY_PASTE
487 CompileKeys((char *)0, 0, mark_key_tab);
488 #endif
489 #ifdef UTF8
490 InitBuiltinTabs();
491 screenencodings = SaveStr(SCREENENCODINGS);
492 #endif
493 #ifdef DW_CHARS
494 cjkwidth = 0;
495 #endif
496 nwin = nwin_undef;
497 nwin_options = nwin_undef;
498 strcpy(screenterm, "screen");
500 logreopen_register(lf_secreopen);
502 av0 = *av;
503 /* if this is a login screen, assume -RR */
504 if (*av0 == '-')
506 rflag = 4;
507 #ifdef MULTI
508 xflag = 1;
509 #else
510 dflag = 1;
511 #endif
512 ShellProg = SaveStr(DefaultShell); /* to prevent nasty circles */
514 while (ac > 0)
516 ap = *++av;
517 if (--ac > 0 && *ap == '-')
519 if (ap[1] == '-' && ap[2] == 0)
521 av++;
522 ac--;
523 break;
525 if (ap[1] == '-' && !strcmp(ap, "--version"))
526 Panic(0, "Screen version %s", version);
527 if (ap[1] == '-' && !strcmp(ap, "--help"))
528 exit_with_usage(myname, NULL, NULL);
529 while (ap && *ap && *++ap)
531 switch (*ap)
533 case 'a':
534 nwin_options.aflag = 1;
535 break;
536 case 'A':
537 adaptflag = 1;
538 break;
539 case 'p': /* preselect */
540 if (*++ap)
541 preselect = ap;
542 else
544 if (!--ac)
545 exit_with_usage(myname, "Specify a window to preselect with -p", NULL);
546 preselect = *++av;
548 ap = NULL;
549 break;
550 #ifdef HAVE_BRAILLE
551 case 'B':
552 bd.bd_start_braille = 1;
553 break;
554 #endif
555 case 'c':
556 if (*++ap)
557 RcFileName = ap;
558 else
560 if (--ac == 0)
561 exit_with_usage(myname, "Specify an alternate rc-filename with -c", NULL);
562 RcFileName = *++av;
564 ap = NULL;
565 break;
566 case 'e':
567 if (!*++ap)
569 if (--ac == 0)
570 exit_with_usage(myname, "Specify command characters with -e", NULL);
571 ap = *++av;
573 if (ParseEscape(ap))
574 Panic(0, "Two characters are required with -e option, not '%s'.", ap);
575 ap = NULL;
576 break;
577 case 'f':
578 ap++;
579 switch (*ap++)
581 case 'n':
582 case '0':
583 nwin_options.flowflag = FLOW_NOW * 0;
584 break;
585 case '\0':
586 ap--;
587 /* FALLTHROUGH */
588 case 'y':
589 case '1':
590 nwin_options.flowflag = FLOW_NOW * 1;
591 break;
592 case 'a':
593 nwin_options.flowflag = FLOW_AUTOFLAG;
594 break;
595 default:
596 exit_with_usage(myname, "Unknown flow option -%s", --ap);
598 break;
599 case 'h':
600 if (--ac == 0)
601 exit_with_usage(myname, NULL, NULL);
602 nwin_options.histheight = atoi(*++av);
603 if (nwin_options.histheight < 0)
604 exit_with_usage(myname, "-h: %s: negative scrollback size?", *av);
605 break;
606 case 'i':
607 iflag = 1;
608 break;
609 case 't': /* title, the former AkA == -k */
610 if (--ac == 0)
611 exit_with_usage(myname, "Specify a new window-name with -t", NULL);
612 nwin_options.aka = *++av;
613 break;
614 case 'l':
615 ap++;
616 switch (*ap++)
618 case 'n':
619 case '0':
620 nwin_options.lflag = 0;
621 break;
622 case '\0':
623 ap--;
624 /* FALLTHROUGH */
625 case 'y':
626 case '1':
627 nwin_options.lflag = 1;
628 break;
629 case 'a':
630 nwin_options.lflag = 3;
631 break;
632 case 's': /* -ls */
633 case 'i': /* -list */
634 lsflag = 1;
635 if (ac > 1 && !SockMatch)
637 SockMatch = *++av;
638 ac--;
640 ap = NULL;
641 break;
642 default:
643 exit_with_usage(myname, "%s: Unknown suboption to -l", --ap);
645 break;
646 case 'w':
647 lsflag = 1;
648 wipeflag = 1;
649 if (ac > 1 && !SockMatch)
651 SockMatch = *++av;
652 ac--;
654 break;
655 case 'L':
656 nwin_options.Lflag = 1;
657 break;
658 case 'm':
659 mflag = 1;
660 break;
661 case 'O': /* to be (or not to be?) deleted. jw. */
662 force_vt = 0;
663 break;
664 case 'T':
665 if (--ac == 0)
666 exit_with_usage(myname, "Specify terminal-type with -T", NULL);
667 if (strlen(*++av) < 20)
668 strcpy(screenterm, *av);
669 else
670 Panic(0, "-T: terminal name too long. (max. 20 char)");
671 nwin_options.term = screenterm;
672 break;
673 case 'q':
674 quietflag = 1;
675 break;
676 case 'r':
677 case 'R':
678 #ifdef MULTI
679 case 'x':
680 #endif
681 if (ac > 1 && *av[1] != '-' && !SockMatch)
683 SockMatch = *++av;
684 ac--;
685 debug2("rflag=%d, SockMatch=%s\n", dflag, SockMatch);
687 #ifdef MULTI
688 if (*ap == 'x')
689 xflag = 1;
690 #endif
691 if (rflag)
692 rflag = 2;
693 rflag += (*ap == 'R') ? 2 : 1;
694 break;
695 #ifdef REMOTE_DETACH
696 case 'd':
697 dflag = 1;
698 /* FALLTHROUGH */
699 case 'D':
700 if (!dflag)
701 dflag = 2;
702 if (ac == 2)
704 if (*av[1] != '-' && !SockMatch)
706 SockMatch = *++av;
707 ac--;
708 debug2("dflag=%d, SockMatch=%s\n", dflag, SockMatch);
711 break;
712 #endif
713 case 's':
714 if (--ac == 0)
715 exit_with_usage(myname, "Specify shell with -s", NULL);
716 if (ShellProg)
717 free(ShellProg);
718 ShellProg = SaveStr(*++av);
719 debug1("ShellProg: '%s'\n", ShellProg);
720 break;
721 case 'S':
722 if (!SockMatch)
724 if (--ac == 0)
725 exit_with_usage(myname, "Specify session-name with -S", NULL);
726 SockMatch = *++av;
728 if (!*SockMatch)
729 exit_with_usage(myname, "Empty session-name?", NULL);
730 break;
731 case 'X':
732 cmdflag = 1;
733 break;
734 case 'v':
735 Panic(0, "Screen version %s", version);
736 /* NOTREACHED */
737 #ifdef UTF8
738 case 'U':
739 nwin_options.encoding = nwin_options.encoding == -1 ? UTF8 : 0;
740 break;
741 #endif
742 default:
743 exit_with_usage(myname, "Unknown option %s", --ap);
747 else
748 break;
751 real_uid = getuid();
752 real_gid = getgid();
753 eff_uid = geteuid();
754 eff_gid = getegid();
755 if (eff_uid != real_uid)
757 /* if running with s-bit, we must install a special signal
758 * handler routine that resets the s-bit, so that we get a
759 * core file anyway.
761 #ifdef SIGBUS /* OOPS, linux has no bus errors! */
762 signal(SIGBUS, CoreDump);
763 #endif /* SIGBUS */
764 signal(SIGSEGV, CoreDump);
767 #ifdef USE_LOCALE
768 setlocale(LC_ALL, "");
769 #endif
770 #ifdef ENCODINGS
771 if (nwin_options.encoding == -1)
773 /* ask locale if we should start in UTF-8 mode */
774 # ifdef HAVE_NL_LANGINFO
775 # ifndef USE_LOCALE
776 setlocale(LC_CTYPE, "");
777 # endif
778 nwin_options.encoding = FindEncoding(nl_langinfo(CODESET));
779 debug1("locale says encoding = %d\n", nwin_options.encoding);
780 # else
781 # ifdef UTF8
782 char *s;
783 if ((s = locale_name()) && InStr(s, "UTF-8"))
784 nwin_options.encoding = UTF8;
785 # endif
786 debug1("environment says encoding=%d\n", nwin_options.encoding);
787 #endif
789 # ifdef DW_CHARS
791 char *s;
792 if ((s = locale_name()))
794 if(!strncmp(s, "zh_", 3) || !strncmp(s, "ja_", 3) || !strncmp(s, "ko_", 3))
796 cjkwidth = 1;
800 #endif
801 #endif
802 if (nwin_options.aka)
804 #ifdef ENCODINGS
805 if (nwin_options.encoding > 0)
807 size_t len = strlen(nwin_options.aka);
808 size_t newsz;
809 char *newbuf = malloc(3 * len);
810 if (!newbuf)
811 Panic(0, strnomem);
812 newsz = RecodeBuf(nwin_options.aka, len,
813 nwin_options.encoding, 0, newbuf);
814 newbuf[newsz] = '\0';
815 nwin_options.aka = newbuf;
817 else
818 #endif
820 /* If we just use the original value from av,
821 subsequent shelltitle invocations will attempt to free
822 space we don't own... */
823 nwin_options.aka = SaveStr(nwin_options.aka);
827 if (SockMatch && strlen(SockMatch) >= MAXSTR)
828 Panic(0, "Ridiculously long socketname - try again.");
829 if (cmdflag && !rflag && !dflag && !xflag)
830 xflag = 1;
831 if (!cmdflag && dflag && mflag && !(rflag || xflag))
832 detached = 1;
833 nwin = nwin_options;
834 #ifdef ENCODINGS
835 nwin.encoding = nwin_undef.encoding; /* let screenrc overwrite it */
836 #endif
837 if (ac)
838 nwin.args = av;
840 /* make the write() calls return -1 on all errors */
841 #ifdef SIGXFSZ
843 * Ronald F. Guilmette, Oct 29 '94, bug-gnu-utils@prep.ai.mit.edu:
844 * It appears that in System V Release 4, UNIX, if you are writing
845 * an output file and you exceed the currently set file size limit,
846 * you _don't_ just get the call to `write' returning with a
847 * failure code. Rather, you get a signal called `SIGXFSZ' which,
848 * if neither handled nor ignored, will cause your program to crash
849 * with a core dump.
851 signal(SIGXFSZ, SIG_IGN);
852 #endif /* SIGXFSZ */
854 #ifdef SIGPIPE
855 signal(SIGPIPE, SIG_IGN);
856 #endif
858 if (!ShellProg)
860 register char *sh;
862 sh = getenv("SHELL");
863 ShellProg = SaveStr(sh ? sh : DefaultShell);
865 ShellArgs[0] = ShellProg;
866 home = getenv("HOME");
867 if (!mflag && !SockMatch)
869 sty = getenv("STY");
870 if (sty && *sty == 0)
871 sty = 0;
874 #ifdef NETHACK
875 if (!(nethackflag = (getenv("NETHACKOPTIONS") != NULL)))
877 char nethackrc[MAXPATHLEN];
879 if (home && (strlen(home) < (MAXPATHLEN - 20)))
881 sprintf(nethackrc,"%s/.nethackrc", home);
882 nethackflag = !access(nethackrc, F_OK);
885 #endif
887 #ifdef MULTIUSER
888 own_uid = multi_uid = real_uid;
889 if (SockMatch && (sockp = index(SockMatch, '/')))
891 *sockp = 0;
892 multi = SockMatch;
893 SockMatch = sockp + 1;
894 if (*multi)
896 struct passwd *mppp;
897 if ((mppp = getpwnam(multi)) == (struct passwd *)0)
898 Panic(0, "Cannot identify account '%s'.", multi);
899 multi_uid = mppp->pw_uid;
900 multi_home = SaveStr(mppp->pw_dir);
901 if (strlen(multi_home) > MAXPATHLEN - 10)
902 Panic(0, "home directory path too long");
903 # ifdef MULTI
904 /* always fake multi attach mode */
905 if (rflag || lsflag)
906 xflag = 1;
907 # endif /* MULTI */
908 detached = 0;
909 multiattach = 1;
911 /* Special case: effective user is multiuser. */
912 if (eff_uid && (multi_uid != eff_uid))
913 Panic(0, "Must run suid root for multiuser support.");
915 if (SockMatch && *SockMatch == 0)
916 SockMatch = 0;
917 #endif /* MULTIUSER */
919 if ((LoginName = getlogin()) && LoginName[0] != '\0')
921 if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0)
922 if ((int)ppp->pw_uid != real_uid)
923 ppp = (struct passwd *) 0;
925 if (ppp == 0)
927 if ((ppp = getpwuid(real_uid)) == 0)
929 Panic(0, "getpwuid() can't identify your account!");
930 exit(1);
932 LoginName = ppp->pw_name;
934 LoginName = SaveStr(LoginName);
936 ppp = getpwbyname(LoginName, ppp);
938 #if !defined(SOCKDIR) && defined(MULTIUSER)
939 if (multi && !multiattach)
941 if (home && strcmp(home, ppp->pw_dir))
942 Panic(0, "$HOME must match passwd entry for multiuser screens.");
944 #endif
946 #define SET_GUID() do \
948 setgid(real_gid); \
949 setuid(real_uid); \
950 eff_uid = real_uid; \
951 eff_gid = real_gid; \
952 } while (0)
954 #define SET_TTYNAME(fatal) do \
956 if (!(attach_tty = ttyname(0))) \
958 if (fatal) \
959 Panic(0, "Must be connected to a terminal."); \
960 else \
961 attach_tty = ""; \
963 else if (stat(attach_tty, &st)) \
964 Panic(errno, "Cannot access '%s'", attach_tty); \
965 if (strlen(attach_tty) >= MAXPATHLEN) \
966 Panic(0, "TtyName too long - sorry."); \
967 } while (0)
969 if (home == 0 || *home == '\0')
970 home = ppp->pw_dir;
971 if (strlen(LoginName) > 20)
972 Panic(0, "LoginName too long - sorry.");
973 #ifdef MULTIUSER
974 if (multi && strlen(multi) > 20)
975 Panic(0, "Screen owner name too long - sorry.");
976 #endif
977 if (strlen(home) > MAXPATHLEN - 25)
978 Panic(0, "$HOME too long - sorry.");
980 attach_tty = "";
981 if (!detached && !lsflag && !cmdflag && !(dflag && !mflag && !rflag && !xflag) && !(!mflag && !SockMatch && sty && !xflag))
983 #ifndef NAMEDPIPE
984 int fl;
985 #endif
987 /* ttyname implies isatty */
988 SET_TTYNAME(1);
989 #ifdef MULTIUSER
990 tty_mode = (int)st.st_mode & 0777;
991 #endif
993 #ifndef NAMEDPIPE
994 fl = fcntl(0, F_GETFL, 0);
995 if (fl != -1 && (fl & (O_RDWR|O_RDONLY|O_WRONLY)) == O_RDWR)
996 attach_fd = 0;
997 #endif
998 if (attach_fd == -1)
1000 if ((n = secopen(attach_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
1001 Panic(0, "Cannot open your terminal '%s' - please check.", attach_tty);
1002 close(n);
1004 debug2("attach_tty is %s, attach_fd is %d\n", attach_tty, attach_fd);
1006 if ((attach_term = getenv("TERM")) == 0 || *attach_term == 0)
1007 Panic(0, "Please set a terminal type.");
1008 if (strlen(attach_term) > sizeof(D_termname) - 1)
1009 Panic(0, "$TERM too long - sorry.");
1010 GetTTY(0, &attach_Mode);
1011 #ifdef DEBUGGGGGGGGGGGGGGG
1012 DebugTTY(&attach_Mode);
1013 #endif /* DEBUG */
1016 #ifdef _MODE_T
1017 oumask = umask(0); /* well, unsigned never fails? jw. */
1018 #else
1019 if ((oumask = (int)umask(0)) == -1)
1020 Panic(errno, "Cannot change umask to zero");
1021 #endif
1022 SockDir = getenv("SCREENDIR");
1023 if (SockDir)
1025 if (strlen(SockDir) >= MAXPATHLEN - 1)
1026 Panic(0, "Ridiculously long $SCREENDIR - try again.");
1027 #ifdef MULTIUSER
1028 if (multi)
1029 Panic(0, "No $SCREENDIR with multi screens, please.");
1030 #endif
1032 #ifdef MULTIUSER
1033 if (multiattach)
1035 # ifndef SOCKDIR
1036 sprintf(SockPath, "%s/.screen", multi_home);
1037 SockDir = SockPath;
1038 # else
1039 SockDir = SOCKDIR;
1040 sprintf(SockPath, "%s/S-%s", SockDir, multi);
1041 # endif
1043 else
1044 #endif
1046 #ifndef SOCKDIR
1047 if (SockDir == 0)
1049 sprintf(SockPath, "%s/.screen", home);
1050 SockDir = SockPath;
1052 #endif
1053 if (SockDir)
1055 if (access(SockDir, F_OK))
1057 debug1("SockDir '%s' missing ...\n", SockDir);
1058 if (UserContext() > 0)
1060 if (mkdir(SockDir, 0700))
1061 UserReturn(0);
1062 UserReturn(1);
1064 if (UserStatus() <= 0)
1065 Panic(0, "Cannot make directory '%s'.", SockDir);
1067 if (SockDir != SockPath)
1068 strcpy(SockPath, SockDir);
1070 #ifdef SOCKDIR
1071 else
1073 SockDir = SOCKDIR;
1074 if (lstat(SockDir, &st))
1076 n = (eff_uid == 0 && (real_uid || eff_gid == real_gid)) ? 0755 :
1077 (eff_gid != real_gid) ? 0775 :
1078 #ifdef S_ISVTX
1079 0777|S_ISVTX;
1080 #else
1081 0777;
1082 #endif
1083 if (mkdir(SockDir, n) == -1)
1084 Panic(errno, "Cannot make directory '%s'", SockDir);
1086 else
1088 if (!S_ISDIR(st.st_mode))
1089 Panic(0, "'%s' must be a directory.", SockDir);
1090 if (eff_uid == 0 && real_uid && (int)st.st_uid != eff_uid)
1091 Panic(0, "Directory '%s' must be owned by root.", SockDir);
1092 n = (eff_uid == 0 && (real_uid || (st.st_mode & 0775) != 0775)) ? 0755 :
1093 (eff_gid == (int)st.st_gid && eff_gid != real_gid) ? 0775 :
1094 0777;
1095 if (((int)st.st_mode & 0777) != n)
1096 Panic(0, "Directory '%s' must have mode %03o.", SockDir, n);
1098 sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
1099 if (access(SockPath, F_OK))
1101 if (mkdir(SockPath, 0700) == -1)
1102 Panic(errno, "Cannot make directory '%s'", SockPath);
1103 (void) chown(SockPath, real_uid, real_gid);
1106 #endif
1109 if (stat(SockPath, &st) == -1)
1110 Panic(errno, "Cannot access %s", SockPath);
1111 else
1112 if (!S_ISDIR(st.st_mode))
1113 Panic(0, "%s is not a directory.", SockPath);
1114 #ifdef MULTIUSER
1115 if (multi)
1117 if ((int)st.st_uid != multi_uid)
1118 Panic(0, "%s is not the owner of %s.", multi, SockPath);
1120 else
1121 #endif
1123 if ((int)st.st_uid != real_uid)
1124 Panic(0, "You are not the owner of %s.", SockPath);
1126 if ((st.st_mode & 0777) != 0700)
1127 Panic(0, "Directory %s must have mode 700.", SockPath);
1128 if (SockMatch && index(SockMatch, '/'))
1129 Panic(0, "Bad session name '%s'", SockMatch);
1130 SockName = SockPath + strlen(SockPath) + 1;
1131 *SockName = 0;
1132 (void) umask(oumask);
1133 debug2("SockPath: %s SockMatch: %s\n", SockPath, SockMatch ? SockMatch : "NULL");
1135 #if defined(SYSV) && !defined(ISC)
1136 if (uname(&utsnam) == -1)
1137 Panic(errno, "uname");
1138 strncpy(HostName, utsnam.nodename, sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1);
1139 HostName[sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1] = '\0';
1140 #else
1141 (void) gethostname(HostName, MAXSTR);
1142 HostName[MAXSTR - 1] = '\0';
1143 #endif
1144 if ((ap = index(HostName, '.')) != NULL)
1145 *ap = '\0';
1147 if (lsflag)
1149 int i, fo, oth;
1151 #ifdef MULTIUSER
1152 if (multi)
1153 real_uid = multi_uid;
1154 #endif
1155 SET_GUID();
1156 i = FindSocket((int *)NULL, &fo, &oth, SockMatch);
1157 if (quietflag)
1158 exit(8 + (fo ? ((oth || i) ? 2 : 1) : 0) + i);
1159 if (fo == 0)
1160 Panic(0, "No Sockets found in %s.\n", SockPath);
1161 Panic(0, "%d Socket%s in %s.\n", fo, fo > 1 ? "s" : "", SockPath);
1162 /* NOTREACHED */
1164 signal(SIG_BYE, AttacherFinit); /* prevent races */
1165 if (cmdflag)
1167 /* attach_tty is not mandatory */
1168 SET_TTYNAME(0);
1169 if (!*av)
1170 Panic(0, "Please specify a command.");
1171 SET_GUID();
1172 SendCmdMessage(sty, SockMatch, av);
1173 exit(0);
1175 else if (rflag || xflag)
1177 debug("screen -r: - is there anybody out there?\n");
1178 if (Attach(MSG_ATTACH))
1180 Attacher();
1181 /* NOTREACHED */
1183 #ifdef MULTIUSER
1184 if (multiattach)
1185 Panic(0, "Can't create sessions of other users.");
1186 #endif
1187 debug("screen -r: backend not responding -- still crying\n");
1189 else if (dflag && !mflag)
1191 SET_TTYNAME(0);
1192 Attach(MSG_DETACH);
1193 Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
1194 eexit(0);
1195 /* NOTREACHED */
1197 if (!SockMatch && !mflag && sty)
1199 /* attach_tty is not mandatory */
1200 SET_TTYNAME(0);
1201 SET_GUID();
1202 nwin_options.args = av;
1203 SendCreateMsg(sty, &nwin);
1204 exit(0);
1205 /* NOTREACHED */
1207 nwin_compose(&nwin_default, &nwin_options, &nwin_default);
1209 if (!detached || dflag != 2)
1210 MasterPid = fork();
1211 else
1212 MasterPid = 0;
1214 switch (MasterPid)
1216 case -1:
1217 Panic(errno, "fork");
1218 /* NOTREACHED */
1219 case 0:
1220 break;
1221 default:
1222 if (detached)
1223 exit(0);
1224 if (SockMatch)
1225 sprintf(socknamebuf, "%d.%s", MasterPid, SockMatch);
1226 else
1227 sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty), HostName);
1228 for (ap = socknamebuf; *ap; ap++)
1229 if (*ap == '/')
1230 *ap = '-';
1231 #ifdef NAME_MAX
1232 if (strlen(socknamebuf) > NAME_MAX)
1233 socknamebuf[NAME_MAX] = 0;
1234 #endif
1235 sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf);
1236 SET_GUID();
1237 Attacher();
1238 /* NOTREACHED */
1241 if (!detached)
1242 PanicPid = getppid();
1244 if (DefaultEsc == -1)
1245 DefaultEsc = Ctrl('a');
1246 if (DefaultMetaEsc == -1)
1247 DefaultMetaEsc = 'a';
1249 ap = av0 + strlen(av0) - 1;
1250 while (ap >= av0)
1252 if (!strncmp("screen", ap, 6))
1254 strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
1255 break;
1257 ap--;
1259 if (ap < av0)
1260 *av0 = 'S';
1262 #ifdef DEBUG
1264 char buf[256];
1266 if (dfp && dfp != stderr)
1267 fclose(dfp);
1268 sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, (int)getpid());
1269 if ((dfp = fopen(buf, "w")) == NULL)
1270 dfp = stderr;
1271 else
1272 (void) chmod(buf, 0666);
1274 #endif
1275 if (!detached)
1277 if (attach_fd == -1)
1279 if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
1280 Panic(0, "Cannot reopen '%s' - please check.", attach_tty);
1282 else
1283 n = dup(attach_fd);
1285 else
1286 n = -1;
1287 freopen("/dev/null", "r", stdin);
1288 freopen("/dev/null", "w", stdout);
1290 #ifdef DEBUG
1291 if (dfp != stderr)
1292 #endif
1293 freopen("/dev/null", "w", stderr);
1294 debug("-- screen.back debug started\n");
1297 * This guarantees that the session owner is listed, even when we
1298 * start detached. From now on we should not refer to 'LoginName'
1299 * any more, use users->u_name instead.
1301 if (UserAdd(LoginName, (char *)0, (struct acluser **)0) < 0)
1302 Panic(0, "Could not create user info");
1303 if (!detached)
1305 if (MakeDisplay(LoginName, attach_tty, attach_term, n, getppid(), &attach_Mode) == 0)
1306 Panic(0, "Could not alloc display");
1307 PanicPid = 0;
1308 #ifdef ENCODINGS
1309 D_encoding = nwin_options.encoding > 0 ? nwin_options.encoding : 0;
1310 debug1("D_encoding = %d\n", D_encoding);
1311 #endif
1314 if (SockMatch)
1316 /* user started us with -S option */
1317 sprintf(socknamebuf, "%d.%s", (int)getpid(), SockMatch);
1319 else
1321 sprintf(socknamebuf, "%d.%s.%s", (int)getpid(), stripdev(attach_tty),
1322 HostName);
1324 for (ap = socknamebuf; *ap; ap++)
1325 if (*ap == '/')
1326 *ap = '-';
1327 #ifdef NAME_MAX
1328 if (strlen(socknamebuf) > NAME_MAX)
1330 debug2("Socketname %s truncated to %d chars\n", socknamebuf, NAME_MAX);
1331 socknamebuf[NAME_MAX] = 0;
1333 #endif
1334 sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf);
1336 ServerSocket = MakeServerSocket();
1337 InitKeytab();
1338 #ifdef ETCSCREENRC
1339 # ifdef ALLOW_SYSSCREENRC
1340 if ((ap = getenv("SYSSCREENRC")))
1341 (void)StartRc(ap, 0);
1342 else
1343 # endif
1344 (void)StartRc(ETCSCREENRC, 0);
1345 #endif
1346 (void)StartRc(RcFileName, 0);
1347 # ifdef UTMPOK
1348 # ifndef UTNOKEEP
1349 InitUtmp();
1350 # endif /* UTNOKEEP */
1351 # endif /* UTMPOK */
1352 if (display)
1354 if (InitTermcap(0, 0))
1356 debug("Could not init termcap - exiting\n");
1357 fcntl(D_userfd, F_SETFL, 0); /* Flush sets FNBLOCK */
1358 freetty();
1359 if (D_userpid)
1360 Kill(D_userpid, SIG_BYE);
1361 eexit(1);
1363 MakeDefaultCanvas();
1364 InitTerm(0);
1365 #ifdef UTMPOK
1366 RemoveLoginSlot();
1367 #endif
1369 else
1370 MakeTermcap(1);
1371 #ifdef LOADAV
1372 InitLoadav();
1373 #endif /* LOADAV */
1374 MakeNewEnv();
1375 signal(SIGHUP, SigHup);
1376 signal(SIGINT, FinitHandler);
1377 signal(SIGQUIT, FinitHandler);
1378 signal(SIGTERM, FinitHandler);
1379 #ifdef BSDJOBS
1380 signal(SIGTTIN, SIG_IGN);
1381 signal(SIGTTOU, SIG_IGN);
1382 #endif
1384 if (display)
1386 brktty(D_userfd);
1387 SetMode(&D_OldMode, &D_NewMode, D_flow, iflag);
1388 /* Note: SetMode must be called _before_ FinishRc. */
1389 SetTTY(D_userfd, &D_NewMode);
1390 if (fcntl(D_userfd, F_SETFL, FNBLOCK))
1391 Msg(errno, "Warning: NBLOCK fcntl failed");
1393 else
1394 brktty(-1); /* just try */
1395 signal(SIGCHLD, SigChld);
1396 #ifdef ETCSCREENRC
1397 # ifdef ALLOW_SYSSCREENRC
1398 if ((ap = getenv("SYSSCREENRC")))
1399 FinishRc(ap);
1400 else
1401 # endif
1402 FinishRc(ETCSCREENRC);
1403 #endif
1404 FinishRc(RcFileName);
1406 debug2("UID %d EUID %d\n", (int)getuid(), (int)geteuid());
1407 if (windows == NULL)
1409 debug("We open one default window, as screenrc did not specify one.\n");
1410 if (MakeWindow(&nwin) == -1)
1412 Msg(0, "Sorry, could not find a PTY.");
1413 sleep(5);
1414 Finit(0);
1415 /* NOTREACHED */
1419 #ifdef HAVE_BRAILLE
1420 StartBraille();
1421 #endif
1423 if (display && default_startup)
1424 display_copyright();
1425 signal(SIGINT, SigInt);
1426 if (rflag && (rflag & 1) == 0 && !quietflag)
1428 Msg(0, "New screen...");
1429 rflag = 0;
1432 serv_read.type = EV_READ;
1433 serv_read.fd = ServerSocket;
1434 serv_read.handler = serv_read_fn;
1435 evenq(&serv_read);
1437 serv_select.pri = -10;
1438 serv_select.type = EV_ALWAYS;
1439 serv_select.handler = serv_select_fn;
1440 evenq(&serv_select);
1442 logflushev.type = EV_TIMEOUT;
1443 logflushev.handler = logflush_fn;
1445 sched();
1446 /* NOTREACHED */
1447 return 0;
1450 void
1451 WindowDied(p, wstat, wstat_valid)
1452 struct win *p;
1453 int wstat;
1454 int wstat_valid;
1456 int killit = 0;
1458 if (ZombieKey_destroy && ZombieKey_onerror && wstat_valid &&
1459 WIFEXITED(wstat) && WEXITSTATUS(wstat) == 0)
1460 killit = 1;
1462 if (ZombieKey_destroy && !killit)
1464 char buf[100], *s, reason[100];
1465 time_t now;
1467 if (wstat_valid) {
1468 if (WIFEXITED(wstat))
1469 if (WEXITSTATUS(wstat))
1470 sprintf(reason, "terminated with exit status %d", WEXITSTATUS(wstat));
1471 else
1472 sprintf(reason, "terminated normally");
1473 else if (WIFSIGNALED(wstat))
1474 sprintf(reason, "terminated with signal %d%s", WTERMSIG(wstat),
1475 #ifdef WCOREDUMP
1476 WCOREDUMP(wstat) ? " (core file generated)" : "");
1477 #else
1478 "");
1479 #endif
1480 } else
1481 sprintf(reason, "detached from window");
1483 (void) time(&now);
1484 s = ctime(&now);
1485 if (s && *s)
1486 s[strlen(s) - 1] = '\0';
1487 debug3("window %d (%s) going into zombie state fd %d",
1488 p->w_number, p->w_title, p->w_ptyfd);
1489 #ifdef UTMPOK
1490 if (p->w_slot != (slot_t)0 && p->w_slot != (slot_t)-1)
1492 RemoveUtmp(p);
1493 p->w_slot = 0; /* "detached" */
1495 #endif
1496 CloseDevice(p);
1498 p->w_deadpid = p->w_pid;
1499 p->w_pid = 0;
1500 ResetWindow(p);
1501 /* p->w_y = p->w_bot; */
1502 p->w_y = MFindUsedLine(p, p->w_bot, 1);
1503 sprintf(buf, "\n\r=== Command %s (%s) ===", reason, s ? s : "?");
1504 WriteString(p, buf, strlen(buf));
1505 WindowChanged(p, 'f');
1507 else
1508 KillWindow(p);
1509 #ifdef UTMPOK
1510 CarefulUtmp();
1511 #endif
1514 static void
1515 SigChldHandler()
1517 struct stat st;
1518 #ifdef DEBUG
1519 fds();
1520 #endif
1521 while (GotSigChld)
1523 GotSigChld = 0;
1524 DoWait();
1525 #ifdef SYSVSIGS
1526 signal(SIGCHLD, SigChld);
1527 #endif
1529 if (stat(SockPath, &st) == -1)
1531 debug1("SigChldHandler: Yuck! cannot stat '%s'\n", SockPath);
1532 if (!RecoverSocket())
1534 debug("SCREEN cannot recover from corrupt Socket, bye\n");
1535 Finit(1);
1537 else
1538 debug1("'%s' reconstructed\n", SockPath);
1540 else
1541 debug2("SigChldHandler: stat '%s' o.k. (%03o)\n", SockPath, (int)st.st_mode);
1544 static sigret_t
1545 SigChld SIGDEFARG
1547 debug("SigChld()\n");
1548 GotSigChld = 1;
1549 SIGRETURN;
1552 sigret_t
1553 SigHup SIGDEFARG
1555 /* Hangup all displays */
1556 while ((display = displays) != 0)
1557 Hangup();
1558 SIGRETURN;
1562 * the backend's Interrupt handler
1563 * we cannot insert the intrc directly, as we never know
1564 * if fore is valid.
1566 static sigret_t
1567 SigInt SIGDEFARG
1569 #if HAZARDOUS
1570 char ibuf;
1572 debug("SigInt()\n");
1573 if (fore && displays)
1575 # if defined(TERMIO) || defined(POSIX)
1576 ibuf = displays->d_OldMode.tio.c_cc[VINTR];
1577 # else
1578 ibuf = displays->d_OldMode.m_tchars.t_intrc;
1579 # endif
1580 fore->w_inlen = 0;
1581 write(fore->w_ptyfd, &ibuf, 1);
1583 #else
1584 signal(SIGINT, SigInt);
1585 debug("SigInt() careful\n");
1586 InterruptPlease = 1;
1587 #endif
1588 SIGRETURN;
1591 static sigret_t
1592 CoreDump SIGDEFARG
1594 struct display *disp;
1595 char buf[80];
1597 #if defined(SYSVSIGS) && defined(SIGHASARG)
1598 signal(sigsig, SIG_IGN);
1599 #endif
1600 setgid(getgid());
1601 setuid(getuid());
1602 unlink("core");
1603 #ifdef SIGHASARG
1604 sprintf(buf, "\r\n[screen caught signal %d.%s]\r\n", sigsig,
1605 #else
1606 sprintf(buf, "\r\n[screen caught a fatal signal.%s]\r\n",
1607 #endif
1608 #if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
1610 #else /* SHADOWPW && !DEBUG */
1611 " (core dumped)"
1612 #endif /* SHADOWPW && !DEBUG */
1614 for (disp = displays; disp; disp = disp->d_next)
1616 fcntl(disp->d_userfd, F_SETFL, 0);
1617 SetTTY(disp->d_userfd, &D_OldMode);
1618 write(disp->d_userfd, buf, strlen(buf));
1619 Kill(disp->d_userpid, SIG_BYE);
1621 #if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
1622 Kill(getpid(), SIGKILL);
1623 eexit(11);
1624 #else /* SHADOWPW && !DEBUG */
1625 abort();
1626 #endif /* SHADOWPW && !DEBUG */
1627 SIGRETURN;
1630 static void
1631 DoWait()
1633 register int pid;
1634 struct win *p, *next;
1635 #ifdef BSDWAIT
1636 union wait wstat;
1637 #else
1638 int wstat;
1639 #endif
1641 #ifdef BSDJOBS
1642 # ifndef BSDWAIT
1643 while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
1644 # else
1645 # ifdef USE_WAIT2
1647 * From: rouilj@sni-usa.com (John Rouillard)
1648 * note that WUNTRACED is not documented to work, but it is defined in
1649 * /usr/include/sys/wait.h, so it may work
1651 while ((pid = wait2(&wstat, WNOHANG | WUNTRACED )) > 0)
1652 # else /* USE_WAIT2 */
1653 while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
1654 # endif /* USE_WAIT2 */
1655 # endif
1656 #else /* BSDJOBS */
1657 while ((pid = wait(&wstat)) < 0)
1658 if (errno != EINTR)
1659 break;
1660 if (pid > 0)
1661 #endif /* BSDJOBS */
1663 for (p = windows; p; p = next)
1665 next = p->w_next;
1666 if ( (p->w_pid && pid == p->w_pid) ||
1667 (p->w_deadpid && pid == p->w_deadpid) )
1669 /* child has ceased to exist */
1670 p->w_pid = 0;
1672 #ifdef BSDJOBS
1673 if (WIFSTOPPED(wstat))
1675 debug3("Window %d pid %d: WIFSTOPPED (sig %d)\n", p->w_number, pid, WSTOPSIG(wstat));
1676 #ifdef SIGTTIN
1677 if (WSTOPSIG(wstat) == SIGTTIN)
1679 Msg(0, "Suspended (tty input)");
1680 continue;
1682 #endif
1683 #ifdef SIGTTOU
1684 if (WSTOPSIG(wstat) == SIGTTOU)
1686 Msg(0, "Suspended (tty output)");
1687 continue;
1689 #endif
1690 /* Try to restart process */
1691 Msg(0, "Child has been stopped, restarting.");
1692 if (killpg(pid, SIGCONT))
1693 kill(pid, SIGCONT);
1695 else
1696 #endif
1698 WindowDied(p, wstat, 1);
1700 break;
1702 #ifdef PSEUDOS
1703 if (p->w_pwin && pid == p->w_pwin->p_pid)
1705 debug2("pseudo of win Nr %d died. pid == %d\n", p->w_number, p->w_pwin->p_pid);
1706 FreePseudowin(p);
1707 break;
1709 #endif
1711 if (p == 0)
1713 debug1("pid %d not found - hope that's ok\n", pid);
1719 static sigret_t
1720 FinitHandler SIGDEFARG
1722 #ifdef SIGHASARG
1723 debug1("FinitHandler called, sig %d.\n", sigsig);
1724 #else
1725 debug("FinitHandler called.\n");
1726 #endif
1727 Finit(1);
1728 SIGRETURN;
1731 void
1732 Finit(i)
1733 int i;
1735 signal(SIGCHLD, SIG_DFL);
1736 signal(SIGHUP, SIG_IGN);
1737 debug1("Finit(%d);\n", i);
1738 while (windows)
1740 struct win *p = windows;
1741 windows = windows->w_next;
1742 FreeWindow(p);
1744 if (ServerSocket != -1)
1746 debug1("we unlink(%s)\n", SockPath);
1747 #ifdef USE_SETEUID
1748 xseteuid(real_uid);
1749 xsetegid(real_gid);
1750 #endif
1751 (void) unlink(SockPath);
1752 #ifdef USE_SETEUID
1753 xseteuid(eff_uid);
1754 xsetegid(eff_gid);
1755 #endif
1757 for (display = displays; display; display = display->d_next)
1759 if (D_status)
1760 RemoveStatus();
1761 FinitTerm();
1762 #ifdef UTMPOK
1763 RestoreLoginSlot();
1764 #endif
1765 AddStr("[screen is terminating]\r\n");
1766 Flush();
1767 SetTTY(D_userfd, &D_OldMode);
1768 fcntl(D_userfd, F_SETFL, 0);
1769 freetty();
1770 Kill(D_userpid, SIG_BYE);
1773 * we _cannot_ call eexit(i) here,
1774 * instead of playing with the Socket above. Sigh.
1776 exit(i);
1779 void
1780 eexit(e)
1781 int e;
1783 debug("eexit\n");
1784 if (ServerSocket != -1)
1786 debug1("we unlink(%s)\n", SockPath);
1787 setgid(real_gid);
1788 setuid(real_uid);
1789 (void) unlink(SockPath);
1791 exit(e);
1794 void
1795 Hangup()
1797 if (display == 0)
1798 return;
1799 debug1("Hangup %x\n", display);
1800 if (D_userfd >= 0)
1802 close(D_userfd);
1803 D_userfd = -1;
1805 if (auto_detach || displays->d_next)
1806 Detach(D_HANGUP);
1807 else
1808 Finit(0);
1812 * Detach now has the following modes:
1813 *D_DETACH SIG_BYE detach backend and exit attacher
1814 *D_HANGUP SIG_BYE detach backend and exit attacher
1815 *D_STOP SIG_STOP stop attacher (and detach backend)
1816 *D_REMOTE SIG_BYE remote detach -- reattach to new attacher
1817 *D_POWER SIG_POWER_BYE power detach -- attacher kills his parent
1818 *D_REMOTE_POWER SIG_POWER_BYE remote power detach -- both
1819 *D_LOCK SIG_LOCK lock the attacher
1820 * (jw)
1821 * we always remove our utmp slots. (even when "lock" or "stop")
1822 * Note: Take extra care here, we may be called by interrupt!
1824 void
1825 Detach(mode)
1826 int mode;
1828 int sign = 0, pid;
1829 struct canvas *cv;
1830 struct win *p;
1832 if (display == 0)
1833 return;
1835 #define AddStrSock(msg) do { \
1836 if (SockName) \
1838 AddStr("[" msg " from "); \
1839 AddStr(SockName); \
1840 AddStr("]\r\n"); \
1842 else \
1843 AddStr("[" msg "]\r\n"); \
1844 } while (0)
1846 signal(SIGHUP, SIG_IGN);
1847 debug1("Detach(%d)\n", mode);
1848 if (D_status)
1849 RemoveStatus();
1850 FinitTerm();
1851 if (!display)
1852 return;
1853 switch (mode)
1855 case D_HANGUP:
1856 sign = SIG_BYE;
1857 break;
1858 case D_DETACH:
1859 AddStrSock("detached");
1860 sign = SIG_BYE;
1861 break;
1862 #ifdef BSDJOBS
1863 case D_STOP:
1864 sign = SIG_STOP;
1865 break;
1866 #endif
1867 #ifdef REMOTE_DETACH
1868 case D_REMOTE:
1869 AddStrSock("remote detached");
1870 sign = SIG_BYE;
1871 break;
1872 #endif
1873 #ifdef POW_DETACH
1874 case D_POWER:
1875 AddStrSock("power detached");
1876 if (PowDetachString)
1878 AddStr(PowDetachString);
1879 AddStr("\r\n");
1881 sign = SIG_POWER_BYE;
1882 break;
1883 #ifdef REMOTE_DETACH
1884 case D_REMOTE_POWER:
1885 AddStrSock("remote power detached");
1886 if (PowDetachString)
1888 AddStr(PowDetachString);
1889 AddStr("\r\n");
1891 sign = SIG_POWER_BYE;
1892 break;
1893 #endif
1894 #endif
1895 case D_LOCK:
1896 ClearAll();
1897 sign = SIG_LOCK;
1898 /* tell attacher to lock terminal with a lockprg. */
1899 break;
1901 #ifdef UTMPOK
1902 if (displays->d_next == 0)
1904 for (p = windows; p; p = p->w_next)
1906 if (p->w_slot != (slot_t) -1 && !(p->w_lflag & 2))
1908 RemoveUtmp(p);
1910 * Set the slot to 0 to get the window
1911 * logged in again.
1913 p->w_slot = (slot_t) 0;
1917 if (mode != D_HANGUP)
1918 RestoreLoginSlot();
1919 #endif
1920 if (displays->d_next == 0 && console_window)
1922 if (TtyGrabConsole(console_window->w_ptyfd, 0, "detach"))
1924 debug("could not release console - killing window\n");
1925 KillWindow(console_window);
1926 display = displays; /* restore display */
1929 if (D_fore)
1931 #ifdef MULTIUSER
1932 ReleaseAutoWritelock(display, D_fore);
1933 #endif
1934 D_user->u_detachwin = D_fore->w_number;
1935 D_user->u_detachotherwin = D_other ? D_other->w_number : -1;
1937 AutosaveLayout(D_layout);
1938 layout_last = D_layout;
1939 for (cv = D_cvlist; cv; cv = cv->c_next)
1941 p = Layer2Window(cv->c_layer);
1942 SetCanvasWindow(cv, 0);
1943 if (p)
1944 WindowChanged(p, 'u');
1947 pid = D_userpid;
1948 debug2("display: %#x displays: %#x\n", (unsigned int)display, (unsigned int)displays);
1949 FreeDisplay();
1950 if (displays == 0)
1951 /* Flag detached-ness */
1952 (void) chsock();
1954 * tell father what to do. We do that after we
1955 * freed the tty, thus getty feels more comfortable on hpux
1956 * if it was a power detach.
1958 Kill(pid, sign);
1959 debug2("Detach: Signal %d to Attacher(%d)!\n", sign, pid);
1960 debug("Detach returns, we are successfully detached.\n");
1961 signal(SIGHUP, SigHup);
1962 #undef AddStrSock
1965 static int
1966 IsSymbol(e, s)
1967 char *e, *s;
1969 register int l;
1971 l = strlen(s);
1972 return strncmp(e, s, l) == 0 && e[l] == '=';
1975 void
1976 MakeNewEnv()
1978 register char **op, **np;
1979 static char stybuf[MAXSTR];
1981 for (op = environ; *op; ++op)
1983 if (NewEnv)
1984 free((char *)NewEnv);
1985 NewEnv = np = (char **) malloc((unsigned) (op - environ + 7 + 1) * sizeof(char **));
1986 if (!NewEnv)
1987 Panic(0, strnomem);
1988 sprintf(stybuf, "STY=%s", strlen(SockName) <= MAXSTR - 5 ? SockName : "?");
1989 *np++ = stybuf; /* NewEnv[0] */
1990 *np++ = Term; /* NewEnv[1] */
1991 np++; /* room for SHELL */
1992 #ifdef TIOCSWINSZ
1993 np += 2; /* room for TERMCAP and WINDOW */
1994 #else
1995 np += 4; /* room for TERMCAP WINDOW LINES COLUMNS */
1996 #endif
1998 for (op = environ; *op; ++op)
2000 if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP")
2001 && !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW")
2002 && !IsSymbol(*op, "SCREENCAP") && !IsSymbol(*op, "SHELL")
2003 && !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS")
2005 *np++ = *op;
2007 *np = 0;
2010 void
2011 /*VARARGS2*/
2012 #if defined(USEVARARGS) && defined(__STDC__)
2013 Msg(int err, char *fmt, VA_DOTS)
2014 #else
2015 Msg(err, fmt, VA_DOTS)
2016 int err;
2017 char *fmt;
2018 VA_DECL
2019 #endif
2021 VA_LIST(ap)
2022 char buf[MAXPATHLEN*2];
2023 char *p = buf;
2025 VA_START(ap, fmt);
2026 fmt = DoNLS(fmt);
2027 (void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap));
2028 VA_END(ap);
2029 if (err)
2031 p += strlen(p);
2032 *p++ = ':';
2033 *p++ = ' ';
2034 strncpy(p, strerror(err), buf + sizeof(buf) - p - 1);
2035 buf[sizeof(buf) - 1] = 0;
2037 debug2("Msg('%s') (%#x);\n", buf, (unsigned int)display);
2039 if (display && displays)
2040 MakeStatus(buf);
2041 else if (displays)
2043 for (display = displays; display; display = display->d_next)
2044 MakeStatus(buf);
2046 else if (display)
2048 /* no displays but a display - must have forked.
2049 * send message to backend!
2051 char *tty = D_usertty;
2052 struct display *olddisplay = display;
2053 display = 0; /* only send once */
2054 SendErrorMsg(tty, buf);
2055 display = olddisplay;
2057 else
2058 printf("%s\r\n", buf);
2062 * Call FinitTerm for all displays, write a message to each and call eexit();
2064 void
2065 /*VARARGS2*/
2066 #if defined(USEVARARGS) && defined(__STDC__)
2067 Panic(int err, char *fmt, VA_DOTS)
2068 #else
2069 Panic(err, fmt, VA_DOTS)
2070 int err;
2071 char *fmt;
2072 VA_DECL
2073 #endif
2075 VA_LIST(ap)
2076 char buf[MAXPATHLEN*2];
2077 char *p = buf;
2079 VA_START(ap, fmt);
2080 fmt = DoNLS(fmt);
2081 (void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap));
2082 VA_END(ap);
2083 if (err)
2085 p += strlen(p);
2086 *p++ = ':';
2087 *p++ = ' ';
2088 strncpy(p, strerror(err), buf + sizeof(buf) - p - 1);
2089 buf[sizeof(buf) - 1] = 0;
2091 debug3("Panic('%s'); display=%x displays=%x\n", buf, display, displays);
2092 if (displays == 0 && display == 0)
2094 printf("%s\r\n", buf);
2095 if (PanicPid)
2096 Kill(PanicPid, SIG_BYE);
2098 else if (displays == 0)
2100 /* no displays but a display - must have forked.
2101 * send message to backend!
2103 char *tty = D_usertty;
2104 display = 0;
2105 SendErrorMsg(tty, buf);
2106 sleep(2);
2107 _exit(1);
2109 else
2110 for (display = displays; display; display = display->d_next)
2112 if (D_status)
2113 RemoveStatus();
2114 FinitTerm();
2115 Flush();
2116 #ifdef UTMPOK
2117 RestoreLoginSlot();
2118 #endif
2119 SetTTY(D_userfd, &D_OldMode);
2120 fcntl(D_userfd, F_SETFL, 0);
2121 write(D_userfd, buf, strlen(buf));
2122 write(D_userfd, "\n", 1);
2123 freetty();
2124 if (D_userpid)
2125 Kill(D_userpid, SIG_BYE);
2127 #ifdef MULTIUSER
2128 if (tty_oldmode >= 0)
2130 # ifdef USE_SETEUID
2131 if (setuid(own_uid))
2132 xseteuid(own_uid); /* may be a loop. sigh. */
2133 # else
2134 setuid(own_uid);
2135 # endif
2136 debug1("Panic: changing back modes from %s\n", attach_tty);
2137 chmod(attach_tty, tty_oldmode);
2139 #endif
2140 eexit(1);
2145 * '^' is allowed as an escape mechanism for control characters. jw.
2147 * Added time insertion using ideas/code from /\ndy Jones
2148 * (andy@lingua.cltr.uq.OZ.AU) - thanks a lot!
2152 #ifndef USE_LOCALE
2153 static const char days[] = "SunMonTueWedThuFriSat";
2154 static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
2155 #endif
2157 static char winmsg_buf[MAXSTR];
2158 #define MAX_WINMSG_REND 16 /* rendition changes */
2159 static int winmsg_rend[MAX_WINMSG_REND];
2160 static int winmsg_rendpos[MAX_WINMSG_REND];
2161 static int winmsg_numrend;
2163 static char *
2164 pad_expand(buf, p, numpad, padlen)
2165 char *buf;
2166 char *p;
2167 int numpad;
2168 int padlen;
2170 char *pn, *pn2;
2171 int i, r;
2173 padlen = padlen - (p - buf); /* space for rent */
2174 if (padlen < 0)
2175 padlen = 0;
2176 pn2 = pn = p + padlen;
2177 r = winmsg_numrend;
2178 while (p >= buf)
2180 if (r && *p != 127 && p - buf == winmsg_rendpos[r - 1])
2182 winmsg_rendpos[--r] = pn - buf;
2183 continue;
2185 *pn-- = *p;
2186 if (*p-- == 127)
2188 pn[1] = ' ';
2189 i = numpad > 0 ? (padlen + numpad - 1) / numpad : 0;
2190 padlen -= i;
2191 while (i-- > 0)
2192 *pn-- = ' ';
2193 numpad--;
2194 if (r && p - buf == winmsg_rendpos[r - 1])
2195 winmsg_rendpos[--r] = pn - buf;
2198 return pn2;
2201 struct backtick {
2202 struct backtick *next;
2203 int num;
2204 int tick;
2205 int lifespan;
2206 time_t bestbefore;
2207 char result[MAXSTR];
2208 char **cmdv;
2209 struct event ev;
2210 char *buf;
2211 int bufi;
2214 struct backtick *backticks;
2216 static void
2217 backtick_filter(bt)
2218 struct backtick *bt;
2220 char *p, *q;
2221 int c;
2223 for (p = q = bt->result; (c = (unsigned char)*p++) != 0;)
2225 if (c == '\t')
2226 c = ' ';
2227 if (c >= ' ' || c == '\005')
2228 *q++ = c;
2230 *q = 0;
2233 static void
2234 backtick_fn(ev, data)
2235 struct event *ev;
2236 char *data;
2238 struct backtick *bt;
2239 int i, j, k, l;
2241 bt = (struct backtick *)data;
2242 debug1("backtick_fn for #%d\n", bt->num);
2243 i = bt->bufi;
2244 l = read(ev->fd, bt->buf + i, MAXSTR - i);
2245 if (l <= 0)
2247 debug1("EOF on backtick #%d\n", bt->num);
2248 evdeq(ev);
2249 close(ev->fd);
2250 ev->fd = -1;
2251 return;
2253 debug1("read %d bytes\n", l);
2254 i += l;
2255 for (j = 0; j < l; j++)
2256 if (bt->buf[i - j - 1] == '\n')
2257 break;
2258 if (j < l)
2260 for (k = i - j - 2; k >= 0; k--)
2261 if (bt->buf[k] == '\n')
2262 break;
2263 k++;
2264 bcopy(bt->buf + k, bt->result, i - j - k);
2265 bt->result[i - j - k - 1] = 0;
2266 backtick_filter(bt);
2267 WindowChanged(0, '`');
2269 if (j == l && i == MAXSTR)
2271 j = MAXSTR/2;
2272 l = j + 1;
2274 if (j < l)
2276 if (j)
2277 bcopy(bt->buf + i - j, bt->buf, j);
2278 i = j;
2280 bt->bufi = i;
2283 void
2284 setbacktick(num, lifespan, tick, cmdv)
2285 int num;
2286 int lifespan;
2287 int tick;
2288 char **cmdv;
2290 struct backtick **btp, *bt;
2291 char **v;
2293 debug1("setbacktick called for backtick #%d\n", num);
2294 for (btp = &backticks; (bt = *btp) != 0; btp = &bt->next)
2295 if (bt->num == num)
2296 break;
2297 if (!bt && !cmdv)
2298 return;
2299 if (bt)
2301 for (v = bt->cmdv; *v; v++)
2302 free(*v);
2303 free(bt->cmdv);
2304 if (bt->buf)
2305 free(bt->buf);
2306 if (bt->ev.fd >= 0)
2307 close(bt->ev.fd);
2308 evdeq(&bt->ev);
2310 if (bt && !cmdv)
2312 *btp = bt->next;
2313 free(bt);
2314 return;
2316 if (!bt)
2318 bt = (struct backtick *)malloc(sizeof *bt);
2319 if (!bt)
2321 Msg(0, strnomem);
2322 return;
2324 bzero(bt, sizeof(*bt));
2325 bt->next = 0;
2326 *btp = bt;
2328 bt->num = num;
2329 bt->tick = tick;
2330 bt->lifespan = lifespan;
2331 bt->bestbefore = 0;
2332 bt->result[0] = 0;
2333 bt->buf = 0;
2334 bt->bufi = 0;
2335 bt->cmdv = cmdv;
2336 bt->ev.fd = -1;
2337 if (bt->tick == 0 && bt->lifespan == 0)
2339 debug("setbacktick: continuous mode\n");
2340 bt->buf = (char *)malloc(MAXSTR);
2341 if (bt->buf == 0)
2343 Msg(0, strnomem);
2344 setbacktick(num, 0, 0, (char **)0);
2345 return;
2347 bt->ev.type = EV_READ;
2348 bt->ev.fd = readpipe(bt->cmdv);
2349 bt->ev.handler = backtick_fn;
2350 bt->ev.data = (char *)bt;
2351 if (bt->ev.fd >= 0)
2352 evenq(&bt->ev);
2356 static char *
2357 runbacktick(bt, tickp, now)
2358 struct backtick *bt;
2359 int *tickp;
2360 time_t now;
2362 int f, i, l, j;
2363 time_t now2;
2365 debug1("runbacktick called for backtick #%d\n", bt->num);
2366 if (bt->tick && (!*tickp || bt->tick < *tickp))
2367 *tickp = bt->tick;
2368 if ((bt->lifespan == 0 && bt->tick == 0) || now < bt->bestbefore)
2370 debug1("returning old result (%d)\n", bt->lifespan);
2371 return bt->result;
2373 f = readpipe(bt->cmdv);
2374 if (f == -1)
2375 return bt->result;
2376 i = 0;
2377 while ((l = read(f, bt->result + i, sizeof(bt->result) - i)) > 0)
2379 debug1("runbacktick: read %d bytes\n", l);
2380 i += l;
2381 for (j = 1; j < l; j++)
2382 if (bt->result[i - j - 1] == '\n')
2383 break;
2384 if (j == l && i == sizeof(bt->result))
2386 j = sizeof(bt->result) / 2;
2387 l = j + 1;
2389 if (j < l)
2391 bcopy(bt->result + i - j, bt->result, j);
2392 i = j;
2395 close(f);
2396 bt->result[sizeof(bt->result) - 1] = '\n';
2397 if (i && bt->result[i - 1] == '\n')
2398 i--;
2399 debug1("runbacktick: finished, %d bytes\n", i);
2400 bt->result[i] = 0;
2401 backtick_filter(bt);
2402 (void)time(&now2);
2403 bt->bestbefore = now2 + bt->lifespan;
2404 return bt->result;
2407 char *
2408 MakeWinMsgEv(str, win, esc, padlen, ev, rec)
2409 char *str;
2410 struct win *win;
2411 int esc;
2412 int padlen;
2413 struct event *ev;
2414 int rec;
2416 static int tick;
2417 char *s = str;
2418 register char *p = winmsg_buf;
2419 register int ctrl;
2420 struct timeval now;
2421 struct tm *tm;
2422 int l, i, r;
2423 int num;
2424 int zeroflg;
2425 int longflg;
2426 int minusflg;
2427 int plusflg;
2428 int qmflag = 0, omflag = 0, qmnumrend = 0;
2429 char *qmpos = 0;
2430 int numpad = 0;
2431 int lastpad = 0;
2432 int truncpos = -1;
2433 int truncper = 0;
2434 int trunclong = 0;
2435 struct backtick *bt;
2437 if (winmsg_numrend >= 0)
2438 winmsg_numrend = 0;
2439 else
2440 winmsg_numrend = -winmsg_numrend;
2442 tick = 0;
2443 tm = 0;
2444 ctrl = 0;
2445 gettimeofday(&now, NULL);
2446 for (; *s && (l = winmsg_buf + MAXSTR - 1 - p) > 0; s++, p++)
2448 *p = *s;
2449 if (ctrl)
2451 ctrl = 0;
2452 if (*s != '^' && *s >= 64)
2453 *p &= 0x1f;
2454 continue;
2456 if (*s != esc)
2458 if (esc == '%')
2460 switch (*s)
2462 #if 0
2463 case '~':
2464 *p = BELL;
2465 break;
2466 #endif
2467 case '^':
2468 ctrl = 1;
2469 *p-- = '^';
2470 break;
2471 default:
2472 break;
2475 continue;
2477 if (*++s == esc) /* double escape ? */
2478 continue;
2479 if ((plusflg = *s == '+') != 0)
2480 s++;
2481 if ((minusflg = *s == '-') != 0)
2482 s++;
2483 if ((zeroflg = *s == '0') != 0)
2484 s++;
2485 num = 0;
2486 while(*s >= '0' && *s <= '9')
2487 num = num * 10 + (*s++ - '0');
2488 if ((longflg = *s == 'L') != 0)
2489 s++;
2490 switch (*s)
2492 case '?':
2493 p--;
2494 if (qmpos)
2496 if ((!qmflag && !omflag) || omflag == 1)
2498 p = qmpos;
2499 if (qmnumrend < winmsg_numrend)
2500 winmsg_numrend = qmnumrend;
2502 qmpos = 0;
2503 break;
2505 qmpos = p;
2506 qmnumrend = winmsg_numrend;
2507 qmflag = omflag = 0;
2508 break;
2509 case ':':
2510 p--;
2511 if (!qmpos)
2512 break;
2513 if (qmflag && omflag != 1)
2515 omflag = 1;
2516 qmpos = p;
2517 qmnumrend = winmsg_numrend;
2519 else
2521 p = qmpos;
2522 if (qmnumrend < winmsg_numrend)
2523 winmsg_numrend = qmnumrend;
2524 omflag = -1;
2526 break;
2527 case 'd': case 'D': case 'm': case 'M': case 'y': case 'Y':
2528 case 'a': case 'A': case 's': case 'c': case 'C':
2529 if (l < 4)
2530 break;
2531 if (tm == 0)
2533 time_t nowsec = now.tv_sec;
2534 tm = localtime(&nowsec);
2536 qmflag = 1;
2537 if (!tick || tick > 3600)
2538 tick = 3600;
2539 switch (*s)
2541 case 'd':
2542 sprintf(p, "%02d", tm->tm_mday % 100);
2543 break;
2544 case 'D':
2545 #ifdef USE_LOCALE
2546 strftime(p, l, (longflg ? "%A" : "%a"), tm);
2547 #else
2548 sprintf(p, "%3.3s", days + 3 * tm->tm_wday);
2549 #endif
2550 break;
2551 case 'm':
2552 sprintf(p, "%02d", tm->tm_mon + 1);
2553 break;
2554 case 'M':
2555 #ifdef USE_LOCALE
2556 strftime(p, l, (longflg ? "%B" : "%b"), tm);
2557 #else
2558 sprintf(p, "%3.3s", months + 3 * tm->tm_mon);
2559 #endif
2560 break;
2561 case 'y':
2562 sprintf(p, "%02d", tm->tm_year % 100);
2563 break;
2564 case 'Y':
2565 sprintf(p, "%04d", tm->tm_year + 1900);
2566 break;
2567 case 'a':
2568 sprintf(p, tm->tm_hour >= 12 ? "pm" : "am");
2569 break;
2570 case 'A':
2571 sprintf(p, tm->tm_hour >= 12 ? "PM" : "AM");
2572 break;
2573 case 's':
2574 sprintf(p, "%02d", tm->tm_sec);
2575 tick = 1;
2576 break;
2577 case 'c':
2578 sprintf(p, zeroflg ? "%02d:%02d" : "%2d:%02d", tm->tm_hour, tm->tm_min);
2579 if (!tick || tick > 60)
2580 tick = 60;
2581 break;
2582 case 'C':
2583 sprintf(p, zeroflg ? "%02d:%02d" : "%2d:%02d", (tm->tm_hour + 11) % 12 + 1, tm->tm_min);
2584 if (!tick || tick > 60)
2585 tick = 60;
2586 break;
2587 default:
2588 break;
2590 p += strlen(p) - 1;
2591 break;
2592 case 'l':
2593 #ifdef LOADAV
2594 *p = 0;
2595 if (l > 20)
2596 AddLoadav(p);
2597 if (*p)
2599 qmflag = 1;
2600 p += strlen(p) - 1;
2602 else
2603 *p = '?';
2604 if (!tick || tick > 60)
2605 tick = 60;
2606 #else
2607 *p = '?';
2608 #endif
2609 p += strlen(p) - 1;
2610 break;
2611 case '`':
2612 case 'h':
2613 if (rec >= 10 || (*s == 'h' && (win == 0 || win->w_hstatus == 0 || *win->w_hstatus == 0)))
2615 p--;
2616 break;
2618 if (*s == '`')
2620 for (bt = backticks; bt; bt = bt->next)
2621 if (bt->num == num)
2622 break;
2623 if (bt == 0)
2625 p--;
2626 break;
2630 char savebuf[sizeof(winmsg_buf)];
2631 int oldtick = tick;
2632 int oldnumrend = winmsg_numrend;
2634 *p = 0;
2635 strcpy(savebuf, winmsg_buf);
2636 winmsg_numrend = -winmsg_numrend;
2637 MakeWinMsgEv(*s == 'h' ? win->w_hstatus : runbacktick(bt, &oldtick, now.tv_sec), win, '\005', 0, (struct event *)0, rec + 1);
2638 debug2("oldtick=%d tick=%d\n", oldtick, tick);
2639 if (!tick || oldtick < tick)
2640 tick = oldtick;
2641 if ((int)strlen(winmsg_buf) < l)
2642 strcat(savebuf, winmsg_buf);
2643 strcpy(winmsg_buf, savebuf);
2644 while (oldnumrend < winmsg_numrend)
2645 winmsg_rendpos[oldnumrend++] += p - winmsg_buf;
2646 if (*p)
2647 qmflag = 1;
2648 p += strlen(p) - 1;
2650 break;
2651 case 'w':
2652 case 'W':
2654 struct win *oldfore = 0;
2655 char *ss;
2657 if (display)
2659 oldfore = D_fore;
2660 D_fore = win;
2662 ss = AddWindows(p, l - 1, (*s == 'w' ? 0 : 1) | (longflg ? 0 : 2) | (plusflg ? 4 : 0), win ? win->w_number : -1);
2663 if (minusflg)
2664 *ss = 0;
2665 if (display)
2666 D_fore = oldfore;
2668 if (*p)
2669 qmflag = 1;
2670 p += strlen(p) - 1;
2671 break;
2672 case 'u':
2673 *p = 0;
2674 if (win)
2675 AddOtherUsers(p, l - 1, win);
2676 if (*p)
2677 qmflag = 1;
2678 p += strlen(p) - 1;
2679 break;
2680 case 'f':
2681 *p = 0;
2682 if (win)
2683 AddWindowFlags(p, l - 1, win);
2684 if (*p)
2685 qmflag = 1;
2686 p += strlen(p) - 1;
2687 break;
2688 case 't':
2689 *p = 0;
2690 if (win && (int)strlen(win->w_title) < l)
2692 strcpy(p, win->w_title);
2693 if (*p)
2694 qmflag = 1;
2696 p += strlen(p) - 1;
2697 break;
2698 case '{':
2700 char rbuf[128];
2701 s++;
2702 for (i = 0; i < 127; i++)
2703 if (s[i] && s[i] != '}')
2704 rbuf[i] = s[i];
2705 else
2706 break;
2707 if (s[i] == '}' && winmsg_numrend < MAX_WINMSG_REND)
2709 r = -1;
2710 rbuf[i] = 0;
2711 debug1("MakeWinMsg attrcolor %s\n", rbuf);
2712 if (i != 1 || rbuf[0] != '-')
2713 r = ParseAttrColor(rbuf, (char *)0, 0);
2714 if (r != -1 || (i == 1 && rbuf[0] == '-'))
2716 winmsg_rend[winmsg_numrend] = r;
2717 winmsg_rendpos[winmsg_numrend] = p - winmsg_buf;
2718 winmsg_numrend++;
2721 s += i;
2722 p--;
2724 break;
2725 case 'H':
2726 *p = 0;
2727 if ((int)strlen(HostName) < l)
2729 strcpy(p, HostName);
2730 if (*p)
2731 qmflag = 1;
2733 p += strlen(p) - 1;
2734 break;
2735 case 'S':
2737 char *session_name;
2738 *p = 0;
2739 session_name = strchr(SockName, '.') + 1;
2740 if ((int)strlen(session_name) < l)
2742 strcpy(p, session_name);
2743 if (*p)
2744 qmflag = 1;
2746 p += strlen(p) - 1;
2748 break;
2749 case 'p':
2751 sprintf(p, "%d", (plusflg && display) ? D_userpid : getpid());
2752 p += strlen(p) - 1;
2754 break;
2755 case 'F':
2756 p--;
2757 /* small hack */
2758 if (display && ((ev && ev == &D_forecv->c_captev) || (!ev && win && win == D_fore)))
2759 minusflg = !minusflg;
2760 if (minusflg)
2761 qmflag = 1;
2762 break;
2763 case '>':
2764 truncpos = p - winmsg_buf;
2765 truncper = num > 100 ? 100 : num;
2766 trunclong = longflg;
2767 p--;
2768 break;
2769 case '=':
2770 case '<':
2771 *p = ' ';
2772 if (num || zeroflg || plusflg || longflg || (*s != '='))
2774 /* expand all pads */
2775 if (minusflg)
2777 num = (plusflg ? lastpad : padlen) - num;
2778 if (!plusflg && padlen == 0)
2779 num = p - winmsg_buf;
2780 plusflg = 0;
2782 else if (!zeroflg)
2784 if (*s != '=' && num == 0 && !plusflg)
2785 num = 100;
2786 if (num > 100)
2787 num = 100;
2788 if (padlen == 0)
2789 num = p - winmsg_buf;
2790 else
2791 num = (padlen - (plusflg ? lastpad : 0)) * num / 100;
2793 if (num < 0)
2794 num = 0;
2795 if (plusflg)
2796 num += lastpad;
2797 if (num > MAXSTR - 1)
2798 num = MAXSTR - 1;
2799 if (numpad)
2800 p = pad_expand(winmsg_buf, p, numpad, num);
2801 numpad = 0;
2802 if (p - winmsg_buf > num && !longflg)
2804 int left, trunc;
2806 if (truncpos == -1)
2808 truncpos = lastpad;
2809 truncper = 0;
2811 trunc = lastpad + truncper * (num - lastpad) / 100;
2812 if (trunc > num)
2813 trunc = num;
2814 if (trunc < lastpad)
2815 trunc = lastpad;
2816 left = truncpos - trunc;
2817 if (left > p - winmsg_buf - num)
2818 left = p - winmsg_buf - num;
2819 debug1("lastpad = %d, ", lastpad);
2820 debug3("truncpos = %d, trunc = %d, left = %d\n", truncpos, trunc, left);
2821 if (left > 0)
2823 if (left + lastpad > p - winmsg_buf)
2824 left = p - winmsg_buf - lastpad;
2825 if (p - winmsg_buf - lastpad - left > 0)
2826 bcopy(winmsg_buf + lastpad + left, winmsg_buf + lastpad, p - winmsg_buf - lastpad - left);
2827 p -= left;
2828 r = winmsg_numrend;
2829 while (r && winmsg_rendpos[r - 1] > lastpad)
2831 r--;
2832 winmsg_rendpos[r] -= left;
2833 if (winmsg_rendpos[r] < lastpad)
2834 winmsg_rendpos[r] = lastpad;
2836 if (trunclong)
2838 if (p - winmsg_buf > lastpad)
2839 winmsg_buf[lastpad] = '.';
2840 if (p - winmsg_buf > lastpad + 1)
2841 winmsg_buf[lastpad + 1] = '.';
2842 if (p - winmsg_buf > lastpad + 2)
2843 winmsg_buf[lastpad + 2] = '.';
2846 if (p - winmsg_buf > num)
2848 p = winmsg_buf + num;
2849 if (trunclong)
2851 if (num - 1 >= lastpad)
2852 p[-1] = '.';
2853 if (num - 2 >= lastpad)
2854 p[-2] = '.';
2855 if (num - 3 >= lastpad)
2856 p[-3] = '.';
2858 r = winmsg_numrend;
2859 while (r && winmsg_rendpos[r - 1] > num)
2860 winmsg_rendpos[--r] = num;
2862 truncpos = -1;
2863 trunclong = 0;
2864 if (lastpad > p - winmsg_buf)
2865 lastpad = p - winmsg_buf;
2866 debug1("lastpad now %d\n", lastpad);
2868 if (*s == '=')
2870 while (p - winmsg_buf < num)
2871 *p++ = ' ';
2872 lastpad = p - winmsg_buf;
2873 truncpos = -1;
2874 trunclong = 0;
2875 debug1("lastpad2 now %d\n", lastpad);
2877 p--;
2879 else if (padlen)
2881 *p = 127; /* internal pad representation */
2882 numpad++;
2884 break;
2885 case 'n':
2886 s++;
2887 /* FALLTHROUGH */
2888 default:
2889 s--;
2890 if (l > 10 + num)
2892 if (num == 0)
2893 num = 1;
2894 if (!win)
2895 sprintf(p, "%*s", num, num > 1 ? "--" : "-");
2896 else
2897 sprintf(p, "%*d", num, win->w_number);
2898 qmflag = 1;
2899 p += strlen(p) - 1;
2901 break;
2904 if (qmpos && !qmflag)
2905 p = qmpos + 1;
2906 *p = '\0';
2907 if (numpad)
2909 if (padlen > MAXSTR - 1)
2910 padlen = MAXSTR - 1;
2911 p = pad_expand(winmsg_buf, p, numpad, padlen);
2913 if (ev)
2915 evdeq(ev); /* just in case */
2916 ev->timeout.tv_sec = 0;
2917 ev->timeout.tv_usec = 0;
2919 if (ev && tick)
2921 now.tv_usec = 100000;
2922 if (tick == 1)
2923 now.tv_sec++;
2924 else
2925 now.tv_sec += tick - (now.tv_sec % tick);
2926 ev->timeout = now;
2927 debug2("NEW timeout %d %d\n", ev->timeout.tv_sec, tick);
2929 return winmsg_buf;
2932 char *
2933 MakeWinMsg(s, win, esc)
2934 char *s;
2935 struct win *win;
2936 int esc;
2938 return MakeWinMsgEv(s, win, esc, 0, (struct event *)0, 0);
2941 void
2942 PutWinMsg(s, start, max)
2943 char *s;
2944 int start, max;
2946 int i, p, l, r, n;
2947 struct mchar rend;
2948 struct mchar rendstack[MAX_WINMSG_REND];
2949 int rendstackn = 0;
2951 if (s != winmsg_buf)
2953 /* sorry, no fancy coloring available */
2954 debug1("PutWinMsg %s plain\n", s);
2955 l = strlen(s);
2956 if (l > max)
2957 l = max;
2958 l -= start;
2959 s += start;
2960 while (l-- > 0)
2961 PUTCHARLP(*s++);
2962 return;
2964 rend = D_rend;
2965 p = 0;
2966 l = strlen(s);
2967 debug2("PutWinMsg %s start attr %x\n", s, rend.attr);
2968 for (i = 0; i < winmsg_numrend && max > 0; i++)
2970 if (p > winmsg_rendpos[i] || winmsg_rendpos[i] > l)
2971 break;
2972 if (p < winmsg_rendpos[i])
2974 n = winmsg_rendpos[i] - p;
2975 if (n > max)
2976 n = max;
2977 max -= n;
2978 p += n;
2979 while(n-- > 0)
2981 if (start-- > 0)
2982 s++;
2983 else
2984 PUTCHARLP(*s++);
2987 r = winmsg_rend[i];
2988 if (r == -1)
2990 if (rendstackn > 0)
2991 rend = rendstack[--rendstackn];
2993 else
2995 rendstack[rendstackn++] = rend;
2996 ApplyAttrColor(r, &rend);
2998 SetRendition(&rend);
3000 if (p < l)
3002 n = l - p;
3003 if (n > max)
3004 n = max;
3005 while(n-- > 0)
3007 if (start-- > 0)
3008 s++;
3009 else
3010 PUTCHARLP(*s++);
3016 #ifdef DEBUG
3017 static void
3018 fds1(i, j)
3019 int i, j;
3021 while (i < j)
3023 debug1("%d ", i);
3024 i++;
3026 if ((j = open("/dev/null", 0)) >= 0)
3028 fds1(i + 1, j);
3029 close(j);
3031 else
3033 while (dup(++i) < 0 && errno != EBADF)
3034 debug1("%d ", i);
3035 debug1(" [%d]\n", i);
3039 static void
3040 fds()
3042 debug("fds: ");
3043 fds1(-1, -1);
3045 #endif
3047 static void
3048 serv_read_fn(ev, data)
3049 struct event *ev;
3050 char *data;
3052 debug("Knock - knock!\n");
3053 ReceiveMsg();
3056 static void
3057 serv_select_fn(ev, data)
3058 struct event *ev;
3059 char *data;
3061 struct win *p;
3063 debug("serv_select_fn called\n");
3064 /* XXX: messages?? */
3065 if (GotSigChld)
3067 SigChldHandler();
3069 if (InterruptPlease)
3071 debug("Backend received interrupt\n");
3072 /* This approach is rather questionable in a multi-display
3073 * environment */
3074 if (fore && displays)
3076 #if defined(TERMIO) || defined(POSIX)
3077 char ibuf = displays->d_OldMode.tio.c_cc[VINTR];
3078 #else
3079 char ibuf = displays->d_OldMode.m_tchars.t_intrc;
3080 #endif
3081 #ifdef PSEUDOS
3082 write(W_UWP(fore) ? fore->w_pwin->p_ptyfd : fore->w_ptyfd,
3083 &ibuf, 1);
3084 debug1("Backend wrote interrupt to %d", fore->w_number);
3085 debug1("%s\n", W_UWP(fore) ? " (pseudowin)" : "");
3086 #else
3087 write(fore->w_ptyfd, &ibuf, 1);
3088 debug1("Backend wrote interrupt to %d\n", fore->w_number);
3089 #endif
3091 InterruptPlease = 0;
3094 for (p = windows; p; p = p->w_next)
3096 if (p->w_bell == BELL_FOUND || p->w_bell == BELL_VISUAL)
3098 struct canvas *cv;
3099 int visual = p->w_bell == BELL_VISUAL || visual_bell;
3100 p->w_bell = BELL_ON;
3101 for (display = displays; display; display = display->d_next)
3103 for (cv = D_cvlist; cv; cv = cv->c_next)
3104 if (cv->c_layer->l_bottom == &p->w_layer)
3105 break;
3106 if (cv == 0)
3108 p->w_bell = BELL_DONE;
3109 Msg(0, "%s", MakeWinMsg(BellString, p, '%'));
3111 else if (visual && !D_VB && (!D_status || !D_status_bell))
3113 Msg(0, "%s", VisualBellString);
3114 if (D_status)
3116 D_status_bell = 1;
3117 debug1("using vbell timeout %d\n", VBellWait);
3118 SetTimeout(&D_statusev, VBellWait );
3122 /* don't annoy the user with two messages */
3123 if (p->w_monitor == MON_FOUND)
3124 p->w_monitor = MON_DONE;
3125 WindowChanged(p, 'f');
3127 if (p->w_monitor == MON_FOUND)
3129 struct canvas *cv;
3130 p->w_monitor = MON_ON;
3131 for (display = displays; display; display = display->d_next)
3133 for (cv = D_cvlist; cv; cv = cv->c_next)
3134 if (cv->c_layer->l_bottom == &p->w_layer)
3135 break;
3136 if (cv)
3137 continue; /* user already sees window */
3138 #ifdef MULTIUSER
3139 if (!(ACLBYTE(p->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id)))
3140 continue; /* user doesn't care */
3141 #endif
3142 Msg(0, "%s", MakeWinMsg(ActivityString, p, '%'));
3143 p->w_monitor = MON_DONE;
3145 WindowChanged(p, 'f');
3149 for (display = displays; display; display = display->d_next)
3151 struct canvas *cv;
3152 if (D_status == STATUS_ON_WIN)
3153 continue;
3154 /* XXX: should use display functions! */
3155 for (cv = D_cvlist; cv; cv = cv->c_next)
3157 int lx, ly;
3159 /* normalize window, see resize.c */
3160 lx = cv->c_layer->l_x;
3161 ly = cv->c_layer->l_y;
3162 if (lx == cv->c_layer->l_width)
3163 lx--;
3164 if (ly + cv->c_yoff < cv->c_ys)
3166 int i, n = cv->c_ys - (ly + cv->c_yoff);
3167 cv->c_yoff = cv->c_ys - ly;
3168 RethinkViewportOffsets(cv);
3169 if (n > cv->c_layer->l_height)
3170 n = cv->c_layer->l_height;
3171 CV_CALL(cv,
3172 LScrollV(flayer, -n, 0, flayer->l_height - 1, 0);
3173 LayRedisplayLine(-1, -1, -1, 1);
3174 for (i = 0; i < n; i++)
3175 LayRedisplayLine(i, 0, flayer->l_width - 1, 1);
3176 if (cv == cv->c_display->d_forecv)
3177 LaySetCursor();
3180 else if (ly + cv->c_yoff > cv->c_ye)
3182 int i, n = ly + cv->c_yoff - cv->c_ye;
3183 cv->c_yoff = cv->c_ye - ly;
3184 RethinkViewportOffsets(cv);
3185 if (n > cv->c_layer->l_height)
3186 n = cv->c_layer->l_height;
3187 CV_CALL(cv,
3188 LScrollV(flayer, n, 0, cv->c_layer->l_height - 1, 0);
3189 LayRedisplayLine(-1, -1, -1, 1);
3190 for (i = 0; i < n; i++)
3191 LayRedisplayLine(i + flayer->l_height - n, 0, flayer->l_width - 1, 1);
3192 if (cv == cv->c_display->d_forecv)
3193 LaySetCursor();
3196 if (lx + cv->c_xoff < cv->c_xs)
3198 int i, n = cv->c_xs - (lx + cv->c_xoff);
3199 if (n < (cv->c_xe - cv->c_xs + 1) / 2)
3200 n = (cv->c_xe - cv->c_xs + 1) / 2;
3201 if (cv->c_xoff + n > cv->c_xs)
3202 n = cv->c_xs - cv->c_xoff;
3203 cv->c_xoff += n;
3204 RethinkViewportOffsets(cv);
3205 if (n > cv->c_layer->l_width)
3206 n = cv->c_layer->l_width;
3207 CV_CALL(cv,
3208 LayRedisplayLine(-1, -1, -1, 1);
3209 for (i = 0; i < flayer->l_height; i++)
3211 LScrollH(flayer, -n, i, 0, flayer->l_width - 1, 0, 0);
3212 LayRedisplayLine(i, 0, n - 1, 1);
3214 if (cv == cv->c_display->d_forecv)
3215 LaySetCursor();
3218 else if (lx + cv->c_xoff > cv->c_xe)
3220 int i, n = lx + cv->c_xoff - cv->c_xe;
3221 if (n < (cv->c_xe - cv->c_xs + 1) / 2)
3222 n = (cv->c_xe - cv->c_xs + 1) / 2;
3223 if (cv->c_xoff - n + cv->c_layer->l_width - 1 < cv->c_xe)
3224 n = cv->c_xoff + cv->c_layer->l_width - 1 - cv->c_xe;
3225 cv->c_xoff -= n;
3226 RethinkViewportOffsets(cv);
3227 if (n > cv->c_layer->l_width)
3228 n = cv->c_layer->l_width;
3229 CV_CALL(cv,
3230 LayRedisplayLine(-1, -1, -1, 1);
3231 for (i = 0; i < flayer->l_height; i++)
3233 LScrollH(flayer, n, i, 0, flayer->l_width - 1, 0, 0);
3234 LayRedisplayLine(i, flayer->l_width - n, flayer->l_width - 1, 1);
3236 if (cv == cv->c_display->d_forecv)
3237 LaySetCursor();
3243 for (display = displays; display; display = display->d_next)
3245 if (D_status == STATUS_ON_WIN || D_cvlist == 0 || D_cvlist->c_next == 0)
3246 continue;
3247 debug1("serv_select_fn: Restore on cv %#x\n", (int)D_forecv);
3248 CV_CALL(D_forecv, LayRestore();LaySetCursor());
3252 static void
3253 logflush_fn(ev, data)
3254 struct event *ev;
3255 char *data;
3257 struct win *p;
3258 char *buf;
3259 int n;
3261 if (!islogfile(NULL))
3262 return; /* no more logfiles */
3263 logfflush(NULL);
3264 n = log_flush ? log_flush : (logtstamp_after + 4) / 5;
3265 if (n)
3267 SetTimeout(ev, n * 1000);
3268 evenq(ev); /* re-enqueue ourself */
3270 if (!logtstamp_on)
3271 return;
3272 /* write fancy time-stamp */
3273 for (p = windows; p; p = p->w_next)
3275 if (!p->w_log)
3276 continue;
3277 p->w_logsilence += n;
3278 if (p->w_logsilence < logtstamp_after)
3279 continue;
3280 if (p->w_logsilence - n >= logtstamp_after)
3281 continue;
3282 buf = MakeWinMsg(logtstamp_string, p, '%');
3283 logfwrite(p->w_log, buf, strlen(buf));
3288 * Interprets ^?, ^@ and other ^-control-char notation.
3289 * Interprets \ddd octal notation
3291 * The result is placed in *cp, p is advanced behind the parsed expression and
3292 * returned.
3294 static char *
3295 ParseChar(p, cp)
3296 char *p, *cp;
3298 if (*p == 0)
3299 return 0;
3300 if (*p == '^' && p[1])
3302 if (*++p == '?')
3303 *cp = '\177';
3304 else if (*p >= '@')
3305 *cp = Ctrl(*p);
3306 else
3307 return 0;
3308 ++p;
3310 else if (*p == '\\' && *++p <= '7' && *p >= '0')
3312 *cp = 0;
3314 *cp = *cp * 8 + *p - '0';
3315 while (*++p <= '7' && *p >= '0');
3317 else
3318 *cp = *p++;
3319 return p;
3322 static int
3323 ParseEscape(p)
3324 char *p;
3326 unsigned char buf[2];
3328 if (*p == 0)
3329 SetEscape((struct acluser *)0, -1, -1);
3330 else
3332 if ((p = ParseChar(p, (char *)buf)) == NULL ||
3333 (p = ParseChar(p, (char *)buf+1)) == NULL || *p)
3334 return -1;
3335 SetEscape((struct acluser *)0, buf[0], buf[1]);
3337 return 0;