~ubuntu-branches/debian/stretch/screen/stretch

« back to all changes in this revision

Viewing changes to .pc/47screen-cc.patch/screen.c

  • Committer: Package Import Robot
  • Author(s): Axel Beckert
  • Date: 2014-07-26 14:05:20 UTC
  • mfrom: (7.1.4 experimental)
  • Revision ID: package-import@ubuntu.com-20140726140520-68d50x42gevcjy5e
Tags: 4.2.1-2
* Upload to unstable again
* Enable parallel building

Show diffs side-by-side

added added

removed removed

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