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
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2, or (at your option)
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program (see the file COPYING); if not, write to the
18
* Free Software Foundation, Inc.,
19
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
21
****************************************************************
24
#include <sys/types.h>
29
# include <sys/ioctl.h>
36
#include "logfile.h" /* logfopen() */
38
extern struct display *displays, *display;
39
extern struct win *windows, *fore, *wtab[], *console_window;
40
extern char *ShellArgs[];
41
extern char *ShellProg;
42
extern char screenterm[];
43
extern char *screenlogfile;
44
extern char HostName[];
46
extern int SilenceWait;
47
extern int real_uid, real_gid, eff_uid, eff_gid;
48
extern char Termcap[];
50
extern int visual_bell, maxwin;
51
extern struct event logflushev;
52
extern int log_flush, logtstamp_after;
53
extern int ZombieKey_destroy, ZombieKey_resurrect;
54
extern struct layer *flayer;
55
extern int maxusercount;
56
extern int pty_preopen;
58
extern int zmodem_mode;
59
extern struct mchar mchar_blank;
60
extern char *zmodem_sendcmd;
61
extern char *zmodem_recvcmd;
64
#if defined(TIOCSWINSZ) || defined(TIOCGWINSZ)
65
extern struct winsize glwz;
69
extern int separate_sids;
72
static void WinProcess __P((char **, int *));
73
static void WinRedisplayLine __P((int, int, int, int));
74
static void WinClearLine __P((int, int, int, int));
75
static int WinRewrite __P((int, int, int, struct mchar *, int));
76
static int WinResize __P((int, int));
77
static void WinRestore __P((void));
78
static int DoAutolf __P((char *, int *, int));
79
static void ZombieProcess __P((char **, int *));
80
static void win_readev_fn __P((struct event *, char *));
81
static void win_writeev_fn __P((struct event *, char *));
82
static int muchpending __P((struct win *, struct event *));
84
static void paste_slowev_fn __P((struct event *, char *));
87
static void pseu_readev_fn __P((struct event *, char *));
88
static void pseu_writeev_fn __P((struct event *, char *));
90
static void win_silenceev_fn __P((struct event *, char *));
92
static int OpenDevice __P((char **, int, int *, char **));
93
static int ForkWindow __P((struct win *, char **, char *));
95
static void zmodem_found __P((struct win *, int, char *, int));
96
static void zmodem_fin __P((char *, int, char *));
97
static int zmodem_parse __P((struct win *, char *, int));
102
int VerboseCreate = 0; /* XXX move this to user.h */
104
char DefaultShell[] = "/bin/sh";
105
static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin";
107
/* keep this in sync with the structure definition in window.h */
108
struct NewWindow nwin_undef =
112
(char **)0, /* args */
114
(char *)0, /* term */
129
(char *)0, /* hstatus */
130
(char *)0 /* charset */
133
struct NewWindow nwin_default =
137
ShellArgs, /* args */
139
screenterm, /* term */
141
1*FLOW_NOW, /* flowflag */
142
LOGINDEFAULT, /* lflag */
143
DEFAULTHISTHEIGHT, /* histheight */
144
MON_OFF, /* monitor */
145
WLOCK_OFF, /* wlock */
154
(char *)0, /* hstatus */
155
(char *)0 /* charset */
158
struct NewWindow nwin_options;
160
static int const_IOSIZE = IOSIZE;
161
static int const_one = 1;
164
nwin_compose(def, new, res)
165
struct NewWindow *def, *new, *res;
167
#define COMPOSE(x) res->x = new->x != nwin_undef.x ? new->x : def->x
192
/*****************************************************************
194
* The window layer functions
197
struct LayFuncs WinLf =
209
DoAutolf(buf, lenp, fr)
218
for (p = buf; len > 0; p++, len--)
229
bcopy(p, p + 1, len++);
237
WinProcess(bufpp, lenp)
241
int l2 = 0, f, *ilen, l = *lenp, trunc;
244
debug1("WinProcess: %d bytes\n", *lenp);
245
fore = (struct win *)flayer->l_data;
247
if (fore->w_ptyfd < 0) /* zombie? */
249
ZombieProcess(bufpp, lenp);
253
/* a pending writelock is this:
254
* fore->w_wlock == WLOCK_AUTO, fore->w_wlockuse = NULL
255
* The user who wants to use this window next, will get the lock, if he can.
257
if (display && fore->w_wlock == WLOCK_AUTO &&
258
!fore->w_wlockuser && !AclCheckPermWin(D_user, ACL_WRITE, fore))
260
fore->w_wlockuser = D_user;
261
debug2("window %d: pending writelock grabbed by user %s\n",
262
fore->w_number, fore->w_wlockuser->u_name);
264
/* if w_wlock is set, only one user may write, else we check acls */
265
if (display && ((fore->w_wlock == WLOCK_OFF) ?
266
AclCheckPermWin(D_user, ACL_WRITE, fore) :
267
(D_user != fore->w_wlockuser)))
269
debug2("window %d, user %s: ", fore->w_number, D_user->u_name);
270
debug2("writelock %d (wlockuser %s)\n", fore->w_wlock,
271
fore->w_wlockuser ? fore->w_wlockuser->u_name : "NULL");
272
/* XXX FIXME only display !*/
273
WBell(fore, visual_bell);
278
#endif /* MULTIUSER */
280
#ifdef BUILTIN_TELNET
281
if (fore->w_type == W_TYPE_TELNET && TelIsline(fore) && *bufpp != fore->w_telbuf)
283
TelProcessLine(bufpp, lenp);
291
/* we send the user input to our pseudowin */
292
ibuf = fore->w_pwin->p_inbuf; ilen = &fore->w_pwin->p_inlen;
293
f = sizeof(fore->w_pwin->p_inbuf) - *ilen;
298
/* we send the user input to the window */
299
ibuf = fore->w_inbuf; ilen = &fore->w_inlen;
300
f = sizeof(fore->w_inbuf) - *ilen;
305
#ifdef BUILTIN_TELNET
312
bcopy(*bufpp, ibuf + *ilen, l2);
313
if (fore->w_autolf && (trunc = DoAutolf(ibuf + *ilen, &l2, f - l2)))
315
#ifdef BUILTIN_TELNET
316
if (fore->w_type == W_TYPE_TELNET && (trunc = DoTelnet(ibuf + *ilen, &l2, f - l2)))
320
continue; /* need exact value */
331
ZombieProcess(bufpp, lenp)
336
char *buf = *bufpp, b1[10], b2[10];
338
debug1("ZombieProcess: %d bytes\n", *lenp);
339
fore = (struct win *)flayer->l_data;
341
ASSERT(fore->w_ptyfd < 0);
344
for (; l-- > 0; buf++)
346
if (*(unsigned char *)buf == ZombieKey_destroy)
348
debug1("Turning undead: %d\n", fore->w_number);
352
if (*(unsigned char *)buf == ZombieKey_resurrect)
354
debug1("Resurrecting Zombie: %d\n", fore->w_number);
355
WriteString(fore, "\r\n", 2);
360
b1[AddXChar(b1, ZombieKey_destroy)] = '\0';
361
b2[AddXChar(b2, ZombieKey_resurrect)] = '\0';
362
Msg(0, "Press %s to destroy or %s to resurrect window", b1, b2);
366
WinRedisplayLine(y, from, to, isblank)
367
int y, from, to, isblank;
369
debug3("WinRedisplayLine %d %d %d\n", y, from, to);
372
fore = (struct win *)flayer->l_data;
373
if (from == 0 && y > 0 && fore->w_mlines[y - 1].image[fore->w_width] == 0)
374
LCDisplayLineWrap(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
376
LCDisplayLine(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank);
380
WinRewrite(y, x1, x2, rend, doit)
384
register int cost, dx;
385
register unsigned char *p, *i;
387
register unsigned char *f;
390
register unsigned char *c;
392
register unsigned char *cx;
396
debug3("WinRewrite %d, %d-%d\n", y, x1, x2);
397
fore = (struct win *)flayer->l_data;
401
i = fore->w_mlines[y].image + x1;
406
p = fore->w_mlines[y].attr + x1;
408
f = fore->w_mlines[y].font + x1;
410
if (is_dw_font(rend->font))
414
if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(fore->w_mlines + y, x1, x2, fore->w_encoding))
419
c = fore->w_mlines[y].color + x1;
421
cx = fore->w_mlines[y].colorx + x1;
425
cost = dx = x2 - x1 + 1;
428
if (*p++ != rend->attr)
431
if (*f++ != rend->font)
435
if (*c++ != rend->color)
438
if (*cx++ != rend->colorx)
447
WinClearLine(y, xs, xe, bce)
450
fore = (struct win *)flayer->l_data;
451
debug3("WinClearLine %d %d-%d\n", y, xs, xe);
452
LClearLine(flayer, y, xs, xe, bce, &fore->w_mlines[y]);
459
fore = (struct win *)flayer->l_data;
460
ChangeWindowSize(fore, wi, he, fore->w_histheight);
468
fore = (struct win *)flayer->l_data;
469
debug1("WinRestore: win %x\n", fore);
470
for (cv = flayer->l_cvlist; cv; cv = cv->c_next)
472
display = cv->c_display;
475
/* ChangeScrollRegion(fore->w_top, fore->w_bot); */
476
KeypadMode(fore->w_keypad);
477
CursorkeysMode(fore->w_cursorkeys);
478
SetFlow(fore->w_flow & FLOW_NOW);
479
InsertMode(fore->w_insert);
480
ReverseVideo(fore->w_revvid);
481
CursorVisibility(fore->w_curinv ? -1 : fore->w_curvvis);
482
MouseMode(fore->w_mouse);
486
/*****************************************************************/
490
* DoStartLog constructs a path for the "want to be logfile" in buf and
493
* returns 0 on success.
496
DoStartLog(w, buf, bufsize)
505
strncpy(buf, MakeWinMsg(screenlogfile, w, '%'), bufsize - 1);
506
buf[bufsize - 1] = 0;
508
debug2("DoStartLog: win %d, file %s\n", w->w_number, buf);
510
if (w->w_log != NULL)
513
if ((w->w_log = logfopen(buf, islogfile(buf) ? NULL : secfopen(buf, "a"))) == NULL)
515
if (!logflushev.queued)
517
n = log_flush ? log_flush : (logtstamp_after + 4) / 5;
520
SetTimeout(&logflushev, n * 1000);
528
* Umask & wlock are set for the user of the display,
529
* The display d (if specified) switches to that window.
533
struct NewWindow *newwin;
535
register struct win **pp, *p;
538
struct NewWindow nwin;
542
extern struct acluser *users;
545
debug1("NewWindow: StartAt %d\n", newwin->StartAt);
546
debug1("NewWindow: aka %s\n", newwin->aka?newwin->aka:"NULL");
547
debug1("NewWindow: dir %s\n", newwin->dir?newwin->dir:"NULL");
548
debug1("NewWindow: term %s\n", newwin->term?newwin->term:"NULL");
550
nwin_compose(&nwin_default, newwin, &nwin);
551
debug1("NWin: aka %s\n", nwin.aka ? nwin.aka : "NULL");
552
debug1("NWin: wlock %d\n", nwin.wlock);
553
debug1("NWin: Lflag %d\n", nwin.Lflag);
555
startat = nwin.StartAt < maxwin ? nwin.StartAt : 0;
562
if (++pp == wtab + maxwin)
565
while (pp != wtab + startat);
568
Msg(0, "No more windows.");
572
#if defined(USRLIMIT) && defined(UTMPOK)
574
* Count current number of users, if logging windows in.
576
if (nwin.lflag && CountUsers() >= USRLIMIT)
578
Msg(0, "User limit reached. Window will not be logged in.");
583
debug1("Makewin creating %d\n", n);
585
if ((f = OpenDevice(nwin.args, nwin.lflag, &type, &TtyName)) < 0)
588
if ((p = (struct win *)malloc(sizeof(struct win))) == 0)
594
bzero((char *)p, (int)sizeof(struct win));
597
if (type != W_TYPE_PTY)
603
/* save the command line so that zombies can be resurrected */
604
for (i = 0; nwin.args[i] && i < MAXARGS - 1; i++)
605
p->w_cmdargs[i] = SaveStr(nwin.args[i]);
608
p->w_dir = SaveStr(nwin.dir);
610
p->w_term = SaveStr(nwin.term);
615
* This is dangerous: without a display we use creators umask
616
* This is intended to be usefull for detached startup.
617
* But is still better than default bits with a NULL user.
619
if (NewWindowAcl(p, display ? D_user : users))
627
p->w_layer.l_next = 0;
628
p->w_layer.l_bottom = &p->w_layer;
629
p->w_layer.l_layfn = &WinLf;
630
p->w_layer.l_data = (char *)p;
631
p->w_savelayer = &p->w_layer;
636
if (display && !AclCheckPermWin(D_user, ACL_WRITE, p))
637
p->w_wlockuser = D_user;
638
p->w_wlock = nwin.wlock;
641
p->w_aflag = nwin.aflag;
642
p->w_flow = nwin.flowflag | ((nwin.flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO);
644
nwin.aka = Filename(nwin.args[0]);
645
strncpy(p->w_akabuf, nwin.aka, sizeof(p->w_akabuf) - 1);
646
if ((nwin.aka = rindex(p->w_akabuf, '|')) != NULL)
650
p->w_title = nwin.aka;
651
p->w_akachange = nwin.aka + strlen(nwin.aka);
654
p->w_title = p->w_akachange = p->w_akabuf;
656
p->w_hstatus = SaveStr(nwin.hstatus);
657
p->w_monitor = nwin.monitor;
659
if (p->w_monitor == MON_ON)
661
/* always tell all users */
662
for (i = 0; i < maxusercount; i++)
663
ACLBYTE(p->w_mon_notify, i) |= ACLBIT(i);
667
* defsilence by Lloyd Zusman (zusman_lloyd@jpmorgan.com)
669
p->w_silence = nwin.silence;
670
p->w_silencewait = SilenceWait;
672
if (p->w_silence == SILENCE_ON)
674
/* always tell all users */
675
for (i = 0; i < maxusercount; i++)
676
ACLBYTE(p->w_lio_notify, i) |= ACLBIT(i);
680
p->w_slowpaste = nwin.slow;
686
strncpy(p->w_tty, TtyName, MAXSTR - 1);
689
/* XXX Fixme display resize */
690
if (ChangeWindowSize(p, display ? D_defwidth : 80,
691
display ? D_defheight : 24,
698
if (ChangeWindowSize(p, display ? D_forecv->c_xe - D_forecv->c_xs + 1: 80,
699
display ? D_forecv->c_ye - D_forecv->c_ys + 1 : 24,
707
p->w_encoding = nwin.encoding;
708
ResetWindow(p); /* sets w_wrap, w_c1, w_gr, w_bce */
712
SetCharsets(p, nwin.charset);
717
struct display *d = display; /* WriteString zaps display */
719
WriteString(p, ":screen (", 9);
720
WriteString(p, p->w_title, strlen(p->w_title));
721
WriteString(p, "):", 2);
722
for (f = 0; p->w_cmdargs[f]; f++)
724
WriteString(p, " ", 1);
725
WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
727
WriteString(p, "\r\n", 2);
736
#ifdef BUILTIN_TELNET
737
if (type == W_TYPE_TELNET)
747
if (type == W_TYPE_PTY)
749
p->w_pid = ForkWindow(p, nwin.args, TtyName);
758
* Place the new window at the head of the most-recently-used list.
760
if (display && D_fore)
765
p->w_lflag = nwin.lflag;
767
p->w_slot = (slot_t)-1;
769
debug1("MakeWindow will %slog in.\n", nwin.lflag?"":"not ");
771
# else /* LOGOUTOK */
772
debug1("MakeWindow will log in, LOGOUTOK undefined in config.h%s.\n",
773
nwin.lflag?"":" (although lflag=0)");
774
# endif /* LOGOUTOK */
776
p->w_slot = (slot_t)0;
777
if (display || (p->w_lflag & 2))
781
CarefulUtmp(); /* If all 've been zombies, we've had no slot */
788
DoStartLog(p, buf, sizeof(buf));
791
p->w_readev.fd = p->w_writeev.fd = p->w_ptyfd;
792
p->w_readev.type = EV_READ;
793
p->w_writeev.type = EV_WRITE;
794
p->w_readev.data = p->w_writeev.data = (char *)p;
795
p->w_readev.handler = win_readev_fn;
796
p->w_writeev.handler = win_writeev_fn;
797
p->w_writeev.condpos = &p->w_inlen;
799
evenq(&p->w_writeev);
801
p->w_paster.pa_slowev.type = EV_TIMEOUT;
802
p->w_paster.pa_slowev.data = (char *)&p->w_paster;
803
p->w_paster.pa_slowev.handler = paste_slowev_fn;
805
p->w_silenceev.type = EV_TIMEOUT;
806
p->w_silenceev.data = (char *)p;
807
p->w_silenceev.handler = win_silenceev_fn;
808
if (p->w_silence > 0)
810
debug("New window has silence enabled.\n");
811
SetTimeout(&p->w_silenceev, p->w_silencewait * 1000);
812
evenq(&p->w_silenceev);
816
Activate(p->w_norefresh);
817
WindowChanged((struct win*)0, 'w');
818
WindowChanged((struct win*)0, 'W');
819
WindowChanged((struct win*)0, 0);
824
* Resurrect a window from Zombie state.
825
* The command vector is therefore stored in the window structure.
826
* Note: The terminaltype defaults to screenterm again, the current
827
* working directory is lost.
836
lflag = nwin_default.lflag;
837
if ((f = OpenDevice(p->w_cmdargs, lflag, &p->w_type, &TtyName)) < 0)
840
strncpy(p->w_tty, *TtyName ? TtyName : p->w_title, MAXSTR - 1);
845
evenq(&p->w_writeev);
849
struct display *d = display; /* WriteString zaps display */
851
WriteString(p, ":screen (", 9);
852
WriteString(p, p->w_title, strlen(p->w_title));
853
WriteString(p, "):", 2);
854
for (f = 0; p->w_cmdargs[f]; f++)
856
WriteString(p, " ", 1);
857
WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f]));
859
WriteString(p, "\r\n", 2);
864
#ifdef BUILTIN_TELNET
865
if (p->w_type == W_TYPE_TELNET)
872
if (p->w_type == W_TYPE_PTY)
874
p->w_pid = ForkWindow(p, p->w_cmdargs, TtyName);
880
if (p->w_slot == (slot_t)0 && (display || (p->w_lflag & 2)))
883
CarefulUtmp(); /* If all 've been zombies, we've had no slot */
886
WindowChanged(p, 'f');
896
if (wp->w_type == W_TYPE_PTY)
899
(void)chmod(wp->w_tty, 0666);
900
(void)chown(wp->w_tty, 0, 0);
905
evdeq(&wp->w_readev);
906
evdeq(&wp->w_writeev);
907
#ifdef BUILTIN_TELNET
908
evdeq(&wp->w_telconnev);
910
wp->w_readev.fd = wp->w_writeev.fd = -1;
919
struct canvas *cv, *ncv;
922
debug1("FreeWindow %d\n", wp ? wp->w_number: -1);
932
if (wp == console_window)
934
TtyGrabConsole(-1, -1, "free");
937
if (wp->w_log != NULL)
938
logfclose(wp->w_log);
939
ChangeWindowSize(wp, 0, 0, 0);
943
for (i = 0; wp->w_cmdargs[i]; i++)
944
free(wp->w_cmdargs[i]);
949
for (d = displays; d; d = d->d_next)
951
if (d->d_other == wp)
952
d->d_other = d->d_fore && d->d_fore->w_next != wp ? d->d_fore->w_next : wp->w_next;
955
for (cv = d->d_cvlist; cv; cv = cv->c_next)
957
for (l = cv->c_layer; l; l = l->l_next)
958
if (l->l_layfn == &WinLf)
962
if ((struct win *)l->l_data != wp)
964
if (cv->c_layer == wp->w_savelayer)
966
KillLayerChain(cv->c_layer);
970
KillLayerChain(wp->w_savelayer);
971
for (cv = wp->w_layer.l_cvlist; cv; cv = ncv)
974
cv->c_layer = &cv->c_blank;
975
cv->c_blank.l_cvlist = cv;
977
cv->c_xoff = cv->c_xs;
978
cv->c_yoff = cv->c_ys;
979
RethinkViewportOffsets(cv);
981
wp->w_layer.l_cvlist = 0;
982
if (flayer == &wp->w_layer)
987
#endif /* MULTIUSER */
988
evdeq(&wp->w_readev); /* just in case */
989
evdeq(&wp->w_writeev); /* just in case */
990
evdeq(&wp->w_silenceev);
992
FreePaster(&wp->w_paster);
998
OpenDevice(args, lflag, typep, namep)
1004
char *arg = args[0];
1010
#ifdef BUILTIN_TELNET
1011
if (strcmp(arg, "//telnet") == 0)
1013
f = TelOpen(args + 1);
1015
*typep = W_TYPE_TELNET;
1020
if ((stat(arg, &st)) == 0 && S_ISCHR(st.st_mode))
1022
if (access(arg, R_OK | W_OK) == -1)
1024
Msg(errno, "Cannot access line '%s' for R/W", arg);
1027
debug("OpenDevice: OpenTTY\n");
1028
if ((f = OpenTTY(arg, args[1])) < 0)
1031
*typep = W_TYPE_PLAIN;
1036
*typep = W_TYPE_PTY;
1040
Msg(0, "No more PTYs.");
1046
if (ioctl(f, TIOCPKT, (char *)&flag))
1048
Msg(errno, "TIOCPKT ioctl");
1053
#endif /* TIOCPKT */
1055
debug1("fcntl(%d, F_SETFL, FNBLOCK)\n", f);
1056
(void) fcntl(f, F_SETFL, FNBLOCK);
1059
* Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select
1060
* gets confused in the following condition:
1061
* Open a pty-master side, request a flush on it, then set packet
1062
* mode and call select(). Select will return a possible read, where
1063
* the one byte response to the flush can be found. Select will
1064
* thereafter return a possible read, which yields I/O error.
1066
* If we request another flush *after* switching into packet mode,
1067
* this I/O error does not occur. We receive a single response byte
1068
* although we send two flush requests now.
1070
* Maybe we should not flush at all.
1074
if (*typep == W_TYPE_PTY || *typep == W_TYPE_PLAIN)
1075
tcflush(f, TCIOFLUSH);
1078
if (*typep != W_TYPE_PTY)
1083
if (chown(*namep, real_uid, PTYGROUP) && !eff_uid)
1085
if (chown(*namep, real_uid, real_gid) && !eff_uid)
1088
Msg(errno, "chown tty");
1093
if (chmod(*namep, lflag ? TtyMode : (TtyMode & ~022)) && !eff_uid)
1095
if (chmod(*namep, TtyMode) && !eff_uid)
1098
Msg(errno, "chmod tty");
1107
* Fields w_width, w_height, aflag, number (and w_tty)
1108
* are read from struct win *win. No fields written.
1109
* If pwin is nonzero, filedescriptors are distributed
1110
* between win->w_tty and open(ttyn)
1114
ForkWindow(win, args, ttyn)
1121
char shellbuf[7 + MAXPATHLEN];
1124
char libuf[20], cobuf[20];
1127
int w = win->w_width;
1128
int h = win->w_height;
1130
int i, pat, wfdused;
1131
struct pseudowin *pwin = win->w_pwin;
1138
debug("pre-opening slave...\n");
1139
if ((slave = open(ttyn, O_RDWR|O_NOCTTY)) == -1)
1146
debug("forking...\n");
1155
switch (pid = fork())
1161
signal(SIGHUP, SIG_DFL);
1162
signal(SIGINT, SIG_DFL);
1163
signal(SIGQUIT, SIG_DFL);
1164
signal(SIGTERM, SIG_DFL);
1166
signal(SIGTTIN, SIG_DFL);
1167
signal(SIGTTOU, SIG_DFL);
1170
signal(SIGPIPE, SIG_DFL);
1173
signal(SIGXFSZ, SIG_DFL);
1176
displays = 0; /* beware of Panic() */
1177
if (setgid(real_gid) || setuid(real_uid))
1178
Panic(errno, "Setuid/gid");
1182
if (!pwin) /* ignore directory if pseudo */
1184
if (win->w_dir && *win->w_dir && chdir(win->w_dir))
1185
Panic(errno, "Cannot chdir to %s", win->w_dir);
1195
if (dfp && dfp != stderr)
1203
closeallfiles(win->w_ptyfd);
1207
closeallfiles(win->w_ptyfd);
1209
if (dfp) /* do not produce child debug, when debug is "off" */
1213
sprintf(buf, "%s/screen.child", DEBUGDIR);
1214
if ((dfp = fopen(buf, "a")) == 0)
1217
(void) chmod(buf, 0666);
1219
debug1("=== ForkWindow: pid %d\n", (int)getpid());
1221
/* Close the three /dev/null descriptors */
1227
* distribute filedescriptors between the ttys
1230
pat = pwin ? pwin->p_fdpat :
1231
((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<<F_PSHIFT) | F_PFRONT);
1232
debug1("Using window pattern 0x%x\n", pat);
1234
for(i = 0; i < 3; i++)
1236
if (pat & F_PFRONT << F_PSHIFT * i)
1242
newfd = open(ttyn, O_RDWR);
1244
newfd = open(ttyn, O_RDWR|O_NOCTTY);
1246
newfd = open(ttyn, O_RDWR);
1249
Panic(errno, "Cannot open %s", ttyn);
1263
* the pseudo window process should not be surprised with a
1264
* nonblocking filedescriptor. Poor Backend!
1266
debug1("Clearing NBLOCK on window-fd(%d)\n", win->w_ptyfd);
1267
if (fcntl(win->w_ptyfd, F_SETFL, 0))
1268
Msg(errno, "Warning: clear NBLOCK fcntl failed");
1273
newfd = open(ttyn, O_RDWR);
1275
newfd = open(ttyn, O_RDWR|O_NOCTTY);
1277
newfd = open(ttyn, O_RDWR);
1280
Panic(errno, "Cannot open %s", ttyn);
1283
#endif /* PSEUDOS */
1284
close(win->w_ptyfd);
1289
struct mode fakemode, *modep;
1292
Msg(errno, "fgtty");
1295
debug("ForkWindow: using display tty mode for new child.\n");
1300
debug("No display - creating tty setting\n");
1307
/* We only want echo if the users input goes to the pseudo
1308
* and the pseudo's stdout is not send to the window.
1311
if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT)))
1313
debug1("clearing echo on pseudywin fd (pat %x)\n", pat);
1314
# if defined(POSIX) || defined(TERMIO)
1315
modep->tio.c_lflag &= ~ECHO;
1316
modep->tio.c_iflag &= ~ICRNL;
1318
modep->m_ttyb.sg_flags &= ~ECHO;
1322
SetTTY(newfd, modep);
1326
(void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz);
1328
/* Always turn off nonblocking mode */
1329
(void)fcntl(newfd, F_SETFL, 0);
1332
sprintf(libuf, "LINES=%d", h);
1333
sprintf(cobuf, "COLUMNS=%d", w);
1338
NewEnv[2] = MakeTermcap(display == 0 || win->w_aflag);
1341
NewEnv[2] = MakeTermcap(1);
1343
NewEnv[2] = Termcap;
1345
strcpy(shellbuf, "SHELL=");
1346
strncpy(shellbuf + 6, ShellProg + (*ShellProg == '-'), sizeof(shellbuf) - 7);
1347
shellbuf[sizeof(shellbuf) - 1] = 0;
1348
NewEnv[4] = shellbuf;
1349
debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf);
1350
if (win->w_term && *win->w_term && strcmp(screenterm, win->w_term) &&
1351
(strlen(win->w_term) < 20))
1355
sprintf(tebuf, "TERM=%s", win->w_term);
1356
debug2("Makewindow %d with %s\n", win->w_number, tebuf);
1357
tl = strlen(win->w_term);
1359
if ((s1 = index(NewEnv[2], '|')))
1361
if ((s2 = index(++s1, '|')))
1363
if (strlen(NewEnv[2]) - (s2 - s1) + tl < 1024)
1365
bcopy(s2, s1 + tl, strlen(s2) + 1);
1366
bcopy(win->w_term, s1, tl);
1371
sprintf(ebuf, "WINDOW=%d", win->w_number);
1377
proc = DefaultShell;
1378
debug1("calling execvpe %s\n", proc);
1379
execvpe(proc, args, NewEnv);
1380
debug1("exec error: %d\n", errno);
1381
Panic(errno, "Cannot exec '%s'", proc);
1391
execvpe(prog, args, env)
1392
char *prog, **args, **env;
1394
register char *path = NULL, *p;
1396
char *shargs[MAXARGS + 1];
1397
register int i, eaccess = 0;
1399
if (rindex(prog, '/'))
1401
if (!path && !(path = getenv("PATH")))
1405
for (p = buf; *path && *path != ':'; path++)
1406
if (p - buf < (int)sizeof(buf) - 2)
1410
if (p - buf + strlen(prog) >= sizeof(buf) - 1)
1413
execve(buf, args, env);
1417
shargs[0] = DefaultShell;
1419
for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i)
1421
execve(DefaultShell, shargs, env);
1444
int i, r = 0, l = 0;
1446
extern struct display *display;
1447
extern struct win *windows;
1448
struct pseudowin *pwin;
1451
if ((w = display ? fore : windows) == NULL)
1453
if (!*av || w->w_pwin)
1455
Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)");
1460
Msg(0, "You feel dead inside.");
1463
if (!(pwin = (struct pseudowin *)malloc(sizeof(struct pseudowin))))
1468
bzero((char *)pwin, (int)sizeof(*pwin));
1470
/* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */
1471
for (s = *av; *s == ' '; s++)
1473
for (p = s; *p == ':' || *p == '.' || *p == '!'; p++)
1476
while (*p && p > s && p[-1] == '.')
1489
for (i = 0; i < 3; i++)
1491
*t = (s < p) ? *s++ : '.';
1496
l |= F_PFRONT << (i * F_PSHIFT);
1499
l |= F_PBACK << (i * F_PSHIFT);
1502
l |= F_PBOTH << (i * F_PSHIFT);
1510
if ((l & F_PMASK) == F_PFRONT)
1513
l ^= F_PFRONT | F_PBACK;
1520
debug1("winexec: '%#x'\n", pwin->p_fdpat);
1523
for (pp = av; *pp; pp++)
1526
while (*p && l-- > 0)
1533
debug1("%s\n", pwin->p_cmd);
1535
if ((pwin->p_ptyfd = OpenDevice(av, 0, &type, &t)) < 0)
1540
strncpy(pwin->p_tty, t, MAXSTR - 1);
1542
if (type != W_TYPE_PTY)
1545
Msg(0, "Cannot only use commands as pseudo win.");
1548
if (!(pwin->p_fdpat & F_PFRONT))
1549
evdeq(&w->w_readev);
1554
if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag))
1556
Msg(errno, "TIOCPKT pwin ioctl");
1560
if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1562
if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1564
Msg(errno, "TIOCPKT win ioctl");
1570
#endif /* TIOCPKT */
1572
pwin->p_readev.fd = pwin->p_writeev.fd = pwin->p_ptyfd;
1573
pwin->p_readev.type = EV_READ;
1574
pwin->p_writeev.type = EV_WRITE;
1575
pwin->p_readev.data = pwin->p_writeev.data = (char *)w;
1576
pwin->p_readev.handler = pseu_readev_fn;
1577
pwin->p_writeev.handler = pseu_writeev_fn;
1578
pwin->p_writeev.condpos = &pwin->p_inlen;
1579
if (pwin->p_fdpat & (F_PFRONT << F_PSHIFT * 2 | F_PFRONT << F_PSHIFT))
1580
evenq(&pwin->p_readev);
1581
evenq(&pwin->p_writeev);
1582
r = pwin->p_pid = ForkWindow(w, av, t);
1592
struct pseudowin *pwin = w->w_pwin;
1595
if (fcntl(w->w_ptyfd, F_SETFL, FNBLOCK))
1596
Msg(errno, "Warning: FreePseudowin: NBLOCK fcntl failed");
1598
if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT))
1601
if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag))
1602
Msg(errno, "Warning: FreePseudowin: TIOCPKT win ioctl");
1605
/* should be able to use CloseDevice() here */
1606
(void)chmod(pwin->p_tty, 0666);
1607
(void)chown(pwin->p_tty, 0, 0);
1608
if (pwin->p_ptyfd >= 0)
1609
close(pwin->p_ptyfd);
1610
evdeq(&pwin->p_readev);
1611
evdeq(&pwin->p_writeev);
1612
if (w->w_readev.condneg == &pwin->p_inlen)
1613
w->w_readev.condpos = w->w_readev.condneg = 0;
1614
evenq(&w->w_readev);
1619
#endif /* PSEUDOS */
1624
* returns 0, if the lock really has been released
1627
ReleaseAutoWritelock(dis, w)
1628
struct display *dis;
1631
debug2("ReleaseAutoWritelock: user %s, window %d\n",
1632
dis->d_user->u_name, w->w_number);
1634
/* release auto writelock when user has no other display here */
1635
if (w->w_wlock == WLOCK_AUTO && w->w_wlockuser == dis->d_user)
1639
for (d = displays; d; d = d->d_next)
1640
if (( d != dis) && (d->d_fore == w) && (d->d_user == dis->d_user))
1642
debug3("%s %s autolock on win %d\n",
1643
dis->d_user->u_name, d ? "keeps" : "releases", w->w_number);
1646
w->w_wlockuser = NULL;
1654
* returns 0, if the lock really could be obtained
1657
ObtainAutoWritelock(d, w)
1661
if ((w->w_wlock == WLOCK_AUTO) &&
1662
!AclCheckPermWin(d->d_user, ACL_WRITE, w) &&
1665
debug2("%s obtained auto writelock for exported window %d\n",
1666
d->d_user->u_name, w->w_number);
1667
w->w_wlockuser = d->d_user;
1673
#endif /* MULTIUSER */
1677
/********************************************************************/
1681
paste_slowev_fn(ev, data)
1685
struct paster *pa = (struct paster *)data;
1689
flayer = pa->pa_pastelayer;
1691
pa->pa_pastelen = 0;
1692
if (!pa->pa_pastelen)
1694
p = Layer2Window(flayer);
1695
DoProcess(p, &pa->pa_pasteptr, &l, pa);
1696
pa->pa_pastelen -= 1 - l;
1697
if (pa->pa_pastelen > 0)
1699
SetTimeout(&pa->pa_slowev, p->w_slowpaste);
1700
evenq(&pa->pa_slowev);
1712
for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext)
1714
display = cv->c_display;
1715
if (D_status == STATUS_ON_WIN && !D_status_bell)
1717
/* wait 'til status is gone */
1718
debug("BLOCKING because of status\n");
1719
ev->condpos = &const_one;
1720
ev->condneg = &D_status;
1723
debug2("muchpending %s %d: ", D_usertty, D_blocked);
1724
debug3("%d %d %d\n", D_obufp - D_obuf, D_obufmax, D_blocked_fuzz);
1727
if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz)
1729
if (D_nonblock == 0)
1731
debug1("obuf is full, stopping output to display %s\n", D_usertty);
1735
debug("BLOCKING because of full obuf\n");
1736
ev->condpos = &D_obuffree;
1737
ev->condneg = &D_obuflenmax;
1738
if (D_nonblock > 0 && !D_blockedev.queued)
1740
debug1("created timeout of %g secs\n", D_nonblock/1000.);
1741
SetTimeout(&D_blockedev, D_nonblock);
1742
evenq(&D_blockedev);
1751
win_readev_fn(ev, data)
1755
struct win *p = (struct win *)data;
1756
char buf[IOSIZE], *bp;
1766
wtop = p->w_pwin && W_WTOP(p);
1769
ASSERT(sizeof(p->w_pwin->p_inbuf) == IOSIZE);
1770
size = IOSIZE - p->w_pwin->p_inlen;
1773
ev->condpos = &const_IOSIZE;
1774
ev->condneg = &p->w_pwin->p_inlen;
1779
if (p->w_layer.l_cvlist && muchpending(p, ev))
1786
ev->condpos = &const_one;
1787
ev->condneg = &p->w_blocked;
1791
ev->condpos = ev->condneg = 0;
1793
if ((len = p->w_outlen))
1796
WriteString(p, p->w_outbuf, len);
1800
debug1("going to read from window fd %d\n", ev->fd);
1801
if ((len = read(ev->fd, buf, size)) < 0)
1803
if (errno == EINTR || errno == EAGAIN)
1805
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1806
if (errno == EWOULDBLOCK)
1809
debug2("Window %d: read error (errno %d) - killing window\n", p->w_number, errno);
1815
debug1("Window %d: EOF - killing window\n", p->w_number);
1819
debug1(" -> %d bytes\n", len);
1821
if (p->w_type == W_TYPE_PTY)
1825
debug1("PAKET %x\n", buf[0]);
1826
if (buf[0] & TIOCPKT_NOSTOP)
1828
if (buf[0] & TIOCPKT_DOSTOP)
1835
#ifdef BUILTIN_TELNET
1836
if (p->w_type == W_TYPE_TELNET)
1837
len = TelIn(p, bp, len, buf + sizeof(buf) - (bp + len));
1842
if (zmodem_mode && zmodem_parse(p, bp, len))
1848
debug("sending input to pwin\n");
1849
bcopy(bp, p->w_pwin->p_inbuf + p->w_pwin->p_inlen, len);
1850
p->w_pwin->p_inlen += len;
1853
WriteString(p, bp, len);
1859
win_writeev_fn(ev, data)
1863
struct win *p = (struct win *)data;
1867
debug2("writing %d bytes to win %d\n", p->w_inlen, p->w_number);
1868
if ((len = write(ev->fd, p->w_inbuf, p->w_inlen)) <= 0)
1869
len = p->w_inlen; /* dead window */
1870
if ((p->w_inlen -= len))
1871
bcopy(p->w_inbuf + len, p->w_inbuf, p->w_inlen);
1874
if (p->w_paster.pa_pastelen && !p->w_slowpaste)
1876
struct paster *pa = &p->w_paster;
1877
flayer = pa->pa_pastelayer;
1879
DoProcess(p, &pa->pa_pasteptr, &pa->pa_pastelen, pa);
1890
pseu_readev_fn(ev, data)
1894
struct win *p = (struct win *)data;
1896
int size, ptow, len;
1903
ASSERT(sizeof(p->w_inbuf) == IOSIZE);
1904
size = IOSIZE - p->w_inlen;
1907
ev->condpos = &const_IOSIZE;
1908
ev->condneg = &p->w_inlen;
1912
if (p->w_layer.l_cvlist && muchpending(p, ev))
1916
ev->condpos = &const_one;
1917
ev->condneg = &p->w_blocked;
1921
ev->condpos = ev->condneg = 0;
1923
if ((len = p->w_outlen))
1926
WriteString(p, p->w_outbuf, len);
1930
if ((len = read(ev->fd, buf, size)) <= 0)
1932
if (errno == EINTR || errno == EAGAIN)
1934
#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN)
1935
if (errno == EWOULDBLOCK)
1938
debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p->w_number, len ? errno : 0);
1942
/* no packet mode on pseudos! */
1945
bcopy(buf, p->w_inbuf + p->w_inlen, len);
1948
WriteString(p, buf, len);
1953
pseu_writeev_fn(ev, data)
1957
struct win *p = (struct win *)data;
1958
struct pseudowin *pw = p->w_pwin;
1962
if (pw->p_inlen == 0)
1964
if ((len = write(ev->fd, pw->p_inbuf, pw->p_inlen)) <= 0)
1965
len = pw->p_inlen; /* dead pseudo */
1966
if ((p->w_pwin->p_inlen -= len))
1967
bcopy(p->w_pwin->p_inbuf + len, p->w_pwin->p_inbuf, p->w_pwin->p_inlen);
1971
#endif /* PSEUDOS */
1974
win_silenceev_fn(ev, data)
1978
struct win *p = (struct win *)data;
1980
debug1("FOUND silence win %d\n", p->w_number);
1981
for (display = displays; display; display = display->d_next)
1983
for (cv = D_cvlist; cv; cv = cv->c_next)
1984
if (cv->c_layer->l_bottom == &p->w_layer)
1987
continue; /* user already sees window */
1989
if (!(ACLBYTE(p->w_lio_notify, D_user->u_id) & ACLBIT(D_user->u_id)))
1992
Msg(0, "Window %d: silence for %d seconds", p->w_number, p->w_silencewait);
1999
zmodem_parse(p, bp, len)
2006
for (i = 0; i < len; i++, b2++)
2008
if (p->w_zauto == 0)
2010
for (; i < len; i++, b2++)
2015
if (i > 1 && b2[-1] == '*' && b2[-2] == '*')
2019
if (p->w_zauto > 5 || *b2 == "**\030B00"[p->w_zauto] || (p->w_zauto == 5 && *b2 == '1') || (p->w_zauto == 5 && p->w_zdisplay && *b2 == '8'))
2021
if (++p->w_zauto < 6)
2023
if (p->w_zauto == 6)
2028
WriteString(p, bp, i + 1 - 6);
2029
WriteString(p, "\r\n", 2);
2030
zmodem_found(p, *b2 == '1', b2 + 1, len - i - 1);
2033
else if (p->w_zauto == 7 || *b2 == '8')
2035
int se = p->w_zdisplay->d_blocked == 2 ? 'O' : '\212';
2036
for (; i < len; i++, b2++)
2043
D_readev.condpos = D_readev.condneg = 0;
2047
Activate(D_fore ? D_fore->w_norefresh : 0);
2054
p->w_zauto = *b2 == '*' ? (p->w_zauto == 2 ? 2 : 1) : 0;
2056
if (p->w_zauto == 0 && bp[len - 1] == '*')
2057
p->w_zauto = len > 1 && bp[len - 2] == '*' ? 2 : 1;
2060
display = p->w_zdisplay;
2069
zmodem_fin(buf, len, data)
2078
RcLine(buf, strlen(buf) + 1);
2081
s = "\030\030\030\030\030\030\030\030\030\030";
2088
zmodem_found(p, send, bp, len)
2096
extern int zmodem_mode;
2098
/* check for abort sequence */
2100
for (i = 0; i < len ; i++)
2105
if (zmodem_mode == 3 || (zmodem_mode == 1 && p->w_type != W_TYPE_PLAIN))
2107
struct display *d, *olddisplay;
2109
olddisplay = display;
2111
if (!d || d->d_fore != p)
2112
for (d = displays; d; d = d->d_next)
2115
if (!d && p->w_layer.l_cvlist)
2116
d = p->w_layer.l_cvlist->c_display;
2123
p->w_zdisplay = display;
2124
D_blocked = 2 + send;
2125
flayer = &p->w_layer;
2128
evdeq(&D_blockedev);
2129
D_readev.condpos = &const_IOSIZE;
2130
D_readev.condneg = &p->w_inlen;
2133
SetRendition(&mchar_blank);
2134
AddStr("Zmodem active\r\n\r\n");
2135
AddStr(send ? "**\030B01" : "**\030B00");
2138
display = olddisplay;
2141
flayer = &p->w_layer;
2142
Input(":", 100, INP_COOKED, zmodem_fin, NULL);
2143
s = send ? zmodem_sendcmd : zmodem_recvcmd;
2153
struct display *olddisplay = display;
2154
struct layer *oldflayer = flayer;
2157
if (p->w_savelayer && p->w_savelayer->l_next)
2159
if (oldflayer == p->w_savelayer)
2160
oldflayer = flayer->l_next;
2161
flayer = p->w_savelayer;
2166
LRefreshAll(&p->w_layer, 0);
2172
D_readev.condpos = D_readev.condneg = 0;
2173
Activate(D_fore ? D_fore->w_norefresh : 0);
2175
display = olddisplay;