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