1
/* Copyright (c) 1993-2002
2
* Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de)
3
* Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de)
4
* Copyright (c) 1987 Oliver Laumann
7
* Authors: Hadi Bargi Rangin bargi@dots.physics.orst.edu
8
* Bill Barry barryb@dots.physics.orst.edu
9
* Randy Lundquist randyl@dots.physics.orst.edu
11
* Modifications Copyright (c) 1995 by
12
* Science Access Project, Oregon State University.
15
* This program is free software; you can redistribute it and/or modify
16
* it under the terms of the GNU General Public License as published by
17
* the Free Software Foundation; either version 2, or (at your option)
20
* This program is distributed in the hope that it will be useful,
21
* but WITHOUT ANY WARRANTY; without even the implied warranty of
22
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23
* GNU General Public License for more details.
25
* You should have received a copy of the GNU General Public License
26
* along with this program (see the file COPYING); if not, write to the
27
* Free Software Foundation, Inc.,
28
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
30
****************************************************************
33
#include <sys/types.h>
39
# include <sys/sysmacros.h>
44
# include <sys/ioctl.h>
54
# include <sys/stropts.h>
57
#if defined(SYSV) && !defined(ISC)
58
# include <sys/utsname.h>
61
#if defined(sequent) || defined(SVR4)
62
# include <sys/resource.h>
63
#endif /* sequent || SVR4 */
67
# include <sys/sioctl.h>
71
#if (defined(AUX) || defined(_AUX_SOURCE)) && defined(POSIX)
74
#if defined(USE_LOCALE) || defined(ENCODINGS)
77
#if defined(HAVE_NL_LANGINFO) && defined(ENCODINGS)
78
# include <langinfo.h>
86
#include "patchlevel.h"
89
* At the moment we only need the real password if the
90
* builtin lock is used. Therefore disable SHADOWPW if
91
* we do not really need it (kind of security thing).
100
#endif /* SHADOWPW */
102
#include "logfile.h" /* islogfile, logfflush */
109
extern char Term[], screenterm[], **environ, Termcap[];
111
int VBellWait, MsgWait, MsgMinWait, SilenceWait;
113
extern struct acluser *users;
114
extern struct display *displays, *display;
117
extern int visual_bell;
119
extern unsigned char mark_key_tab[];
121
extern char version[];
122
extern char DefaultShell[];
124
extern char *zmodem_sendcmd;
125
extern char *zmodem_recvcmd;
132
extern struct NewWindow nwin_undef, nwin_default, nwin_options;
135
static struct passwd *getpwbyname __P((char *, struct passwd *));
136
static void SigChldHandler __P((void));
137
static sigret_t SigChld __P(SIGPROTOARG);
138
static sigret_t SigInt __P(SIGPROTOARG);
139
static sigret_t CoreDump __P(SIGPROTOARG);
140
static sigret_t FinitHandler __P(SIGPROTOARG);
141
static void DoWait __P((void));
142
static void serv_read_fn __P((struct event *, char *));
143
static void serv_select_fn __P((struct event *, char *));
144
static void logflush_fn __P((struct event *, char *));
145
static void backtick_filter __P((struct backtick *));
146
static void backtick_fn __P((struct event *, char *));
147
static char *runbacktick __P((struct backtick *, int *, time_t));
148
static int IsSymbol __P((char *, char *));
149
static char *ParseChar __P((char *, char *));
150
static int ParseEscape __P((char *));
151
static char *pad_expand __P((char *, char *, int, int));
153
static void fds __P((void));
156
int nversion; /* numerical version, used for secondary DA */
163
struct mode attach_Mode;
165
char SockPath[MAXPATHLEN + 2 * MAXSTR];
166
char *SockName; /* SockName is pointer in SockPath */
167
char *SockMatch = NULL; /* session id command line argument */
168
int ServerSocket = -1;
169
struct event serv_read;
170
struct event serv_select;
171
struct event logflushev;
173
char **NewEnv = NULL;
175
char *RcFileName = NULL;
178
char *screenlogfile; /* filename layout */
179
int log_flush = 10; /* flush interval in seconds */
180
int logtstamp_on = 0; /* tstamp disabled */
181
char *logtstamp_string; /* stamp layout */
182
int logtstamp_after = 120; /* first tstamp after 120s */
183
char *hardcopydir = NULL;
185
char *VisualBellString;
186
char *ActivityString;
191
char *PowDetachString;
199
int iflag, rflag, dflag, lsflag, quietflag, wipeflag, xflag;
210
int tty_oldmode = -1;
213
char HostName[MAXSTR];
215
int real_uid, real_gid, eff_uid, eff_gid;
217
int ZombieKey_destroy, ZombieKey_resurrect;
218
char *preselect = NULL; /* only used in Attach() */
221
char *screenencodings;
230
struct layer *flayer;
233
struct win *console_window;
242
char strnomem[] = "Out of memory.";
245
static int InterruptPlease;
246
static int GotSigChld;
249
lf_secreopen(name, wantfd, l)
257
if (((got_fd = secopen(name, O_WRONLY | O_CREAT | O_APPEND, 0666)) < 0) ||
258
lf_move_fd(got_fd, wantfd) < 0)
261
debug1("lf_secreopen: failed for %s\n", name);
264
l->st->st_ino = l->st->st_dev = 0;
265
debug2("lf_secreopen: %d = %s\n", wantfd, name);
269
/********************************************************************/
270
/********************************************************************/
271
/********************************************************************/
274
static struct passwd *
275
getpwbyname(name, ppp)
281
struct spwd *sss = NULL;
282
static char *spw = NULL;
285
if (!ppp && !(ppp = getpwnam(name)))
288
/* Do password sanity check..., allow ##user for SUN_C2 security */
293
if (ppp->pw_passwd[0] == '#' && ppp->pw_passwd[1] == '#' &&
294
strcmp(ppp->pw_passwd + 2, ppp->pw_name) == 0)
298
char c = ppp->pw_passwd[n];
299
if (!(c == '.' || c == '/' || c == '$' ||
300
(c >= '0' && c <= '9') ||
301
(c >= 'a' && c <= 'z') ||
302
(c >= 'A' && c <= 'Z')))
307
/* try to determine real password */
308
if (n < 13 && sss == 0)
310
sss = getspnam(ppp->pw_name);
315
ppp->pw_passwd = spw = SaveStr(sss->sp_pwdp);
316
endspent(); /* this should delete all buffers ... */
319
endspent(); /* this should delete all buffers ... */
325
if (ppp->pw_passwd && strlen(ppp->pw_passwd) == 13 + 11)
326
ppp->pw_passwd[13] = 0; /* beware of linux's long passwords */
341
char socknamebuf[2 * MAXSTR];
343
char *myname = (ac == 0) ? "screen" : av[0];
346
#ifdef _MODE_T /* (jw) */
351
#if defined(SYSV) && !defined(ISC)
352
struct utsname utsnam;
354
struct NewWindow nwin;
355
int detached = 0; /* start up detached */
360
#if (defined(AUX) || defined(_AUX_SOURCE)) && defined(POSIX)
361
setcompat(COMPAT_POSIX|COMPAT_BSDPROT); /* turn on seteuid support */
363
#if defined(sun) && defined(SVR4)
365
/* Solaris' login blocks SIGHUP! This is _very bad_ */
368
sigprocmask(SIG_SETMASK, &sset, 0);
373
* First, close all unused descriptors
374
* (otherwise, we might have problems with the select() call)
380
sprintf(version, "%d.%.2d.%.2d%s (%s) %s", REV, VERS,
381
PATCHLEVEL, STATE, ORIGIN, DATE);
382
nversion = REV * 10000 + VERS * 100 + PATCHLEVEL;
383
debug2("-- screen debug started %s (%s)\n", *av, version);
397
debug("NAMEDPIPE\n");
399
#if defined(SIGWINCH) && defined(TIOCGWINSZ)
400
debug("Window size changing enabled\n");
430
debug1("NAME_MAX = %d\n", NAME_MAX);
433
BellString = SaveStr("Bell in window %n");
434
VisualBellString = SaveStr(" Wuff, Wuff!! ");
435
ActivityString = SaveStr("Activity in window %n");
436
screenlogfile = SaveStr("screenlog.%n");
437
logtstamp_string = SaveStr("-- %n:%t -- time-stamp -- %M/%d/%y %c:%s --\n");
438
hstatusstring = SaveStr("%h");
439
captionstring = SaveStr("%3n %t");
440
timestring = SaveStr("%c:%s %M %d %H%? %l%?");
441
wlisttit = SaveStr("Num Name%=Flags");
442
wliststr = SaveStr("%3n %t%=%f");
444
BufferFile = SaveStr(DEFAULT_BUFFERFILE);
450
default_startup = (ac > 1) ? 0 : 1;
452
VBellWait = VBELLWAIT * 1000;
453
MsgWait = MSGWAIT * 1000;
454
MsgMinWait = MSGMINWAIT * 1000;
455
SilenceWait = SILENCEWAIT;
460
zmodem_sendcmd = SaveStr("!!! sz -vv -b ");
461
zmodem_recvcmd = SaveStr("!!! rz -vv -b -E");
465
CompileKeys((char *)0, 0, mark_key_tab);
469
screenencodings = SaveStr(SCREENENCODINGS);
472
nwin_options = nwin_undef;
473
strcpy(screenterm, "screen");
475
logreopen_register(lf_secreopen);
478
/* if this is a login screen, assume -RR */
487
ShellProg = SaveStr(DefaultShell); /* to prevent nasty circles */
492
if (--ac > 0 && *ap == '-')
494
if (ap[1] == '-' && ap[2] == 0)
500
if (ap[1] == '-' && !strcmp(ap, "--version"))
501
Panic(0, "Screen version %s", version);
502
if (ap[1] == '-' && !strcmp(ap, "--help"))
503
exit_with_usage(myname, NULL, NULL);
504
while (ap && *ap && *++ap)
509
nwin_options.aflag = 1;
514
case 'p': /* preselect */
520
exit_with_usage(myname, "Specify a window to preselect with -p", NULL);
527
bd.bd_start_braille = 1;
536
exit_with_usage(myname, "Specify an alternate rc-filename with -c", NULL);
545
exit_with_usage(myname, "Specify command characters with -e", NULL);
549
Panic(0, "Two characters are required with -e option, not '%s'.", ap);
558
nwin_options.flowflag = FLOW_NOW * 0;
565
nwin_options.flowflag = FLOW_NOW * 1;
568
nwin_options.flowflag = FLOW_AUTOFLAG;
571
exit_with_usage(myname, "Unknown flow option -%s", --ap);
576
exit_with_usage(myname, NULL, NULL);
577
nwin_options.histheight = atoi(*++av);
578
if (nwin_options.histheight < 0)
579
exit_with_usage(myname, "-h: %s: negative scrollback size?", *av);
584
case 't': /* title, the former AkA == -k */
586
exit_with_usage(myname, "Specify a new window-name with -t", NULL);
587
nwin_options.aka = *++av;
595
nwin_options.lflag = 0;
602
nwin_options.lflag = 1;
605
nwin_options.lflag = 3;
608
case 'i': /* -list */
610
if (ac > 1 && !SockMatch)
618
exit_with_usage(myname, "%s: Unknown suboption to -l", --ap);
624
if (ac > 1 && !SockMatch)
631
nwin_options.Lflag = 1;
636
case 'O': /* to be (or not to be?) deleted. jw. */
641
exit_with_usage(myname, "Specify terminal-type with -T", NULL);
642
if (strlen(*++av) < 20)
643
strcpy(screenterm, *av);
645
Panic(0, "-T: terminal name too long. (max. 20 char)");
646
nwin_options.term = screenterm;
656
if (ac > 1 && *av[1] != '-' && !SockMatch)
660
debug2("rflag=%d, SockMatch=%s\n", dflag, SockMatch);
668
rflag += (*ap == 'R') ? 2 : 1;
679
if (*av[1] != '-' && !SockMatch)
683
debug2("dflag=%d, SockMatch=%s\n", dflag, SockMatch);
690
exit_with_usage(myname, "Specify shell with -s", NULL);
693
ShellProg = SaveStr(*++av);
694
debug1("ShellProg: '%s'\n", ShellProg);
700
exit_with_usage(myname, "Specify session-name with -S", NULL);
704
exit_with_usage(myname, "Empty session-name?", NULL);
710
Panic(0, "Screen version %s", version);
714
nwin_options.encoding = nwin_options.encoding == -1 ? UTF8 : 0;
718
exit_with_usage(myname, "Unknown option %s", --ap);
730
if (eff_uid != real_uid)
732
/* if running with s-bit, we must install a special signal
733
* handler routine that resets the s-bit, so that we get a
736
#ifdef SIGBUS /* OOPS, linux has no bus errors! */
737
signal(SIGBUS, CoreDump);
739
signal(SIGSEGV, CoreDump);
743
setlocale(LC_ALL, "");
746
if (nwin_options.encoding == -1)
748
/* ask locale if we should start in UTF-8 mode */
749
# ifdef HAVE_NL_LANGINFO
751
setlocale(LC_CTYPE, "");
753
nwin_options.encoding = FindEncoding(nl_langinfo(CODESET));
754
debug1("locale says encoding = %d\n", nwin_options.encoding);
758
if (((s = getenv("LC_ALL")) || (s = getenv("LC_CTYPE")) ||
759
(s = getenv("LANG"))) && InStr(s, "UTF-8"))
760
nwin_options.encoding = UTF8;
762
debug1("environment says encoding=%d\n", nwin_options.encoding);
766
if (SockMatch && strlen(SockMatch) >= MAXSTR)
767
Panic(0, "Ridiculously long socketname - try again.");
768
if (cmdflag && !rflag && !dflag && !xflag)
770
if (!cmdflag && dflag && mflag && !(rflag || xflag))
774
nwin.encoding = nwin_undef.encoding; /* let screenrc overwrite it */
779
/* make the write() calls return -1 on all errors */
782
* Ronald F. Guilmette, Oct 29 '94, bug-gnu-utils@prep.ai.mit.edu:
783
* It appears that in System V Release 4, UNIX, if you are writing
784
* an output file and you exceed the currently set file size limit,
785
* you _don't_ just get the call to `write' returning with a
786
* failure code. Rather, you get a signal called `SIGXFSZ' which,
787
* if neither handled nor ignored, will cause your program to crash
790
signal(SIGXFSZ, SIG_IGN);
794
signal(SIGPIPE, SIG_IGN);
801
sh = getenv("SHELL");
802
ShellProg = SaveStr(sh ? sh : DefaultShell);
804
ShellArgs[0] = ShellProg;
805
home = getenv("HOME");
808
if (!(nethackflag = (getenv("NETHACKOPTIONS") != NULL)))
810
char nethackrc[MAXPATHLEN];
812
if (home && (strlen(home) < (MAXPATHLEN - 20)))
814
sprintf(nethackrc,"%s/.nethackrc", home);
815
nethackflag = !access(nethackrc, F_OK);
821
own_uid = multi_uid = real_uid;
822
if (SockMatch && (sockp = index(SockMatch, '/')))
825
Panic(0, "Must run suid root for multiuser support.");
828
SockMatch = sockp + 1;
832
if ((mppp = getpwnam(multi)) == (struct passwd *)0)
833
Panic(0, "Cannot identify account '%s'.", multi);
834
multi_uid = mppp->pw_uid;
835
multi_home = SaveStr(mppp->pw_dir);
836
if (strlen(multi_home) > MAXPATHLEN - 10)
837
Panic(0, "home directory path too long");
839
/* always fake multi attach mode */
847
if (SockMatch && *SockMatch == 0)
849
#endif /* MULTIUSER */
851
if ((LoginName = getlogin()) && LoginName[0] != '\0')
853
if ((ppp = getpwnam(LoginName)) != (struct passwd *) 0)
854
if ((int)ppp->pw_uid != real_uid)
855
ppp = (struct passwd *) 0;
859
if ((ppp = getpwuid(real_uid)) == 0)
861
Panic(0, "getpwuid() can't identify your account!");
864
LoginName = ppp->pw_name;
866
LoginName = SaveStr(LoginName);
868
ppp = getpwbyname(LoginName, ppp);
870
#if !defined(SOCKDIR) && defined(MULTIUSER)
871
if (multi && !multiattach)
873
if (home && strcmp(home, ppp->pw_dir))
874
Panic(0, "$HOME must match passwd entry for multiuser screens.");
878
if (home == 0 || *home == '\0')
880
if (strlen(LoginName) > 20)
881
Panic(0, "LoginName too long - sorry.");
883
if (multi && strlen(multi) > 20)
884
Panic(0, "Screen owner name too long - sorry.");
886
if (strlen(home) > MAXPATHLEN - 25)
887
Panic(0, "$HOME too long - sorry.");
890
if (!detached && !lsflag && !cmdflag && !(dflag && !mflag && !rflag && !xflag))
892
/* ttyname implies isatty */
893
if (!(attach_tty = ttyname(0)))
894
Panic(0, "Must be connected to a terminal.");
895
if (strlen(attach_tty) >= MAXPATHLEN)
896
Panic(0, "TtyName too long - sorry.");
897
if (stat(attach_tty, &st))
898
Panic(errno, "Cannot access '%s'", attach_tty);
900
tty_mode = (int)st.st_mode & 0777;
902
if ((n = secopen(attach_tty, O_RDWR | O_NONBLOCK, 0)) < 0)
903
Panic(0, "Cannot open your terminal '%s' - please check.", attach_tty);
905
debug1("attach_tty is %s\n", attach_tty);
906
if ((attach_term = getenv("TERM")) == 0 || *attach_term == 0)
907
Panic(0, "Please set a terminal type.");
908
if (strlen(attach_term) > sizeof(D_termname) - 1)
909
Panic(0, "$TERM too long - sorry.");
910
GetTTY(0, &attach_Mode);
911
#ifdef DEBUGGGGGGGGGGGGGGG
912
DebugTTY(&attach_Mode);
917
oumask = umask(0); /* well, unsigned never fails? jw. */
919
if ((oumask = (int)umask(0)) == -1)
920
Panic(errno, "Cannot change umask to zero");
922
SockDir = getenv("SCREENDIR");
925
if (strlen(SockDir) >= MAXPATHLEN - 1)
926
Panic(0, "Ridiculously long $SCREENDIR - try again.");
929
Panic(0, "No $SCREENDIR with multi screens, please.");
936
sprintf(SockPath, "%s/.screen", multi_home);
940
sprintf(SockPath, "%s/S-%s", SockDir, multi);
949
sprintf(SockPath, "%s/.screen", home);
955
if (access(SockDir, F_OK))
957
debug1("SockDir '%s' missing ...\n", SockDir);
958
if (UserContext() > 0)
960
if (mkdir(SockDir, 0700))
964
if (UserStatus() <= 0)
965
Panic(0, "Cannot make directory '%s'.", SockDir);
967
if (SockDir != SockPath)
968
strcpy(SockPath, SockDir);
974
if (lstat(SockDir, &st))
976
n = (eff_uid == 0 && (real_uid || eff_gid == real_gid)) ? 0755 :
977
(eff_gid != real_gid) ? 0775 :
983
if (mkdir(SockDir, n) == -1)
984
Panic(errno, "Cannot make directory '%s'", SockDir);
988
if (!S_ISDIR(st.st_mode))
989
Panic(0, "'%s' must be a directory.", SockDir);
990
if (eff_uid == 0 && real_uid && (int)st.st_uid != eff_uid)
991
Panic(0, "Directory '%s' must be owned by root.", SockDir);
992
n = (eff_uid == 0 && (real_uid || (st.st_mode & 0775) != 0775)) ? 0755 :
993
(eff_gid == (int)st.st_gid && eff_gid != real_gid) ? 0775 :
995
if (((int)st.st_mode & 0777) != n)
996
Panic(0, "Directory '%s' must have mode %03o.", SockDir, n);
998
sprintf(SockPath, "%s/S-%s", SockDir, LoginName);
999
if (access(SockPath, F_OK))
1001
if (mkdir(SockPath, 0700) == -1)
1002
Panic(errno, "Cannot make directory '%s'", SockPath);
1003
(void) chown(SockPath, real_uid, real_gid);
1009
if (stat(SockPath, &st) == -1)
1010
Panic(errno, "Cannot access %s", SockPath);
1012
if (!S_ISDIR(st.st_mode))
1013
Panic(0, "%s is not a directory.", SockPath);
1017
if ((int)st.st_uid != multi_uid)
1018
Panic(0, "%s is not the owner of %s.", multi, SockPath);
1023
if ((int)st.st_uid != real_uid)
1024
Panic(0, "You are not the owner of %s.", SockPath);
1026
if ((st.st_mode & 0777) != 0700)
1027
Panic(0, "Directory %s must have mode 700.", SockPath);
1028
if (SockMatch && index(SockMatch, '/'))
1029
Panic(0, "Bad session name '%s'", SockMatch);
1030
SockName = SockPath + strlen(SockPath) + 1;
1032
(void) umask(oumask);
1033
debug2("SockPath: %s SockMatch: %s\n", SockPath, SockMatch ? SockMatch : "NULL");
1035
#if defined(SYSV) && !defined(ISC)
1036
if (uname(&utsnam) == -1)
1037
Panic(errno, "uname");
1038
strncpy(HostName, utsnam.nodename, sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1);
1039
HostName[sizeof(utsnam.nodename) < MAXSTR ? sizeof(utsnam.nodename) : MAXSTR - 1] = '\0';
1041
(void) gethostname(HostName, MAXSTR);
1042
HostName[MAXSTR - 1] = '\0';
1044
if ((ap = index(HostName, '.')) != NULL)
1053
real_uid = multi_uid;
1059
i = FindSocket((int *)NULL, &fo, &oth, SockMatch);
1061
exit(8 + (fo ? ((oth || i) ? 2 : 1) : 0) + i);
1063
Panic(0, "No Sockets found in %s.\n", SockPath);
1064
Panic(0, "%d Socket%s in %s.\n", fo, fo > 1 ? "s" : "", SockPath);
1067
signal(SIG_BYE, AttacherFinit); /* prevent races */
1072
/* attach_tty is not mandatory */
1073
if ((attach_tty = ttyname(0)) == 0)
1075
if (strlen(attach_tty) >= MAXPATHLEN)
1076
Panic(0, "TtyName too long - sorry.");
1078
Panic(0, "Please specify a command.");
1083
if (!mflag && !SockMatch)
1085
sty = getenv("STY");
1086
if (sty && *sty == 0)
1089
SendCmdMessage(sty, SockMatch, av);
1092
else if (rflag || xflag)
1094
debug("screen -r: - is there anybody out there?\n");
1095
if (Attach(MSG_ATTACH))
1102
Panic(0, "Can't create sessions of other users.");
1104
debug("screen -r: backend not responding -- still crying\n");
1106
else if (dflag && !mflag)
1108
(void) Attach(MSG_DETACH);
1109
Msg(0, "[%s %sdetached.]\n", SockName, (dflag > 1 ? "power " : ""));
1113
if (!SockMatch && !mflag)
1117
if ((sty = getenv("STY")) != 0 && *sty != '\0')
1123
nwin_options.args = av;
1124
SendCreateMsg(sty, &nwin);
1129
nwin_compose(&nwin_default, &nwin_options, &nwin_default);
1131
if (!detached || dflag != 2)
1139
Panic(errno, "fork");
1147
sprintf(socknamebuf, "%d.%s", MasterPid, SockMatch);
1149
sprintf(socknamebuf, "%d.%s.%s", MasterPid, stripdev(attach_tty), HostName);
1150
for (ap = socknamebuf; *ap; ap++)
1154
if (strlen(socknamebuf) > NAME_MAX)
1155
socknamebuf[NAME_MAX] = 0;
1157
sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf);
1166
if (DefaultEsc == -1)
1167
DefaultEsc = Ctrl('a');
1168
if (DefaultMetaEsc == -1)
1169
DefaultMetaEsc = 'a';
1171
ap = av0 + strlen(av0) - 1;
1174
if (!strncmp("screen", ap, 6))
1176
strncpy(ap, "SCREEN", 6); /* name this process "SCREEN-BACKEND" */
1188
if (dfp && dfp != stderr)
1190
sprintf(buf, "%s/SCREEN.%d", DEBUGDIR, (int)getpid());
1191
if ((dfp = fopen(buf, "w")) == NULL)
1194
(void) chmod(buf, 0666);
1199
/* reopen tty. must do this, because fd 0 may be RDONLY */
1200
if ((n = secopen(attach_tty, O_RDWR, 0)) < 0)
1201
Panic(0, "Cannot reopen '%s' - please check.", attach_tty);
1205
freopen("/dev/null", "r", stdin);
1206
freopen("/dev/null", "w", stdout);
1211
freopen("/dev/null", "w", stderr);
1212
debug("-- screen.back debug started\n");
1215
* This guarantees that the session owner is listed, even when we
1216
* start detached. From now on we should not refer to 'LoginName'
1217
* any more, use users->u_name instead.
1219
if (UserAdd(LoginName, (char *)0, (struct acluser **)0) < 0)
1220
Panic(0, "Could not create user info");
1223
if (MakeDisplay(LoginName, attach_tty, attach_term, n, getppid(), &attach_Mode) == 0)
1224
Panic(0, "Could not alloc display");
1226
D_encoding = nwin_options.encoding > 0 ? nwin_options.encoding : 0;
1227
debug1("D_encoding = %d\n", D_encoding);
1233
/* user started us with -S option */
1234
sprintf(socknamebuf, "%d.%s", (int)getpid(), SockMatch);
1238
sprintf(socknamebuf, "%d.%s.%s", (int)getpid(), stripdev(attach_tty),
1241
for (ap = socknamebuf; *ap; ap++)
1245
if (strlen(socknamebuf) > NAME_MAX)
1247
debug2("Socketname %s truncated to %d chars\n", socknamebuf, NAME_MAX);
1248
socknamebuf[NAME_MAX] = 0;
1251
sprintf(SockPath + strlen(SockPath), "/%s", socknamebuf);
1253
ServerSocket = MakeServerSocket();
1256
# ifdef ALLOW_SYSSCREENRC
1257
if ((ap = getenv("SYSSCREENRC")))
1261
StartRc(ETCSCREENRC);
1263
StartRc(RcFileName);
1267
# endif /* UTNOKEEP */
1268
# endif /* UTMPOK */
1271
if (InitTermcap(0, 0))
1273
debug("Could not init termcap - exiting\n");
1274
fcntl(D_userfd, F_SETFL, 0); /* Flush sets FNBLOCK */
1277
Kill(D_userpid, SIG_BYE);
1280
MakeDefaultCanvas();
1292
signal(SIGHUP, SigHup);
1293
signal(SIGINT, FinitHandler);
1294
signal(SIGQUIT, FinitHandler);
1295
signal(SIGTERM, FinitHandler);
1297
signal(SIGTTIN, SIG_IGN);
1298
signal(SIGTTOU, SIG_IGN);
1304
SetMode(&D_OldMode, &D_NewMode, D_flow, iflag);
1305
/* Note: SetMode must be called _before_ FinishRc. */
1306
SetTTY(D_userfd, &D_NewMode);
1307
if (fcntl(D_userfd, F_SETFL, FNBLOCK))
1308
Msg(errno, "Warning: NBLOCK fcntl failed");
1311
brktty(-1); /* just try */
1312
signal(SIGCHLD, SigChld);
1314
# ifdef ALLOW_SYSSCREENRC
1315
if ((ap = getenv("SYSSCREENRC")))
1319
FinishRc(ETCSCREENRC);
1321
FinishRc(RcFileName);
1323
debug2("UID %d EUID %d\n", (int)getuid(), (int)geteuid());
1324
if (windows == NULL)
1326
debug("We open one default window, as screenrc did not specify one.\n");
1327
if (MakeWindow(&nwin) == -1)
1329
Msg(0, "Sorry, could not find a PTY.");
1340
if (display && default_startup)
1341
display_copyright();
1342
signal(SIGINT, SigInt);
1343
if (rflag && (rflag & 1) == 0)
1345
Msg(0, "New screen...");
1349
serv_read.type = EV_READ;
1350
serv_read.fd = ServerSocket;
1351
serv_read.handler = serv_read_fn;
1354
serv_select.pri = -10;
1355
serv_select.type = EV_ALWAYS;
1356
serv_select.handler = serv_select_fn;
1357
evenq(&serv_select);
1359
logflushev.type = EV_TIMEOUT;
1360
logflushev.handler = logflush_fn;
1371
if (ZombieKey_destroy)
1379
s[strlen(s) - 1] = '\0';
1380
debug3("window %d (%s) going into zombie state fd %d",
1381
p->w_number, p->w_title, p->w_ptyfd);
1383
if (p->w_slot != (slot_t)0 && p->w_slot != (slot_t)-1)
1386
p->w_slot = 0; /* "detached" */
1393
/* p->w_y = p->w_bot; */
1394
p->w_y = MFindUsedLine(p, p->w_bot, 1);
1395
sprintf(buf, "\n\r=== Window terminated (%s) ===", s ? s : "?");
1396
WriteString(p, buf, strlen(buf));
1397
WindowChanged(p, 'f');
1418
signal(SIGCHLD, SigChld);
1421
if (stat(SockPath, &st) == -1)
1423
debug1("SigChldHandler: Yuck! cannot stat '%s'\n", SockPath);
1424
if (!RecoverSocket())
1426
debug("SCREEN cannot recover from corrupt Socket, bye\n");
1430
debug1("'%s' reconstructed\n", SockPath);
1433
debug2("SigChldHandler: stat '%s' o.k. (%03o)\n", SockPath, (int)st.st_mode);
1439
debug("SigChld()\n");
1447
/* Hangup all displays */
1448
while ((display = displays) != 0)
1454
* the backend's Interrupt handler
1455
* we cannot insert the intrc directly, as we never know
1464
debug("SigInt()\n");
1465
if (fore && displays)
1467
# if defined(TERMIO) || defined(POSIX)
1468
ibuf = displays->d_OldMode.tio.c_cc[VINTR];
1470
ibuf = displays->d_OldMode.m_tchars.t_intrc;
1473
write(fore->w_ptyfd, &ibuf, 1);
1476
signal(SIGINT, SigInt);
1477
debug("SigInt() careful\n");
1478
InterruptPlease = 1;
1486
struct display *disp;
1489
#if defined(SYSVSIGS) && defined(SIGHASARG)
1490
signal(sigsig, SIG_IGN);
1496
sprintf(buf, "\r\n[screen caught signal %d.%s]\r\n", sigsig,
1498
sprintf(buf, "\r\n[screen caught a fatal signal.%s]\r\n",
1500
#if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
1502
#else /* SHADOWPW && !DEBUG */
1504
#endif /* SHADOWPW && !DEBUG */
1506
for (disp = displays; disp; disp = disp->d_next)
1508
fcntl(disp->d_userfd, F_SETFL, 0);
1509
SetTTY(disp->d_userfd, &D_OldMode);
1510
write(disp->d_userfd, buf, strlen(buf));
1511
Kill(disp->d_userpid, SIG_BYE);
1513
#if defined(SHADOWPW) && !defined(DEBUG) && !defined(DUMPSHADOW)
1514
Kill(getpid(), SIGKILL);
1516
#else /* SHADOWPW && !DEBUG */
1518
#endif /* SHADOWPW && !DEBUG */
1526
struct win *p, *next;
1535
while ((pid = waitpid(-1, &wstat, WNOHANG | WUNTRACED)) > 0)
1539
* From: rouilj@sni-usa.com (John Rouillard)
1540
* note that WUNTRACED is not documented to work, but it is defined in
1541
* /usr/include/sys/wait.h, so it may work
1543
while ((pid = wait2(&wstat, WNOHANG | WUNTRACED )) > 0)
1544
# else /* USE_WAIT2 */
1545
while ((pid = wait3(&wstat, WNOHANG | WUNTRACED, (struct rusage *) 0)) > 0)
1546
# endif /* USE_WAIT2 */
1549
while ((pid = wait(&wstat)) < 0)
1553
#endif /* BSDJOBS */
1555
for (p = windows; p; p = next)
1558
if (pid == p->w_pid)
1561
if (WIFSTOPPED(wstat))
1563
debug3("Window %d pid %d: WIFSTOPPED (sig %d)\n", p->w_number, p->w_pid, WSTOPSIG(wstat));
1565
if (WSTOPSIG(wstat) == SIGTTIN)
1567
Msg(0, "Suspended (tty input)");
1572
if (WSTOPSIG(wstat) == SIGTTOU)
1574
Msg(0, "Suspended (tty output)");
1578
/* Try to restart process */
1579
Msg(0, "Child has been stopped, restarting.");
1580
if (killpg(p->w_pid, SIGCONT))
1581
kill(p->w_pid, SIGCONT);
1591
if (p->w_pwin && pid == p->w_pwin->p_pid)
1593
debug2("pseudo of win Nr %d died. pid == %d\n", p->w_number, p->w_pwin->p_pid);
1601
debug1("pid %d not found - hope that's ok\n", pid);
1608
FinitHandler SIGDEFARG
1611
debug1("FinitHandler called, sig %d.\n", sigsig);
1613
debug("FinitHandler called.\n");
1623
struct win *p, *next;
1625
signal(SIGCHLD, SIG_DFL);
1626
signal(SIGHUP, SIG_IGN);
1627
debug1("Finit(%d);\n", i);
1628
for (p = windows; p; p = next)
1633
if (ServerSocket != -1)
1635
debug1("we unlink(%s)\n", SockPath);
1640
(void) unlink(SockPath);
1646
for (display = displays; display; display = display->d_next)
1654
AddStr("[screen is terminating]\r\n");
1656
SetTTY(D_userfd, &D_OldMode);
1657
fcntl(D_userfd, F_SETFL, 0);
1659
Kill(D_userpid, SIG_BYE);
1662
* we _cannot_ call eexit(i) here,
1663
* instead of playing with the Socket above. Sigh.
1673
if (ServerSocket != -1)
1675
debug1("we unlink(%s)\n", SockPath);
1678
(void) unlink(SockPath);
1688
debug1("Hangup %x\n", display);
1694
if (auto_detach || displays->d_next)
1701
* Detach now has the following modes:
1702
*D_DETACH SIG_BYE detach backend and exit attacher
1703
*D_HANGUP SIG_BYE detach backend and exit attacher
1704
*D_STOP SIG_STOP stop attacher (and detach backend)
1705
*D_REMOTE SIG_BYE remote detach -- reattach to new attacher
1706
*D_POWER SIG_POWER_BYE power detach -- attacher kills his parent
1707
*D_REMOTE_POWER SIG_POWER_BYE remote power detach -- both
1708
*D_LOCK SIG_LOCK lock the attacher
1710
* we always remove our utmp slots. (even when "lock" or "stop")
1711
* Note: Take extra care here, we may be called by interrupt!
1724
signal(SIGHUP, SIG_IGN);
1725
debug1("Detach(%d)\n", mode);
1737
AddStr("[detached]\r\n");
1745
#ifdef REMOTE_DETACH
1747
AddStr("[remote detached]\r\n");
1753
AddStr("[power detached]\r\n");
1754
if (PowDetachString)
1756
AddStr(PowDetachString);
1759
sign = SIG_POWER_BYE;
1761
#ifdef REMOTE_DETACH
1762
case D_REMOTE_POWER:
1763
AddStr("[remote power detached]\r\n");
1764
if (PowDetachString)
1766
AddStr(PowDetachString);
1769
sign = SIG_POWER_BYE;
1776
/* tell attacher to lock terminal with a lockprg. */
1780
if (displays->d_next == 0)
1782
for (p = windows; p; p = p->w_next)
1784
if (p->w_slot != (slot_t) -1 && !(p->w_lflag & 2))
1788
* Set the slot to 0 to get the window
1791
p->w_slot = (slot_t) 0;
1795
if (mode != D_HANGUP)
1798
if (displays->d_next == 0 && console_window)
1800
if (TtyGrabConsole(console_window->w_ptyfd, 0, "detach"))
1802
debug("could not release console - killing window\n");
1803
KillWindow(console_window);
1804
display = displays; /* restore display */
1810
ReleaseAutoWritelock(display, D_fore);
1812
D_user->u_detachwin = D_fore->w_number;
1813
D_user->u_detachotherwin = D_other ? D_other->w_number : -1;
1815
for (cv = D_cvlist; cv; cv = cv->c_next)
1817
p = Layer2Window(cv->c_layer);
1818
SetCanvasWindow(cv, 0);
1820
WindowChanged(p, 'u');
1824
debug2("display: %#x displays: %#x\n", (unsigned int)display, (unsigned int)displays);
1827
/* Flag detached-ness */
1830
* tell father what to do. We do that after we
1831
* freed the tty, thus getty feels more comfortable on hpux
1832
* if it was a power detach.
1835
debug2("Detach: Signal %d to Attacher(%d)!\n", sign, pid);
1836
debug("Detach returns, we are successfully detached.\n");
1837
signal(SIGHUP, SigHup);
1847
return strncmp(e, s, l) == 0 && e[l] == '=';
1853
register char **op, **np;
1854
static char stybuf[MAXSTR];
1856
for (op = environ; *op; ++op)
1859
free((char *)NewEnv);
1860
NewEnv = np = (char **) malloc((unsigned) (op - environ + 7 + 1) * sizeof(char **));
1863
sprintf(stybuf, "STY=%s", strlen(SockName) <= MAXSTR - 5 ? SockName : "?");
1864
*np++ = stybuf; /* NewEnv[0] */
1865
*np++ = Term; /* NewEnv[1] */
1866
np++; /* room for SHELL */
1868
np += 2; /* room for TERMCAP and WINDOW */
1870
np += 4; /* room for TERMCAP WINDOW LINES COLUMNS */
1873
for (op = environ; *op; ++op)
1875
if (!IsSymbol(*op, "TERM") && !IsSymbol(*op, "TERMCAP")
1876
&& !IsSymbol(*op, "STY") && !IsSymbol(*op, "WINDOW")
1877
&& !IsSymbol(*op, "SCREENCAP") && !IsSymbol(*op, "SHELL")
1878
&& !IsSymbol(*op, "LINES") && !IsSymbol(*op, "COLUMNS")
1887
#if defined(USEVARARGS) && defined(__STDC__)
1888
Msg(int err, char *fmt, VA_DOTS)
1890
Msg(err, fmt, VA_DOTS)
1897
char buf[MAXPATHLEN*2];
1902
(void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap));
1909
strncpy(p, strerror(err), buf + sizeof(buf) - p - 1);
1910
buf[sizeof(buf) - 1] = 0;
1912
debug2("Msg('%s') (%#x);\n", buf, (unsigned int)display);
1914
if (display && displays)
1918
for (display = displays; display; display = display->d_next)
1923
/* no displays but a display - must have forked.
1924
* send message to backend!
1926
char *tty = D_usertty;
1927
struct display *olddisplay = display;
1928
display = 0; /* only send once */
1929
SendErrorMsg(tty, buf);
1930
display = olddisplay;
1933
printf("%s\r\n", buf);
1937
* Call FinitTerm for all displays, write a message to each and call eexit();
1941
#if defined(USEVARARGS) && defined(__STDC__)
1942
Panic(int err, char *fmt, VA_DOTS)
1944
Panic(err, fmt, VA_DOTS)
1951
char buf[MAXPATHLEN*2];
1956
(void)vsnprintf(p, sizeof(buf) - 100, fmt, VA_ARGS(ap));
1963
strncpy(p, strerror(err), buf + sizeof(buf) - p - 1);
1964
buf[sizeof(buf) - 1] = 0;
1966
debug3("Panic('%s'); display=%x displays=%x\n", buf, display, displays);
1967
if (displays == 0 && display == 0)
1968
printf("%s\r\n", buf);
1969
else if (displays == 0)
1971
/* no displays but a display - must have forked.
1972
* send message to backend!
1974
char *tty = D_usertty;
1976
SendErrorMsg(tty, buf);
1981
for (display = displays; display; display = display->d_next)
1990
SetTTY(D_userfd, &D_OldMode);
1991
fcntl(D_userfd, F_SETFL, 0);
1992
write(D_userfd, buf, strlen(buf));
1993
write(D_userfd, "\n", 1);
1996
Kill(D_userpid, SIG_BYE);
1999
if (tty_oldmode >= 0)
2002
if (setuid(own_uid))
2003
xseteuid(own_uid); /* may be a loop. sigh. */
2007
debug1("Panic: changing back modes from %s\n", attach_tty);
2008
chmod(attach_tty, tty_oldmode);
2016
* '^' is allowed as an escape mechanism for control characters. jw.
2018
* Added time insertion using ideas/code from /\ndy Jones
2019
* (andy@lingua.cltr.uq.OZ.AU) - thanks a lot!
2024
static const char days[] = "SunMonTueWedThuFriSat";
2025
static const char months[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
2028
static char winmsg_buf[MAXSTR];
2029
#define MAX_WINMSG_REND 16 /* rendition changes */
2030
static int winmsg_rend[MAX_WINMSG_REND];
2031
static int winmsg_rendpos[MAX_WINMSG_REND];
2032
static int winmsg_numrend;
2035
pad_expand(buf, p, numpad, padlen)
2044
padlen = padlen - (p - buf); /* space for rent */
2047
pn2 = pn = p + padlen;
2051
if (r && p - buf == winmsg_rendpos[r - 1])
2053
winmsg_rendpos[--r] = pn - buf;
2060
i = numpad > 0 ? (padlen + numpad - 1) / numpad : 0;
2071
struct backtick *next;
2076
char result[MAXSTR];
2083
struct backtick *backticks;
2087
struct backtick *bt;
2092
for (p = q = bt->result; (c = (unsigned char)*p++) != 0;)
2096
if (c >= ' ' || c == '\005')
2103
backtick_fn(ev, data)
2107
struct backtick *bt;
2110
bt = (struct backtick *)data;
2111
debug1("backtick_fn for #%d\n", bt->num);
2113
l = read(ev->fd, bt->buf + i, MAXSTR - i);
2116
debug1("EOF on backtick #%d\n", bt->num);
2122
debug1("read %d bytes\n", l);
2124
for (j = 0; j < l; j++)
2125
if (bt->buf[i - j - 1] == '\n')
2129
for (k = i - j - 2; k >= 0; k--)
2130
if (bt->buf[k] == '\n')
2133
bcopy(bt->buf + k, bt->result, i - j - k);
2134
bt->result[i - j - k - 1] = 0;
2135
backtick_filter(bt);
2136
WindowChanged(0, '`');
2138
if (j == l && i == MAXSTR)
2146
bcopy(bt->buf + i - j, bt->buf, j);
2153
setbacktick(num, lifespan, tick, cmdv)
2159
struct backtick **btp, *bt;
2162
debug1("setbacktick called for backtick #%d\n", num);
2163
for (btp = &backticks; (bt = *btp) != 0; btp = &bt->next)
2170
for (v = bt->cmdv; *v; v++)
2187
bt = (struct backtick *)malloc(sizeof *bt);
2193
bzero(bt, sizeof(*bt));
2199
bt->lifespan = lifespan;
2206
if (bt->tick == 0 && bt->lifespan == 0)
2208
debug("setbacktick: continuous mode\n");
2209
bt->buf = (char *)malloc(MAXSTR);
2213
setbacktick(num, 0, 0, (char **)0);
2216
bt->ev.type = EV_READ;
2217
bt->ev.fd = readpipe(bt->cmdv);
2218
bt->ev.handler = backtick_fn;
2219
bt->ev.data = (char *)bt;
2226
runbacktick(bt, tickp, now)
2227
struct backtick *bt;
2234
debug1("runbacktick called for backtick #%d\n", bt->num);
2235
if (bt->tick && (!*tickp || bt->tick < *tickp))
2237
if ((bt->lifespan == 0 && bt->tick == 0) || now < bt->bestbefore)
2239
debug1("returning old result (%d)\n", bt->lifespan);
2242
f = readpipe(bt->cmdv);
2246
while ((l = read(f, bt->result + i, sizeof(bt->result) - i)) > 0)
2248
debug1("runbacktick: read %d bytes\n", l);
2250
for (j = 1; j < l; j++)
2251
if (bt->result[i - j - 1] == '\n')
2253
if (j == l && i == sizeof(bt->result))
2255
j = sizeof(bt->result) / 2;
2260
bcopy(bt->result + i - j, bt->result, j);
2265
bt->result[sizeof(bt->result) - 1] = '\n';
2266
if (i && bt->result[i - 1] == '\n')
2268
debug1("runbacktick: finished, %d bytes\n", i);
2270
backtick_filter(bt);
2272
bt->bestbefore = now2 + bt->lifespan;
2277
MakeWinMsgEv(str, win, esc, padlen, ev, rec)
2287
register char *p = winmsg_buf;
2297
int qmflag = 0, omflag = 0, qmnumrend = 0;
2304
struct backtick *bt;
2306
if (winmsg_numrend >= 0)
2309
winmsg_numrend = -winmsg_numrend;
2314
gettimeofday(&now, NULL);
2315
for (; *s && (l = winmsg_buf + MAXSTR - 1 - p) > 0; s++, p++)
2321
if (*s != '^' && *s >= 64)
2346
if (*++s == esc) /* double escape ? */
2348
if ((plusflg = *s == '+') != 0)
2350
if ((minusflg = *s == '-') != 0)
2352
if ((zeroflg = *s == '0') != 0)
2355
while(*s >= '0' && *s <= '9')
2356
num = num * 10 + (*s++ - '0');
2357
if ((longflg = *s == 'L') != 0)
2365
if ((!qmflag && !omflag) || omflag == 1)
2368
if (qmnumrend < winmsg_numrend)
2369
winmsg_numrend = qmnumrend;
2375
qmnumrend = winmsg_numrend;
2376
qmflag = omflag = 0;
2382
if (qmflag && omflag != 1)
2386
qmnumrend = winmsg_numrend;
2391
if (qmnumrend < winmsg_numrend)
2392
winmsg_numrend = qmnumrend;
2396
case 'd': case 'D': case 'm': case 'M': case 'y': case 'Y':
2397
case 'a': case 'A': case 's': case 'c': case 'C':
2402
time_t nowsec = now.tv_sec;
2403
tm = localtime(&nowsec);
2406
if (!tick || tick > 3600)
2411
sprintf(p, "%02d", tm->tm_mday % 100);
2415
strftime(p, l, (longflg ? "%A" : "%a"), tm);
2417
sprintf(p, "%3.3s", days + 3 * tm->tm_wday);
2421
sprintf(p, "%02d", tm->tm_mon + 1);
2425
strftime(p, l, (longflg ? "%B" : "%b"), tm);
2427
sprintf(p, "%3.3s", months + 3 * tm->tm_mon);
2431
sprintf(p, "%02d", tm->tm_year % 100);
2434
sprintf(p, "%04d", tm->tm_year + 1900);
2437
sprintf(p, tm->tm_hour >= 12 ? "pm" : "am");
2440
sprintf(p, tm->tm_hour >= 12 ? "PM" : "AM");
2443
sprintf(p, "%02d", tm->tm_sec);
2447
sprintf(p, zeroflg ? "%02d:%02d" : "%2d:%02d", tm->tm_hour, tm->tm_min);
2448
if (!tick || tick > 60)
2452
sprintf(p, zeroflg ? "%02d:%02d" : "%2d:%02d", (tm->tm_hour + 11) % 12 + 1, tm->tm_min);
2453
if (!tick || tick > 60)
2473
if (!tick || tick > 60)
2482
if (rec >= 10 || (*s == 'h' && (win == 0 || win->w_hstatus == 0 || *win->w_hstatus == 0)))
2489
for (bt = backticks; bt; bt = bt->next)
2499
char savebuf[sizeof(winmsg_buf)];
2501
int oldnumrend = winmsg_numrend;
2504
strcpy(savebuf, winmsg_buf);
2505
winmsg_numrend = -winmsg_numrend;
2506
MakeWinMsgEv(*s == 'h' ? win->w_hstatus : runbacktick(bt, &oldtick, now.tv_sec), win, '\005', 0, (struct event *)0, rec + 1);
2507
debug2("oldtick=%d tick=%d\n", oldtick, tick);
2508
if (!tick || oldtick < tick)
2510
if ((int)strlen(winmsg_buf) < l)
2511
strcat(savebuf, winmsg_buf);
2512
strcpy(winmsg_buf, savebuf);
2513
while (oldnumrend < winmsg_numrend)
2514
winmsg_rendpos[oldnumrend++] += p - winmsg_buf;
2523
struct win *oldfore = 0;
2531
ss = AddWindows(p, l - 1, (*s == 'w' ? 0 : 1) | (longflg ? 0 : 2) | (plusflg ? 4 : 0), win ? win->w_number : -1);
2544
AddOtherUsers(p, l - 1, win);
2552
AddWindowFlags(p, l - 1, win);
2559
if (win && (int)strlen(win->w_title) < l)
2561
strcpy(p, win->w_title);
2571
for (i = 0; i < 127; i++)
2572
if (s[i] && s[i] != '}')
2576
if (s[i] == '}' && winmsg_numrend < MAX_WINMSG_REND)
2580
debug1("MakeWinMsg attrcolor %s\n", rbuf);
2581
if (i != 1 || rbuf[0] != '-')
2582
r = ParseAttrColor(rbuf, (char *)0, 0);
2583
if (r != -1 || (i == 1 && rbuf[0] == '-'))
2585
winmsg_rend[winmsg_numrend] = r;
2586
winmsg_rendpos[winmsg_numrend] = p - winmsg_buf;
2596
if ((int)strlen(HostName) < l)
2598
strcpy(p, HostName);
2607
if (display && ((ev && ev == &D_forecv->c_captev) || (!ev && win && win == D_fore)))
2611
truncpos = p - winmsg_buf;
2612
truncper = num > 100 ? 100 : num;
2613
trunclong = longflg;
2619
if (num || zeroflg || plusflg || longflg || (*s != '='))
2621
/* expand all pads */
2624
num = (plusflg ? lastpad : padlen) - num;
2625
if (!plusflg && padlen == 0)
2626
num = p - winmsg_buf;
2631
if (*s != '=' && num == 0 && !plusflg)
2636
num = p - winmsg_buf;
2638
num = (padlen - (plusflg ? lastpad : 0)) * num / 100;
2644
if (num > MAXSTR - 1)
2647
p = pad_expand(winmsg_buf, p, numpad, num);
2649
if (p - winmsg_buf > num && !longflg)
2658
trunc = lastpad + truncper * (num - lastpad) / 100;
2661
if (trunc < lastpad)
2663
left = truncpos - trunc;
2664
if (left > p - winmsg_buf - num)
2665
left = p - winmsg_buf - num;
2666
debug1("lastpad = %d, ", lastpad);
2667
debug3("truncpos = %d, trunc = %d, left = %d\n", truncpos, trunc, left);
2670
if (left + lastpad > p - winmsg_buf)
2671
left = p - winmsg_buf - lastpad;
2672
if (p - winmsg_buf - lastpad - left > 0)
2673
bcopy(winmsg_buf + lastpad + left, winmsg_buf + lastpad, p - winmsg_buf - lastpad - left);
2676
while (r && winmsg_rendpos[r - 1] > lastpad)
2679
winmsg_rendpos[r] -= left;
2680
if (winmsg_rendpos[r] < lastpad)
2681
winmsg_rendpos[r] = lastpad;
2685
if (p - winmsg_buf > lastpad)
2686
winmsg_buf[lastpad] = '.';
2687
if (p - winmsg_buf > lastpad + 1)
2688
winmsg_buf[lastpad + 1] = '.';
2689
if (p - winmsg_buf > lastpad + 2)
2690
winmsg_buf[lastpad + 2] = '.';
2693
if (p - winmsg_buf > num)
2695
p = winmsg_buf + num;
2698
if (num - 1 >= lastpad)
2700
if (num - 2 >= lastpad)
2702
if (num - 3 >= lastpad)
2706
while (r && winmsg_rendpos[r - 1] > num)
2707
winmsg_rendpos[--r] = num;
2711
if (lastpad > p - winmsg_buf)
2712
lastpad = p - winmsg_buf;
2713
debug1("lastpad now %d\n", lastpad);
2717
while (p - winmsg_buf < num)
2719
lastpad = p - winmsg_buf;
2722
debug1("lastpad2 now %d\n", lastpad);
2728
*p = 127; /* internal pad representation */
2742
sprintf(p, "%*s", num, num > 1 ? "--" : "-");
2744
sprintf(p, "%*d", num, win->w_number);
2751
if (qmpos && !qmflag)
2756
if (padlen > MAXSTR - 1)
2757
padlen = MAXSTR - 1;
2758
p = pad_expand(winmsg_buf, p, numpad, padlen);
2762
evdeq(ev); /* just in case */
2763
ev->timeout.tv_sec = 0;
2764
ev->timeout.tv_usec = 0;
2768
now.tv_usec = 100000;
2772
now.tv_sec += tick - (now.tv_sec % tick);
2774
debug2("NEW timeout %d %d\n", ev->timeout.tv_sec, tick);
2780
MakeWinMsg(s, win, esc)
2785
return MakeWinMsgEv(s, win, esc, 0, (struct event *)0, 0);
2789
PutWinMsg(s, start, max)
2795
struct mchar rendstack[MAX_WINMSG_REND];
2798
if (s != winmsg_buf)
2803
debug2("PutWinMsg %s start attr %x\n", s, rend.attr);
2804
for (i = 0; i < winmsg_numrend && max > 0; i++)
2806
if (p > winmsg_rendpos[i] || winmsg_rendpos[i] > l)
2808
if (p < winmsg_rendpos[i])
2810
n = winmsg_rendpos[i] - p;
2827
rend = rendstack[--rendstackn];
2831
rendstack[rendstackn++] = rend;
2832
ApplyAttrColor(r, &rend);
2834
SetRendition(&rend);
2863
if ((j = open("/dev/null", 0)) >= 0)
2870
while (dup(++i) < 0 && errno != EBADF)
2872
debug1(" [%d]\n", i);
2885
serv_read_fn(ev, data)
2889
debug("Knock - knock!\n");
2894
serv_select_fn(ev, data)
2900
debug("serv_select_fn called\n");
2901
/* XXX: messages?? */
2906
if (InterruptPlease)
2908
debug("Backend received interrupt\n");
2909
/* This approach is rather questionable in a multi-display
2911
if (fore && displays)
2913
#if defined(TERMIO) || defined(POSIX)
2914
char ibuf = displays->d_OldMode.tio.c_cc[VINTR];
2916
char ibuf = displays->d_OldMode.m_tchars.t_intrc;
2919
write(W_UWP(fore) ? fore->w_pwin->p_ptyfd : fore->w_ptyfd,
2921
debug1("Backend wrote interrupt to %d", fore->w_number);
2922
debug1("%s\n", W_UWP(fore) ? " (pseudowin)" : "");
2924
write(fore->w_ptyfd, &ibuf, 1);
2925
debug1("Backend wrote interrupt to %d\n", fore->w_number);
2928
InterruptPlease = 0;
2931
for (p = windows; p; p = p->w_next)
2933
if (p->w_bell == BELL_FOUND || p->w_bell == BELL_VISUAL)
2936
int visual = p->w_bell == BELL_VISUAL || visual_bell;
2937
p->w_bell = BELL_ON;
2938
for (display = displays; display; display = display->d_next)
2940
for (cv = D_cvlist; cv; cv = cv->c_next)
2941
if (cv->c_layer->l_bottom == &p->w_layer)
2945
p->w_bell = BELL_DONE;
2946
Msg(0, "%s", MakeWinMsg(BellString, p, '%'));
2948
else if (visual && !D_VB && (!D_status || !D_status_bell))
2950
Msg(0, "%s", VisualBellString);
2954
debug1("using vbell timeout %d\n", VBellWait);
2955
SetTimeout(&D_statusev, VBellWait );
2959
/* don't annoy the user with two messages */
2960
if (p->w_monitor == MON_FOUND)
2961
p->w_monitor = MON_DONE;
2962
WindowChanged(p, 'f');
2964
if (p->w_monitor == MON_FOUND)
2967
p->w_monitor = MON_ON;
2968
for (display = displays; display; display = display->d_next)
2970
for (cv = D_cvlist; cv; cv = cv->c_next)
2971
if (cv->c_layer->l_bottom == &p->w_layer)
2974
continue; /* user already sees window */
2976
if (!(ACLBYTE(p->w_mon_notify, D_user->u_id) & ACLBIT(D_user->u_id)))
2977
continue; /* user doesn't care */
2979
Msg(0, "%s", MakeWinMsg(ActivityString, p, '%'));
2980
p->w_monitor = MON_DONE;
2982
WindowChanged(p, 'f');
2986
for (display = displays; display; display = display->d_next)
2989
if (D_status == STATUS_ON_WIN)
2991
/* XXX: should use display functions! */
2992
for (cv = D_cvlist; cv; cv = cv->c_next)
2996
/* normalize window, see resize.c */
2997
lx = cv->c_layer->l_x;
2998
ly = cv->c_layer->l_y;
2999
if (lx == cv->c_layer->l_width)
3001
if (ly + cv->c_yoff < cv->c_ys)
3003
int i, n = cv->c_ys - (ly + cv->c_yoff);
3004
cv->c_yoff = cv->c_ys - ly;
3005
RethinkViewportOffsets(cv);
3006
if (n > cv->c_layer->l_height)
3007
n = cv->c_layer->l_height;
3009
LScrollV(flayer, -n, 0, flayer->l_height - 1, 0);
3010
LayRedisplayLine(-1, -1, -1, 1);
3011
for (i = 0; i < n; i++)
3012
LayRedisplayLine(i, 0, flayer->l_width - 1, 1);
3013
if (cv == cv->c_display->d_forecv)
3017
else if (ly + cv->c_yoff > cv->c_ye)
3019
int i, n = ly + cv->c_yoff - cv->c_ye;
3020
cv->c_yoff = cv->c_ye - ly;
3021
RethinkViewportOffsets(cv);
3022
if (n > cv->c_layer->l_height)
3023
n = cv->c_layer->l_height;
3025
LScrollV(flayer, n, 0, cv->c_layer->l_height - 1, 0);
3026
LayRedisplayLine(-1, -1, -1, 1);
3027
for (i = 0; i < n; i++)
3028
LayRedisplayLine(i + flayer->l_height - n, 0, flayer->l_width - 1, 1);
3029
if (cv == cv->c_display->d_forecv)
3033
if (lx + cv->c_xoff < cv->c_xs)
3035
int i, n = cv->c_xs - (lx + cv->c_xoff);
3036
if (n < (cv->c_xe - cv->c_xs + 1) / 2)
3037
n = (cv->c_xe - cv->c_xs + 1) / 2;
3038
if (cv->c_xoff + n > cv->c_xs)
3039
n = cv->c_xs - cv->c_xoff;
3041
RethinkViewportOffsets(cv);
3042
if (n > cv->c_layer->l_width)
3043
n = cv->c_layer->l_width;
3045
LayRedisplayLine(-1, -1, -1, 1);
3046
for (i = 0; i < flayer->l_height; i++)
3048
LScrollH(flayer, -n, i, 0, flayer->l_width - 1, 0, 0);
3049
LayRedisplayLine(i, 0, n - 1, 1);
3051
if (cv == cv->c_display->d_forecv)
3055
else if (lx + cv->c_xoff > cv->c_xe)
3057
int i, n = lx + cv->c_xoff - cv->c_xe;
3058
if (n < (cv->c_xe - cv->c_xs + 1) / 2)
3059
n = (cv->c_xe - cv->c_xs + 1) / 2;
3060
if (cv->c_xoff - n + cv->c_layer->l_width - 1 < cv->c_xe)
3061
n = cv->c_xoff + cv->c_layer->l_width - 1 - cv->c_xe;
3063
RethinkViewportOffsets(cv);
3064
if (n > cv->c_layer->l_width)
3065
n = cv->c_layer->l_width;
3067
LayRedisplayLine(-1, -1, -1, 1);
3068
for (i = 0; i < flayer->l_height; i++)
3070
LScrollH(flayer, n, i, 0, flayer->l_width - 1, 0, 0);
3071
LayRedisplayLine(i, flayer->l_width - n, flayer->l_width - 1, 1);
3073
if (cv == cv->c_display->d_forecv)
3080
for (display = displays; display; display = display->d_next)
3082
if (D_status == STATUS_ON_WIN || D_cvlist == 0 || D_cvlist->c_next == 0)
3084
debug1("serv_select_fn: Restore on cv %#x\n", (int)D_forecv);
3085
CV_CALL(D_forecv, LayRestore();LaySetCursor());
3090
logflush_fn(ev, data)
3098
if (!islogfile(NULL))
3099
return; /* no more logfiles */
3101
n = log_flush ? log_flush : (logtstamp_after + 4) / 5;
3104
SetTimeout(ev, n * 1000);
3105
evenq(ev); /* re-enqueue ourself */
3109
/* write fancy time-stamp */
3110
for (p = windows; p; p = p->w_next)
3114
p->w_logsilence += n;
3115
if (p->w_logsilence < logtstamp_after)
3117
if (p->w_logsilence - n >= logtstamp_after)
3119
buf = MakeWinMsg(logtstamp_string, p, '%');
3120
logfwrite(p->w_log, buf, strlen(buf));
3125
* Interprets ^?, ^@ and other ^-control-char notation.
3126
* Interprets \ddd octal notation
3128
* The result is placed in *cp, p is advanced behind the parsed expression and
3137
if (*p == '^' && p[1])
3147
else if (*p == '\\' && *++p <= '7' && *p >= '0')
3151
*cp = *cp * 8 + *p - '0';
3152
while (*++p <= '7' && *p >= '0');
3163
unsigned char buf[2];
3166
SetEscape((struct acluser *)0, -1, -1);
3169
if ((p = ParseChar(p, (char *)buf)) == NULL ||
3170
(p = ParseChar(p, (char *)buf+1)) == NULL || *p)
3172
SetEscape((struct acluser *)0, buf[0], buf[1]);