1/* Copyright (c) 1993-2002 2 * Juergen Weigert (jnweiger@immd4.informatik.uni-erlangen.de) 3 * Michael Schroeder (mlschroe@immd4.informatik.uni-erlangen.de) 4 * Copyright (c) 1987 Oliver Laumann 5 * 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) 9 * any later version. 10 * 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. 15 * 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 20 * 21 **************************************************************** 22 */ 23 24#include <sys/types.h> 25#include <sys/stat.h> 26#include <signal.h> 27#include <fcntl.h> 28#ifdef __APPLE__ 29#include <unistd.h> 30#endif __APPLE__ 31#ifndef sun 32# include <sys/ioctl.h> 33#endif 34 35#include "config.h" 36 37#include "screen.h" 38#include "extern.h" 39#include "logfile.h" /* logfopen() */ 40 41extern struct display *displays, *display; 42extern struct win *windows, *fore, *wtab[], *console_window; 43extern char *ShellArgs[]; 44extern char *ShellProg; 45extern char screenterm[]; 46extern char *screenlogfile; 47extern char HostName[]; 48extern int TtyMode; 49extern int SilenceWait; 50extern int real_uid, real_gid, eff_uid, eff_gid; 51extern char Termcap[]; 52extern char **NewEnv; 53extern int visual_bell, maxwin; 54extern struct event logflushev; 55extern int log_flush, logtstamp_after; 56extern int ZombieKey_destroy, ZombieKey_resurrect; 57extern struct layer *flayer; 58extern int maxusercount; 59extern int pty_preopen; 60#ifdef ZMODEM 61extern int zmodem_mode; 62extern struct mchar mchar_blank; 63extern char *zmodem_sendcmd; 64extern char *zmodem_recvcmd; 65#endif 66 67#if defined(TIOCSWINSZ) || defined(TIOCGWINSZ) 68extern struct winsize glwz; 69#endif 70 71#ifdef O_NOCTTY 72extern int separate_sids; 73#endif 74 75static void WinProcess __P((char **, int *)); 76static void WinRedisplayLine __P((int, int, int, int)); 77static void WinClearLine __P((int, int, int, int)); 78static int WinRewrite __P((int, int, int, struct mchar *, int)); 79static int WinResize __P((int, int)); 80static void WinRestore __P((void)); 81static int DoAutolf __P((char *, int *, int)); 82static void ZombieProcess __P((char **, int *)); 83static void win_readev_fn __P((struct event *, char *)); 84static void win_writeev_fn __P((struct event *, char *)); 85static int muchpending __P((struct win *, struct event *)); 86#ifdef COPY_PASTE 87static void paste_slowev_fn __P((struct event *, char *)); 88#endif 89#ifdef PSEUDOS 90static void pseu_readev_fn __P((struct event *, char *)); 91static void pseu_writeev_fn __P((struct event *, char *)); 92#endif 93static void win_silenceev_fn __P((struct event *, char *)); 94 95static int OpenDevice __P((char **, int, int *, char **)); 96static int ForkWindow __P((struct win *, char **, char *)); 97#ifdef ZMODEM 98static void zmodem_found __P((struct win *, int, char *, int)); 99static void zmodem_fin __P((char *, int, char *)); 100static int zmodem_parse __P((struct win *, char *, int)); 101#endif 102 103 104 105int VerboseCreate = 0; /* XXX move this to user.h */ 106 107char DefaultShell[] = "/bin/sh"; 108static char DefaultPath[] = ":/usr/ucb:/bin:/usr/bin"; 109 110/* keep this in sync with the structure definition in window.h */ 111struct NewWindow nwin_undef = 112{ 113 -1, /* StartAt */ 114 (char *)0, /* aka */ 115 (char **)0, /* args */ 116 (char *)0, /* dir */ 117 (char *)0, /* term */ 118 -1, /* aflag */ 119 -1, /* flowflag */ 120 -1, /* lflag */ 121 -1, /* histheight */ 122 -1, /* monitor */ 123 -1, /* wlock */ 124 -1, /* silence */ 125 -1, /* wrap */ 126 -1, /* logging */ 127 -1, /* slowpaste */ 128 -1, /* gr */ 129 -1, /* c1 */ 130 -1, /* bce */ 131 -1, /* encoding */ 132 (char *)0, /* hstatus */ 133 (char *)0 /* charset */ 134}; 135 136struct NewWindow nwin_default = 137{ 138 0, /* StartAt */ 139 0, /* aka */ 140 ShellArgs, /* args */ 141 0, /* dir */ 142 screenterm, /* term */ 143 0, /* aflag */ 144 1*FLOW_NOW, /* flowflag */ 145 LOGINDEFAULT, /* lflag */ 146 DEFAULTHISTHEIGHT, /* histheight */ 147 MON_OFF, /* monitor */ 148 WLOCK_OFF, /* wlock */ 149 0, /* silence */ 150 1, /* wrap */ 151 0, /* logging */ 152 0, /* slowpaste */ 153 0, /* gr */ 154 1, /* c1 */ 155 0, /* bce */ 156 0, /* encoding */ 157 (char *)0, /* hstatus */ 158 (char *)0 /* charset */ 159}; 160 161struct NewWindow nwin_options; 162 163static int const_IOSIZE = IOSIZE; 164static int const_one = 1; 165 166void 167nwin_compose(def, new, res) 168struct NewWindow *def, *new, *res; 169{ 170#define COMPOSE(x) res->x = new->x != nwin_undef.x ? new->x : def->x 171 COMPOSE(StartAt); 172 COMPOSE(aka); 173 COMPOSE(args); 174 COMPOSE(dir); 175 COMPOSE(term); 176 COMPOSE(aflag); 177 COMPOSE(flowflag); 178 COMPOSE(lflag); 179 COMPOSE(histheight); 180 COMPOSE(monitor); 181 COMPOSE(wlock); 182 COMPOSE(silence); 183 COMPOSE(wrap); 184 COMPOSE(Lflag); 185 COMPOSE(slow); 186 COMPOSE(gr); 187 COMPOSE(c1); 188 COMPOSE(bce); 189 COMPOSE(encoding); 190 COMPOSE(hstatus); 191 COMPOSE(charset); 192#undef COMPOSE 193} 194 195/***************************************************************** 196 * 197 * The window layer functions 198 */ 199 200struct LayFuncs WinLf = 201{ 202 WinProcess, 203 0, 204 WinRedisplayLine, 205 WinClearLine, 206 WinRewrite, 207 WinResize, 208 WinRestore 209}; 210 211static int 212DoAutolf(buf, lenp, fr) 213char *buf; 214int *lenp; 215int fr; 216{ 217 char *p; 218 int len = *lenp; 219 int trunc = 0; 220 221 for (p = buf; len > 0; p++, len--) 222 { 223 if (*p != '\r') 224 continue; 225 if (fr-- <= 0) 226 { 227 trunc++; 228 len--; 229 } 230 if (len == 0) 231 break; 232 bcopy(p, p + 1, len++); 233 p[1] = '\n'; 234 } 235 *lenp = p - buf; 236 return trunc; 237} 238 239static void 240WinProcess(bufpp, lenp) 241char **bufpp; 242int *lenp; 243{ 244 int l2 = 0, f, *ilen, l = *lenp, trunc; 245 char *ibuf; 246 247 debug1("WinProcess: %d bytes\n", *lenp); 248 fore = (struct win *)flayer->l_data; 249 250 if (fore->w_ptyfd < 0) /* zombie? */ 251 { 252 ZombieProcess(bufpp, lenp); 253 return; 254 } 255#ifdef MULTIUSER 256 /* a pending writelock is this: 257 * fore->w_wlock == WLOCK_AUTO, fore->w_wlockuse = NULL 258 * The user who wants to use this window next, will get the lock, if he can. 259 */ 260 if (display && fore->w_wlock == WLOCK_AUTO && 261 !fore->w_wlockuser && !AclCheckPermWin(D_user, ACL_WRITE, fore)) 262 { 263 fore->w_wlockuser = D_user; 264 debug2("window %d: pending writelock grabbed by user %s\n", 265 fore->w_number, fore->w_wlockuser->u_name); 266 } 267 /* if w_wlock is set, only one user may write, else we check acls */ 268 if (display && ((fore->w_wlock == WLOCK_OFF) ? 269 AclCheckPermWin(D_user, ACL_WRITE, fore) : 270 (D_user != fore->w_wlockuser))) 271 { 272 debug2("window %d, user %s: ", fore->w_number, D_user->u_name); 273 debug2("writelock %d (wlockuser %s)\n", fore->w_wlock, 274 fore->w_wlockuser ? fore->w_wlockuser->u_name : "NULL"); 275 /* XXX FIXME only display !*/ 276 WBell(fore, visual_bell); 277 *bufpp += *lenp; 278 *lenp = 0; 279 return; 280 } 281#endif /* MULTIUSER */ 282 283#ifdef BUILTIN_TELNET 284 if (fore->w_type == W_TYPE_TELNET && TelIsline(fore) && *bufpp != fore->w_telbuf) 285 { 286 TelProcessLine(bufpp, lenp); 287 return; 288 } 289#endif 290 291#ifdef PSEUDOS 292 if (W_UWP(fore)) 293 { 294 /* we send the user input to our pseudowin */ 295 ibuf = fore->w_pwin->p_inbuf; ilen = &fore->w_pwin->p_inlen; 296 f = sizeof(fore->w_pwin->p_inbuf) - *ilen; 297 } 298 else 299#endif /* PSEUDOS */ 300 { 301 /* we send the user input to the window */ 302 ibuf = fore->w_inbuf; ilen = &fore->w_inlen; 303 f = sizeof(fore->w_inbuf) - *ilen; 304 } 305 306 if (l > f) 307 l = f; 308#ifdef BUILTIN_TELNET 309 while (l > 0) 310#else 311 if (l > 0) 312#endif 313 { 314 l2 = l; 315 bcopy(*bufpp, ibuf + *ilen, l2); 316 if (fore->w_autolf && (trunc = DoAutolf(ibuf + *ilen, &l2, f - l2))) 317 l -= trunc; 318#ifdef BUILTIN_TELNET 319 if (fore->w_type == W_TYPE_TELNET && (trunc = DoTelnet(ibuf + *ilen, &l2, f - l2))) 320 { 321 l -= trunc; 322 if (fore->w_autolf) 323 continue; /* need exact value */ 324 } 325#endif 326 *ilen += l2; 327 *bufpp += l; 328 *lenp -= l; 329 return; 330 } 331} 332 333static void 334ZombieProcess(bufpp, lenp) 335char **bufpp; 336int *lenp; 337{ 338 int l = *lenp; 339 char *buf = *bufpp, b1[10], b2[10]; 340 341 debug1("ZombieProcess: %d bytes\n", *lenp); 342 fore = (struct win *)flayer->l_data; 343 344 ASSERT(fore->w_ptyfd < 0); 345 *bufpp += *lenp; 346 *lenp = 0; 347 for (; l-- > 0; buf++) 348 { 349 if (*(unsigned char *)buf == ZombieKey_destroy) 350 { 351 debug1("Turning undead: %d\n", fore->w_number); 352 KillWindow(fore); 353 return; 354 } 355 if (*(unsigned char *)buf == ZombieKey_resurrect) 356 { 357 debug1("Resurrecting Zombie: %d\n", fore->w_number); 358 WriteString(fore, "\r\n", 2); 359 RemakeWindow(fore); 360 return; 361 } 362 } 363 b1[AddXChar(b1, ZombieKey_destroy)] = '\0'; 364 b2[AddXChar(b2, ZombieKey_resurrect)] = '\0'; 365 Msg(0, "Press %s to destroy or %s to resurrect window", b1, b2); 366} 367 368static void 369WinRedisplayLine(y, from, to, isblank) 370int y, from, to, isblank; 371{ 372 debug3("WinRedisplayLine %d %d %d\n", y, from, to); 373 if (y < 0) 374 return; 375 fore = (struct win *)flayer->l_data; 376 if (from == 0 && y > 0 && fore->w_mlines[y - 1].image[fore->w_width] == 0) 377 LCDisplayLineWrap(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank); 378 else 379 LCDisplayLine(&fore->w_layer, &fore->w_mlines[y], y, from, to, isblank); 380} 381 382static int 383WinRewrite(y, x1, x2, rend, doit) 384int y, x1, x2, doit; 385struct mchar *rend; 386{ 387 register int cost, dx; 388 register unsigned char *p, *i; 389#ifdef FONT 390 register unsigned char *f; 391#endif 392#ifdef COLOR 393 register unsigned char *c; 394# ifdef COLORS256 395 register unsigned char *cx; 396# endif 397#endif 398 399 debug3("WinRewrite %d, %d-%d\n", y, x1, x2); 400 fore = (struct win *)flayer->l_data; 401 dx = x2 - x1 + 1; 402 if (doit) 403 { 404 i = fore->w_mlines[y].image + x1; 405 while (dx-- > 0) 406 PUTCHAR(*i++); 407 return 0; 408 } 409 p = fore->w_mlines[y].attr + x1; 410#ifdef FONT 411 f = fore->w_mlines[y].font + x1; 412# ifdef DW_CHARS 413 if (is_dw_font(rend->font)) 414 return EXPENSIVE; 415# endif 416# ifdef UTF8 417 if (fore->w_encoding && fore->w_encoding != UTF8 && D_encoding == UTF8 && ContainsSpecialDeffont(fore->w_mlines + y, x1, x2, fore->w_encoding)) 418 return EXPENSIVE; 419# endif 420#endif 421#ifdef COLOR 422 c = fore->w_mlines[y].color + x1; 423# ifdef COLORS256 424 cx = fore->w_mlines[y].colorx + x1; 425# endif 426#endif 427 428 cost = dx = x2 - x1 + 1; 429 while(dx-- > 0) 430 { 431 if (*p++ != rend->attr) 432 return EXPENSIVE; 433#ifdef FONT 434 if (*f++ != rend->font) 435 return EXPENSIVE; 436#endif 437#ifdef COLOR 438 if (*c++ != rend->color) 439 return EXPENSIVE; 440# ifdef COLORS256 441 if (*cx++ != rend->colorx) 442 return EXPENSIVE; 443# endif 444#endif 445 } 446 return cost; 447} 448 449static void 450WinClearLine(y, xs, xe, bce) 451int y, xs, xe, bce; 452{ 453 fore = (struct win *)flayer->l_data; 454 debug3("WinClearLine %d %d-%d\n", y, xs, xe); 455 LClearLine(flayer, y, xs, xe, bce, &fore->w_mlines[y]); 456} 457 458static int 459WinResize(wi, he) 460int wi, he; 461{ 462 fore = (struct win *)flayer->l_data; 463 ChangeWindowSize(fore, wi, he, fore->w_histheight); 464 return 0; 465} 466 467static void 468WinRestore() 469{ 470 struct canvas *cv; 471 fore = (struct win *)flayer->l_data; 472 debug1("WinRestore: win %x\n", fore); 473 for (cv = flayer->l_cvlist; cv; cv = cv->c_next) 474 { 475 display = cv->c_display; 476 if (cv != D_forecv) 477 continue; 478 /* ChangeScrollRegion(fore->w_top, fore->w_bot); */ 479 KeypadMode(fore->w_keypad); 480 CursorkeysMode(fore->w_cursorkeys); 481 SetFlow(fore->w_flow & FLOW_NOW); 482 InsertMode(fore->w_insert); 483 ReverseVideo(fore->w_revvid); 484 CursorVisibility(fore->w_curinv ? -1 : fore->w_curvvis); 485 MouseMode(fore->w_mouse); 486 } 487} 488 489/*****************************************************************/ 490 491 492/* 493 * DoStartLog constructs a path for the "want to be logfile" in buf and 494 * attempts logfopen. 495 * 496 * returns 0 on success. 497 */ 498int 499DoStartLog(w, buf, bufsize) 500struct win *w; 501char *buf; 502int bufsize; 503{ 504 int n; 505 if (!w || !buf) 506 return -1; 507 508 strncpy(buf, MakeWinMsg(screenlogfile, w, '%'), bufsize - 1); 509 buf[bufsize - 1] = 0; 510 511 debug2("DoStartLog: win %d, file %s\n", w->w_number, buf); 512 513 if (w->w_log != NULL) 514 logfclose(w->w_log); 515 516 if ((w->w_log = logfopen(buf, islogfile(buf) ? NULL : secfopen(buf, "a"))) == NULL) 517 return -2; 518 if (!logflushev.queued) 519 { 520 n = log_flush ? log_flush : (logtstamp_after + 4) / 5; 521 if (n) 522 { 523 SetTimeout(&logflushev, n * 1000); 524 evenq(&logflushev); 525 } 526 } 527 return 0; 528} 529 530/* 531 * Umask & wlock are set for the user of the display, 532 * The display d (if specified) switches to that window. 533 */ 534int 535MakeWindow(newwin) 536struct NewWindow *newwin; 537{ 538 register struct win **pp, *p; 539 register int n, i; 540 int f = -1; 541 struct NewWindow nwin; 542 int type, startat; 543 char *TtyName; 544#ifdef MULTIUSER 545 extern struct acluser *users; 546#endif 547 548 debug1("NewWindow: StartAt %d\n", newwin->StartAt); 549 debug1("NewWindow: aka %s\n", newwin->aka?newwin->aka:"NULL"); 550 debug1("NewWindow: dir %s\n", newwin->dir?newwin->dir:"NULL"); 551 debug1("NewWindow: term %s\n", newwin->term?newwin->term:"NULL"); 552 553 nwin_compose(&nwin_default, newwin, &nwin); 554 debug1("NWin: aka %s\n", nwin.aka ? nwin.aka : "NULL"); 555 debug1("NWin: wlock %d\n", nwin.wlock); 556 debug1("NWin: Lflag %d\n", nwin.Lflag); 557 558 startat = nwin.StartAt < maxwin ? nwin.StartAt : 0; 559 pp = wtab + startat; 560 561 do 562 { 563 if (*pp == 0) 564 break; 565 if (++pp == wtab + maxwin) 566 pp = wtab; 567 } 568 while (pp != wtab + startat); 569 if (*pp) 570 { 571 Msg(0, "No more windows."); 572 return -1; 573 } 574 575#if defined(USRLIMIT) && defined(UTMPOK) 576 /* 577 * Count current number of users, if logging windows in. 578 */ 579 if (nwin.lflag && CountUsers() >= USRLIMIT) 580 { 581 Msg(0, "User limit reached. Window will not be logged in."); 582 nwin.lflag = 0; 583 } 584#endif 585 n = pp - wtab; 586 debug1("Makewin creating %d\n", n); 587 588 if ((f = OpenDevice(nwin.args, nwin.lflag, &type, &TtyName)) < 0) 589 return -1; 590 591 if ((p = (struct win *)malloc(sizeof(struct win))) == 0) 592 { 593 close(f); 594 Msg(0, strnomem); 595 return -1; 596 } 597 bzero((char *)p, (int)sizeof(struct win)); 598 599#ifdef UTMPOK 600 if (type != W_TYPE_PTY) 601 nwin.lflag = 0; 602#endif 603 604 p->w_type = type; 605 606 /* save the command line so that zombies can be resurrected */ 607 for (i = 0; nwin.args[i] && i < MAXARGS - 1; i++) 608 p->w_cmdargs[i] = SaveStr(nwin.args[i]); 609 p->w_cmdargs[i] = 0; 610 if (nwin.dir) 611 p->w_dir = SaveStr(nwin.dir); 612 if (nwin.term) 613 p->w_term = SaveStr(nwin.term); 614 615 p->w_number = n; 616#ifdef MULTIUSER 617 /* 618 * This is dangerous: without a display we use creators umask 619 * This is intended to be usefull for detached startup. 620 * But is still better than default bits with a NULL user. 621 */ 622 if (NewWindowAcl(p, display ? D_user : users)) 623 { 624 free((char *)p); 625 close(f); 626 Msg(0, strnomem); 627 return -1; 628 } 629#endif 630 p->w_layer.l_next = 0; 631 p->w_layer.l_bottom = &p->w_layer; 632 p->w_layer.l_layfn = &WinLf; 633 p->w_layer.l_data = (char *)p; 634 p->w_savelayer = &p->w_layer; 635 p->w_pdisplay = 0; 636 p->w_lastdisp = 0; 637 638#ifdef MULTIUSER 639 if (display && !AclCheckPermWin(D_user, ACL_WRITE, p)) 640 p->w_wlockuser = D_user; 641 p->w_wlock = nwin.wlock; 642#endif 643 p->w_ptyfd = f; 644 p->w_aflag = nwin.aflag; 645 p->w_flow = nwin.flowflag | ((nwin.flowflag & FLOW_AUTOFLAG) ? (FLOW_AUTO|FLOW_NOW) : FLOW_AUTO); 646 if (!nwin.aka) 647 nwin.aka = Filename(nwin.args[0]); 648 strncpy(p->w_akabuf, nwin.aka, sizeof(p->w_akabuf) - 1); 649 if ((nwin.aka = rindex(p->w_akabuf, '|')) != NULL) 650 { 651 p->w_autoaka = 0; 652 *nwin.aka++ = 0; 653 p->w_title = nwin.aka; 654 p->w_akachange = nwin.aka + strlen(nwin.aka); 655 } 656 else 657 p->w_title = p->w_akachange = p->w_akabuf; 658 if (nwin.hstatus) 659 p->w_hstatus = SaveStr(nwin.hstatus); 660 p->w_monitor = nwin.monitor; 661#ifdef MULTIUSER 662 if (p->w_monitor == MON_ON) 663 { 664 /* always tell all users */ 665 for (i = 0; i < maxusercount; i++) 666 ACLBYTE(p->w_mon_notify, i) |= ACLBIT(i); 667 } 668#endif 669 /* 670 * defsilence by Lloyd Zusman (zusman_lloyd@jpmorgan.com) 671 */ 672 p->w_silence = nwin.silence; 673 p->w_silencewait = SilenceWait; 674#ifdef MULTIUSER 675 if (p->w_silence == SILENCE_ON) 676 { 677 /* always tell all users */ 678 for (i = 0; i < maxusercount; i++) 679 ACLBYTE(p->w_lio_notify, i) |= ACLBIT(i); 680 } 681#endif 682#ifdef COPY_PASTE 683 p->w_slowpaste = nwin.slow; 684#else 685 nwin.histheight = 0; 686#endif 687 688 p->w_norefresh = 0; 689 strncpy(p->w_tty, TtyName, MAXSTR - 1); 690 691#if 0 692 /* XXX Fixme display resize */ 693 if (ChangeWindowSize(p, display ? D_defwidth : 80, 694 display ? D_defheight : 24, 695 nwin.histheight)) 696 { 697 FreeWindow(p); 698 return -1; 699 } 700#else 701 if (ChangeWindowSize(p, display ? D_forecv->c_xe - D_forecv->c_xs + 1: 80, 702 display ? D_forecv->c_ye - D_forecv->c_ys + 1 : 24, 703 nwin.histheight)) 704 { 705 FreeWindow(p); 706 return -1; 707 } 708#endif 709 710 p->w_encoding = nwin.encoding; 711 ResetWindow(p); /* sets w_wrap, w_c1, w_gr, w_bce */ 712 713#ifdef FONT 714 if (nwin.charset) 715 SetCharsets(p, nwin.charset); 716#endif 717 718 if (VerboseCreate) 719 { 720 struct display *d = display; /* WriteString zaps display */ 721 722 WriteString(p, ":screen (", 9); 723 WriteString(p, p->w_title, strlen(p->w_title)); 724 WriteString(p, "):", 2); 725 for (f = 0; p->w_cmdargs[f]; f++) 726 { 727 WriteString(p, " ", 1); 728 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f])); 729 } 730 WriteString(p, "\r\n", 2); 731 display = d; 732 } 733 734 p->w_pid = 0; 735#ifdef PSEUDOS 736 p->w_pwin = 0; 737#endif 738 739#ifdef BUILTIN_TELNET 740 if (type == W_TYPE_TELNET) 741 { 742 if (TelConnect(p)) 743 { 744 FreeWindow(p); 745 return -1; 746 } 747 } 748 else 749#endif 750 if (type == W_TYPE_PTY) 751 { 752 p->w_pid = ForkWindow(p, nwin.args, TtyName); 753 if (p->w_pid < 0) 754 { 755 FreeWindow(p); 756 return -1; 757 } 758 } 759 760 /* 761 * Place the new window at the head of the most-recently-used list. 762 */ 763 if (display && D_fore) 764 D_other = D_fore; 765 *pp = p; 766 p->w_next = windows; 767 windows = p; 768 p->w_lflag = nwin.lflag; 769#ifdef UTMPOK 770 p->w_slot = (slot_t)-1; 771# ifdef LOGOUTOK 772 debug1("MakeWindow will %slog in.\n", nwin.lflag?"":"not "); 773 if (nwin.lflag & 1) 774# else /* LOGOUTOK */ 775 debug1("MakeWindow will log in, LOGOUTOK undefined in config.h%s.\n", 776 nwin.lflag?"":" (although lflag=0)"); 777# endif /* LOGOUTOK */ 778 { 779 p->w_slot = (slot_t)0; 780 if (display || (p->w_lflag & 2)) 781 SetUtmp(p); 782 } 783# ifdef CAREFULUTMP 784 CarefulUtmp(); /* If all 've been zombies, we've had no slot */ 785# endif 786#endif /* UTMPOK */ 787 788 if (nwin.Lflag) 789 { 790 char buf[1024]; 791 DoStartLog(p, buf, sizeof(buf)); 792 } 793 794 p->w_readev.fd = p->w_writeev.fd = p->w_ptyfd; 795 p->w_readev.type = EV_READ; 796 p->w_writeev.type = EV_WRITE; 797 p->w_readev.data = p->w_writeev.data = (char *)p; 798 p->w_readev.handler = win_readev_fn; 799 p->w_writeev.handler = win_writeev_fn; 800 p->w_writeev.condpos = &p->w_inlen; 801 evenq(&p->w_readev); 802 evenq(&p->w_writeev); 803#ifdef COPY_PASTE 804 p->w_paster.pa_slowev.type = EV_TIMEOUT; 805 p->w_paster.pa_slowev.data = (char *)&p->w_paster; 806 p->w_paster.pa_slowev.handler = paste_slowev_fn; 807#endif 808 p->w_silenceev.type = EV_TIMEOUT; 809 p->w_silenceev.data = (char *)p; 810 p->w_silenceev.handler = win_silenceev_fn; 811 if (p->w_silence > 0) 812 { 813 debug("New window has silence enabled.\n"); 814 SetTimeout(&p->w_silenceev, p->w_silencewait * 1000); 815 evenq(&p->w_silenceev); 816 } 817 818 SetForeWindow(p); 819 Activate(p->w_norefresh); 820 WindowChanged((struct win*)0, 'w'); 821 WindowChanged((struct win*)0, 'W'); 822 WindowChanged((struct win*)0, 0); 823 return n; 824} 825 826/* 827 * Resurrect a window from Zombie state. 828 * The command vector is therefore stored in the window structure. 829 * Note: The terminaltype defaults to screenterm again, the current 830 * working directory is lost. 831 */ 832int 833RemakeWindow(p) 834struct win *p; 835{ 836 char *TtyName; 837 int lflag, f; 838 839 lflag = nwin_default.lflag; 840 if ((f = OpenDevice(p->w_cmdargs, lflag, &p->w_type, &TtyName)) < 0) 841 return -1; 842 843 strncpy(p->w_tty, *TtyName ? TtyName : p->w_title, MAXSTR - 1); 844 p->w_ptyfd = f; 845 p->w_readev.fd = f; 846 p->w_writeev.fd = f; 847 evenq(&p->w_readev); 848 evenq(&p->w_writeev); 849 850 if (VerboseCreate) 851 { 852 struct display *d = display; /* WriteString zaps display */ 853 854 WriteString(p, ":screen (", 9); 855 WriteString(p, p->w_title, strlen(p->w_title)); 856 WriteString(p, "):", 2); 857 for (f = 0; p->w_cmdargs[f]; f++) 858 { 859 WriteString(p, " ", 1); 860 WriteString(p, p->w_cmdargs[f], strlen(p->w_cmdargs[f])); 861 } 862 WriteString(p, "\r\n", 2); 863 display = d; 864 } 865 866 p->w_pid = 0; 867#ifdef BUILTIN_TELNET 868 if (p->w_type == W_TYPE_TELNET) 869 { 870 if (TelConnect(p)) 871 return -1; 872 } 873 else 874#endif 875 if (p->w_type == W_TYPE_PTY) 876 { 877 p->w_pid = ForkWindow(p, p->w_cmdargs, TtyName); 878 if (p->w_pid < 0) 879 return -1; 880 } 881 882#ifdef UTMPOK 883 if (p->w_slot == (slot_t)0 && (display || (p->w_lflag & 2))) 884 SetUtmp(p); 885# ifdef CAREFULUTMP 886 CarefulUtmp(); /* If all 've been zombies, we've had no slot */ 887# endif 888#endif 889 WindowChanged(p, 'f'); 890 return p->w_number; 891} 892 893void 894CloseDevice(wp) 895struct win *wp; 896{ 897 if (wp->w_ptyfd < 0) 898 return; 899 if (wp->w_type == W_TYPE_PTY) 900 { 901 /* pty 4 SALE */ 902 (void)chmod(wp->w_tty, 0666); 903 (void)chown(wp->w_tty, 0, 0); 904 } 905 close(wp->w_ptyfd); 906 wp->w_ptyfd = -1; 907 wp->w_tty[0] = 0; 908 evdeq(&wp->w_readev); 909 evdeq(&wp->w_writeev); 910#ifdef BUILTIN_TELNET 911 evdeq(&wp->w_telconnev); 912#endif 913 wp->w_readev.fd = wp->w_writeev.fd = -1; 914} 915 916void 917FreeWindow(wp) 918struct win *wp; 919{ 920 struct display *d; 921 int i; 922 struct canvas *cv, *ncv; 923 struct layer *l; 924 925 debug1("FreeWindow %d\n", wp ? wp->w_number: -1); 926#ifdef PSEUDOS 927 if (wp->w_pwin) 928 FreePseudowin(wp); 929#endif 930#ifdef UTMPOK 931 RemoveUtmp(wp); 932#endif 933 CloseDevice(wp); 934 935 if (wp == console_window) 936 { 937 TtyGrabConsole(-1, -1, "free"); 938 console_window = 0; 939 } 940 if (wp->w_log != NULL) 941 logfclose(wp->w_log); 942 ChangeWindowSize(wp, 0, 0, 0); 943 944 if (wp->w_hstatus) 945 free(wp->w_hstatus); 946 for (i = 0; wp->w_cmdargs[i]; i++) 947 free(wp->w_cmdargs[i]); 948 if (wp->w_dir) 949 free(wp->w_dir); 950 if (wp->w_term) 951 free(wp->w_term); 952 for (d = displays; d; d = d->d_next) 953 { 954 if (d->d_other == wp) 955 d->d_other = d->d_fore && d->d_fore->w_next != wp ? d->d_fore->w_next : wp->w_next; 956 if (d->d_fore == wp) 957 d->d_fore = NULL; 958 for (cv = d->d_cvlist; cv; cv = cv->c_next) 959 { 960 for (l = cv->c_layer; l; l = l->l_next) 961 if (l->l_layfn == &WinLf) 962 break; 963 if (!l) 964 continue; 965 if ((struct win *)l->l_data != wp) 966 continue; 967 if (cv->c_layer == wp->w_savelayer) 968 wp->w_savelayer = 0; 969 KillLayerChain(cv->c_layer); 970 } 971 } 972 if (wp->w_savelayer) 973 KillLayerChain(wp->w_savelayer); 974 for (cv = wp->w_layer.l_cvlist; cv; cv = ncv) 975 { 976 ncv = cv->c_lnext; 977 cv->c_layer = &cv->c_blank; 978 cv->c_blank.l_cvlist = cv; 979 cv->c_lnext = 0; 980 cv->c_xoff = cv->c_xs; 981 cv->c_yoff = cv->c_ys; 982 RethinkViewportOffsets(cv); 983 } 984 wp->w_layer.l_cvlist = 0; 985 if (flayer == &wp->w_layer) 986 flayer = 0; 987 988#ifdef MULTIUSER 989 FreeWindowAcl(wp); 990#endif /* MULTIUSER */ 991 evdeq(&wp->w_readev); /* just in case */ 992 evdeq(&wp->w_writeev); /* just in case */ 993 evdeq(&wp->w_silenceev); 994#ifdef COPY_PASTE 995 FreePaster(&wp->w_paster); 996#endif 997 free((char *)wp); 998} 999 1000static int 1001OpenDevice(args, lflag, typep, namep) 1002char **args; 1003int lflag; 1004int *typep; 1005char **namep; 1006{ 1007 char *arg = args[0]; 1008 struct stat st; 1009 int f; 1010 1011 if (!arg) 1012 return -1; 1013#ifdef BUILTIN_TELNET 1014 if (strcmp(arg, "//telnet") == 0) 1015 { 1016 f = TelOpen(args + 1); 1017 lflag = 0; 1018 *typep = W_TYPE_TELNET; 1019 *namep = "telnet"; 1020 } 1021 else 1022#endif 1023 if ((stat(arg, &st)) == 0 && S_ISCHR(st.st_mode)) 1024 { 1025 if (access(arg, R_OK | W_OK) == -1) 1026 { 1027 Msg(errno, "Cannot access line '%s' for R/W", arg); 1028 return -1; 1029 } 1030 debug("OpenDevice: OpenTTY\n"); 1031 if ((f = OpenTTY(arg, args[1])) < 0) 1032 return -1; 1033 lflag = 0; 1034 *typep = W_TYPE_PLAIN; 1035 *namep = arg; 1036 } 1037 else 1038 { 1039 *typep = W_TYPE_PTY; 1040 f = OpenPTY(namep); 1041 if (f == -1) 1042 { 1043 Msg(0, "No more PTYs."); 1044 return -1; 1045 } 1046#ifdef TIOCPKT 1047 { 1048 int flag = 1; 1049 if (ioctl(f, TIOCPKT, (char *)&flag)) 1050 { 1051 Msg(errno, "TIOCPKT ioctl"); 1052 close(f); 1053 return -1; 1054 } 1055 } 1056#endif /* TIOCPKT */ 1057 } 1058 debug1("fcntl(%d, F_SETFL, FNBLOCK)\n", f); 1059 (void) fcntl(f, F_SETFL, FNBLOCK); 1060#ifdef linux 1061 /* 1062 * Tenebreux (zeus@ns.acadiacom.net) has Linux 1.3.70 where select 1063 * gets confused in the following condition: 1064 * Open a pty-master side, request a flush on it, then set packet 1065 * mode and call select(). Select will return a possible read, where 1066 * the one byte response to the flush can be found. Select will 1067 * thereafter return a possible read, which yields I/O error. 1068 * 1069 * If we request another flush *after* switching into packet mode, 1070 * this I/O error does not occur. We receive a single response byte 1071 * although we send two flush requests now. 1072 * 1073 * Maybe we should not flush at all. 1074 * 1075 * 10.5.96 jw. 1076 */ 1077 if (*typep == W_TYPE_PTY || *typep == W_TYPE_PLAIN) 1078 tcflush(f, TCIOFLUSH); 1079#endif 1080 1081 if (*typep != W_TYPE_PTY) 1082 return f; 1083 1084#ifndef PTYROFS 1085#ifdef PTYGROUP 1086 if (chown(*namep, real_uid, PTYGROUP) && !eff_uid) 1087#else 1088 if (chown(*namep, real_uid, real_gid) && !eff_uid) 1089#endif 1090 { 1091 Msg(errno, "chown tty"); 1092 close(f); 1093 return -1; 1094 } 1095#ifdef UTMPOK 1096 if (chmod(*namep, lflag ? TtyMode : (TtyMode & ~022)) && !eff_uid) 1097#else 1098 if (chmod(*namep, TtyMode) && !eff_uid) 1099#endif 1100 { 1101 Msg(errno, "chmod tty"); 1102 close(f); 1103 return -1; 1104 } 1105#endif 1106 return f; 1107} 1108 1109/* 1110 * Fields w_width, w_height, aflag, number (and w_tty) 1111 * are read from struct win *win. No fields written. 1112 * If pwin is nonzero, filedescriptors are distributed 1113 * between win->w_tty and open(ttyn) 1114 * 1115 */ 1116static int 1117ForkWindow(win, args, ttyn) 1118struct win *win; 1119char **args, *ttyn; 1120{ 1121 int pid; 1122 char tebuf[25]; 1123 char ebuf[10]; 1124 char shellbuf[7 + MAXPATHLEN]; 1125 char *proc; 1126#ifndef TIOCSWINSZ 1127 char libuf[20], cobuf[20]; 1128#endif 1129 int newfd; 1130 int w = win->w_width; 1131 int h = win->w_height; 1132#ifdef PSEUDOS 1133 int i, pat, wfdused; 1134 struct pseudowin *pwin = win->w_pwin; 1135#endif 1136 int slave = -1; 1137 1138#ifdef O_NOCTTY 1139 if (pty_preopen) 1140 { 1141 debug("pre-opening slave...\n"); 1142 if ((slave = open(ttyn, O_RDWR|O_NOCTTY)) == -1) 1143 { 1144 Msg(errno, "ttyn"); 1145 return -1; 1146 } 1147 } 1148#endif 1149 debug("forking...\n"); 1150 proc = *args; 1151 if (proc == 0) 1152 { 1153 args = ShellArgs; 1154 proc = *args; 1155 } 1156 fflush(stdout); 1157 fflush(stderr); 1158 switch (pid = fork()) 1159 { 1160 case -1: 1161 Msg(errno, "fork"); 1162 break; 1163 case 0: 1164 signal(SIGHUP, SIG_DFL); 1165 signal(SIGINT, SIG_DFL); 1166 signal(SIGQUIT, SIG_DFL); 1167 signal(SIGTERM, SIG_DFL); 1168#ifdef BSDJOBS 1169 signal(SIGTTIN, SIG_DFL); 1170 signal(SIGTTOU, SIG_DFL); 1171#endif 1172#ifdef SIGPIPE 1173 signal(SIGPIPE, SIG_DFL); 1174#endif 1175#ifdef SIGXFSZ 1176 signal(SIGXFSZ, SIG_DFL); 1177#endif 1178 1179 displays = 0; /* beware of Panic() */ 1180 if (setgid(real_gid) || setuid(real_uid)) 1181 Panic(errno, "Setuid/gid"); 1182 eff_uid = real_uid; 1183 eff_gid = real_gid; 1184#ifdef PSEUDOS 1185 if (!pwin) /* ignore directory if pseudo */ 1186#endif 1187 if (win->w_dir && *win->w_dir && chdir(win->w_dir)) 1188 Panic(errno, "Cannot chdir to %s", win->w_dir); 1189 1190 if (display) 1191 { 1192 brktty(D_userfd); 1193 freetty(); 1194 } 1195 else 1196 brktty(-1); 1197#ifdef DEBUG 1198 if (dfp && dfp != stderr) 1199 fclose(dfp); 1200#endif 1201 if (slave != -1) 1202 { 1203 close(0); 1204 dup(slave); 1205 close(slave); 1206 closeallfiles(win->w_ptyfd); 1207 slave = dup(0); 1208 } 1209 else 1210 closeallfiles(win->w_ptyfd); 1211#ifdef DEBUG 1212 if (dfp) /* do not produce child debug, when debug is "off" */ 1213 { 1214 char buf[256]; 1215 1216 sprintf(buf, "%s/screen.child", DEBUGDIR); 1217 if ((dfp = fopen(buf, "a")) == 0) 1218 dfp = stderr; 1219 else 1220 (void) chmod(buf, 0666); 1221 } 1222 debug1("=== ForkWindow: pid %d\n", (int)getpid()); 1223#endif 1224 /* Close the three /dev/null descriptors */ 1225 close(0); 1226 close(1); 1227 close(2); 1228 newfd = -1; 1229 /* 1230 * distribute filedescriptors between the ttys 1231 */ 1232#ifdef PSEUDOS 1233 pat = pwin ? pwin->p_fdpat : 1234 ((F_PFRONT<<(F_PSHIFT*2)) | (F_PFRONT<<F_PSHIFT) | F_PFRONT); 1235 debug1("Using window pattern 0x%x\n", pat); 1236 wfdused = 0; 1237 for(i = 0; i < 3; i++) 1238 { 1239 if (pat & F_PFRONT << F_PSHIFT * i) 1240 { 1241 if (newfd < 0) 1242 { 1243# ifdef O_NOCTTY 1244 if (separate_sids) 1245 newfd = open(ttyn, O_RDWR); 1246 else 1247 newfd = open(ttyn, O_RDWR|O_NOCTTY); 1248# else 1249 newfd = open(ttyn, O_RDWR); 1250# endif 1251 if (newfd < 0) 1252 Panic(errno, "Cannot open %s", ttyn); 1253 } 1254 else 1255 dup(newfd); 1256 } 1257 else 1258 { 1259 dup(win->w_ptyfd); 1260 wfdused = 1; 1261 } 1262 } 1263 if (wfdused) 1264 { 1265 /* 1266 * the pseudo window process should not be surprised with a 1267 * nonblocking filedescriptor. Poor Backend! 1268 */ 1269 debug1("Clearing NBLOCK on window-fd(%d)\n", win->w_ptyfd); 1270 if (fcntl(win->w_ptyfd, F_SETFL, 0)) 1271 Msg(errno, "Warning: clear NBLOCK fcntl failed"); 1272 } 1273#else /* PSEUDOS */ 1274# ifdef O_NOCTTY 1275 if (separate_sids) 1276 newfd = open(ttyn, O_RDWR); 1277 else 1278 newfd = open(ttyn, O_RDWR|O_NOCTTY); 1279# else 1280 newfd = open(ttyn, O_RDWR); 1281# endif 1282 if (newfd != 0) 1283 Panic(errno, "Cannot open %s", ttyn); 1284 dup(0); 1285 dup(0); 1286#endif /* PSEUDOS */ 1287 close(win->w_ptyfd); 1288 if (slave != -1) 1289 close(slave); 1290 if (newfd >= 0) 1291 { 1292 struct mode fakemode, *modep; 1293 InitPTY(newfd); 1294 if (fgtty(newfd)) 1295 Msg(errno, "fgtty"); 1296 if (display) 1297 { 1298 debug("ForkWindow: using display tty mode for new child.\n"); 1299 modep = &D_OldMode; 1300 } 1301 else 1302 { 1303 debug("No display - creating tty setting\n"); 1304 modep = &fakemode; 1305 InitTTY(modep, 0); 1306#ifdef DEBUG 1307 DebugTTY(modep); 1308#endif 1309 } 1310 /* We only want echo if the users input goes to the pseudo 1311 * and the pseudo's stdout is not send to the window. 1312 */ 1313#ifdef PSEUDOS 1314 if (pwin && (!(pat & F_UWP) || (pat & F_PBACK << F_PSHIFT))) 1315 { 1316 debug1("clearing echo on pseudywin fd (pat %x)\n", pat); 1317# if defined(POSIX) || defined(TERMIO) 1318 modep->tio.c_lflag &= ~ECHO; 1319 modep->tio.c_iflag &= ~ICRNL; 1320# else 1321 modep->m_ttyb.sg_flags &= ~ECHO; 1322# endif 1323 } 1324#endif 1325 SetTTY(newfd, modep); 1326#ifdef TIOCSWINSZ 1327 glwz.ws_col = w; 1328 glwz.ws_row = h; 1329 (void) ioctl(newfd, TIOCSWINSZ, (char *)&glwz); 1330#endif 1331 /* Always turn off nonblocking mode */ 1332 (void)fcntl(newfd, F_SETFL, 0); 1333 } 1334#ifndef TIOCSWINSZ 1335 sprintf(libuf, "LINES=%d", h); 1336 sprintf(cobuf, "COLUMNS=%d", w); 1337 NewEnv[5] = libuf; 1338 NewEnv[6] = cobuf; 1339#endif 1340#ifdef MAPKEYS 1341 NewEnv[2] = MakeTermcap(display == 0 || win->w_aflag); 1342#else 1343 if (win->w_aflag) 1344 NewEnv[2] = MakeTermcap(1); 1345 else 1346 NewEnv[2] = Termcap; 1347#endif 1348 strcpy(shellbuf, "SHELL="); 1349 strncpy(shellbuf + 6, ShellProg + (*ShellProg == '-'), sizeof(shellbuf) - 7); 1350 shellbuf[sizeof(shellbuf) - 1] = 0; 1351 NewEnv[4] = shellbuf; 1352 debug1("ForkWindow: NewEnv[4] = '%s'\n", shellbuf); 1353 if (win->w_term && *win->w_term && strcmp(screenterm, win->w_term) && 1354 (strlen(win->w_term) < 20)) 1355 { 1356 char *s1, *s2, tl; 1357 1358 sprintf(tebuf, "TERM=%s", win->w_term); 1359 debug2("Makewindow %d with %s\n", win->w_number, tebuf); 1360 tl = strlen(win->w_term); 1361 NewEnv[1] = tebuf; 1362 if ((s1 = index(NewEnv[2], '|'))) 1363 { 1364 if ((s2 = index(++s1, '|'))) 1365 { 1366 if (strlen(NewEnv[2]) - (s2 - s1) + tl < 1024) 1367 { 1368 bcopy(s2, s1 + tl, strlen(s2) + 1); 1369 bcopy(win->w_term, s1, tl); 1370 } 1371 } 1372 } 1373 } 1374 sprintf(ebuf, "WINDOW=%d", win->w_number); 1375 NewEnv[3] = ebuf; 1376 1377 if (*proc == '-') 1378 proc++; 1379 if (!*proc) 1380 proc = DefaultShell; 1381 debug1("calling execvpe %s\n", proc); 1382 execvpe(proc, args, NewEnv); 1383 debug1("exec error: %d\n", errno); 1384 Panic(errno, "Cannot exec '%s'", proc); 1385 default: 1386 break; 1387 } 1388 if (slave != -1) 1389 close(slave); 1390 return pid; 1391} 1392 1393#ifdef __APPLE__ 1394#ifdef RUN_LOGIN 1395/* 1396 * All of the logic to maintain utmpx is now built into /usr/bin/login, so 1397 * all we need to do is call it, and pass the shell command to it. 1398 */ 1399extern char *LoginName; 1400 1401static int 1402run_login(const char *path, char *const argv[], char *const envp[]) 1403{ 1404 const char *shargs[MAXARGS + 1 + 3]; 1405 const char **fp, **tp; 1406 1407 if (access(path, X_OK) < 0) 1408 return -1; 1409 shargs[0] = "login"; 1410 shargs[1] = (*argv[0] == '-') ? "-pfq" : "-pflq"; 1411 shargs[2] = LoginName; 1412 shargs[3] = path; 1413 fp = (const char **)argv + 1; 1414 tp = shargs + 4; 1415 /* argv has already been check for length */ 1416 while ((*tp++ = *fp++) != NULL) {} 1417 /* shouldn't return unless there was an error */ 1418 return (execve("/usr/bin/login", (char *const*)shargs, envp)); 1419} 1420 1421/* replace the following occurrences of execve() with run_login() */ 1422#define execve run_login 1423 1424#endif /* RUN_LOGIN */ 1425#endif /* __APPLE__ */ 1426 1427void 1428execvpe(prog, args, env) 1429char *prog, **args, **env; 1430{ 1431 register char *path = NULL, *p; 1432 char buf[1024]; 1433 char *shargs[MAXARGS + 1]; 1434 register int i, eaccess = 0; 1435 1436 if (rindex(prog, '/')) 1437 path = ""; 1438 if (!path && !(path = getenv("PATH"))) 1439 path = DefaultPath; 1440 do 1441 { 1442 for (p = buf; *path && *path != ':'; path++) 1443 if (p - buf < (int)sizeof(buf) - 2) 1444 *p++ = *path; 1445 if (p > buf) 1446 *p++ = '/'; 1447 if (p - buf + strlen(prog) >= sizeof(buf) - 1) 1448 continue; 1449 strcpy(p, prog); 1450 execve(buf, args, env); 1451 switch (errno) 1452 { 1453 case ENOEXEC: 1454 shargs[0] = DefaultShell; 1455 shargs[1] = buf; 1456 for (i = 1; (shargs[i + 1] = args[i]) != NULL; ++i) 1457 ; 1458 execve(DefaultShell, shargs, env); 1459 return; 1460 case EACCES: 1461 eaccess = 1; 1462 break; 1463 case ENOMEM: 1464 case E2BIG: 1465 case ETXTBSY: 1466 return; 1467 } 1468 } while (*path++); 1469 if (eaccess) 1470 errno = EACCES; 1471} 1472 1473#ifdef PSEUDOS 1474 1475int 1476winexec(av) 1477char **av; 1478{ 1479 char **pp; 1480 char *p, *s, *t; 1481 int i, r = 0, l = 0; 1482 struct win *w; 1483 extern struct display *display; 1484 extern struct win *windows; 1485 struct pseudowin *pwin; 1486 int type; 1487 1488 if ((w = display ? fore : windows) == NULL) 1489 return -1; 1490 if (!*av || w->w_pwin) 1491 { 1492 Msg(0, "Filter running: %s", w->w_pwin ? w->w_pwin->p_cmd : "(none)"); 1493 return -1; 1494 } 1495 if (w->w_ptyfd < 0) 1496 { 1497 Msg(0, "You feel dead inside."); 1498 return -1; 1499 } 1500 if (!(pwin = (struct pseudowin *)malloc(sizeof(struct pseudowin)))) 1501 { 1502 Msg(0, strnomem); 1503 return -1; 1504 } 1505 bzero((char *)pwin, (int)sizeof(*pwin)); 1506 1507 /* allow ^a:!!./ttytest as a short form for ^a:exec !.. ./ttytest */ 1508 for (s = *av; *s == ' '; s++) 1509 ; 1510 for (p = s; *p == ':' || *p == '.' || *p == '!'; p++) 1511 ; 1512 if (*p != '|') 1513 while (*p && p > s && p[-1] == '.') 1514 p--; 1515 if (*p == '|') 1516 { 1517 l = F_UWP; 1518 p++; 1519 } 1520 if (*p) 1521 av[0] = p; 1522 else 1523 av++; 1524 1525 t = pwin->p_cmd; 1526 for (i = 0; i < 3; i++) 1527 { 1528 *t = (s < p) ? *s++ : '.'; 1529 switch (*t++) 1530 { 1531 case '.': 1532 case '|': 1533 l |= F_PFRONT << (i * F_PSHIFT); 1534 break; 1535 case '!': 1536 l |= F_PBACK << (i * F_PSHIFT); 1537 break; 1538 case ':': 1539 l |= F_PBOTH << (i * F_PSHIFT); 1540 break; 1541 } 1542 } 1543 1544 if (l & F_UWP) 1545 { 1546 *t++ = '|'; 1547 if ((l & F_PMASK) == F_PFRONT) 1548 { 1549 *pwin->p_cmd = '!'; 1550 l ^= F_PFRONT | F_PBACK; 1551 } 1552 } 1553 if (!(l & F_PBACK)) 1554 l |= F_UWP; 1555 *t++ = ' '; 1556 pwin->p_fdpat = l; 1557 debug1("winexec: '%#x'\n", pwin->p_fdpat); 1558 1559 l = MAXSTR - 4; 1560 for (pp = av; *pp; pp++) 1561 { 1562 p = *pp; 1563 while (*p && l-- > 0) 1564 *t++ = *p++; 1565 if (l <= 0) 1566 break; 1567 *t++ = ' '; 1568 } 1569 *--t = '\0'; 1570 debug1("%s\n", pwin->p_cmd); 1571 1572 if ((pwin->p_ptyfd = OpenDevice(av, 0, &type, &t)) < 0) 1573 { 1574 free((char *)pwin); 1575 return -1; 1576 } 1577 strncpy(pwin->p_tty, t, MAXSTR - 1); 1578 w->w_pwin = pwin; 1579 if (type != W_TYPE_PTY) 1580 { 1581 FreePseudowin(w); 1582 Msg(0, "Cannot only use commands as pseudo win."); 1583 return -1; 1584 } 1585 if (!(pwin->p_fdpat & F_PFRONT)) 1586 evdeq(&w->w_readev); 1587#ifdef TIOCPKT 1588 { 1589 int flag = 0; 1590 1591 if (ioctl(pwin->p_ptyfd, TIOCPKT, (char *)&flag)) 1592 { 1593 Msg(errno, "TIOCPKT pwin ioctl"); 1594 FreePseudowin(w); 1595 return -1; 1596 } 1597 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT)) 1598 { 1599 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag)) 1600 { 1601 Msg(errno, "TIOCPKT win ioctl"); 1602 FreePseudowin(w); 1603 return -1; 1604 } 1605 } 1606 } 1607#endif /* TIOCPKT */ 1608 1609 pwin->p_readev.fd = pwin->p_writeev.fd = pwin->p_ptyfd; 1610 pwin->p_readev.type = EV_READ; 1611 pwin->p_writeev.type = EV_WRITE; 1612 pwin->p_readev.data = pwin->p_writeev.data = (char *)w; 1613 pwin->p_readev.handler = pseu_readev_fn; 1614 pwin->p_writeev.handler = pseu_writeev_fn; 1615 pwin->p_writeev.condpos = &pwin->p_inlen; 1616 if (pwin->p_fdpat & (F_PFRONT << F_PSHIFT * 2 | F_PFRONT << F_PSHIFT)) 1617 evenq(&pwin->p_readev); 1618 evenq(&pwin->p_writeev); 1619 r = pwin->p_pid = ForkWindow(w, av, t); 1620 if (r < 0) 1621 FreePseudowin(w); 1622 return r; 1623} 1624 1625void 1626FreePseudowin(w) 1627struct win *w; 1628{ 1629 struct pseudowin *pwin = w->w_pwin; 1630 1631 ASSERT(pwin); 1632 if (fcntl(w->w_ptyfd, F_SETFL, FNBLOCK)) 1633 Msg(errno, "Warning: FreePseudowin: NBLOCK fcntl failed"); 1634#ifdef TIOCPKT 1635 if (w->w_type == W_TYPE_PTY && !(pwin->p_fdpat & F_PFRONT)) 1636 { 1637 int flag = 1; 1638 if (ioctl(w->w_ptyfd, TIOCPKT, (char *)&flag)) 1639 Msg(errno, "Warning: FreePseudowin: TIOCPKT win ioctl"); 1640 } 1641#endif 1642 /* should be able to use CloseDevice() here */ 1643 (void)chmod(pwin->p_tty, 0666); 1644 (void)chown(pwin->p_tty, 0, 0); 1645 if (pwin->p_ptyfd >= 0) 1646 close(pwin->p_ptyfd); 1647 evdeq(&pwin->p_readev); 1648 evdeq(&pwin->p_writeev); 1649 if (w->w_readev.condneg == &pwin->p_inlen) 1650 w->w_readev.condpos = w->w_readev.condneg = 0; 1651 evenq(&w->w_readev); 1652 free((char *)pwin); 1653 w->w_pwin = NULL; 1654} 1655 1656#endif /* PSEUDOS */ 1657 1658 1659#ifdef MULTIUSER 1660/* 1661 * returns 0, if the lock really has been released 1662 */ 1663int 1664ReleaseAutoWritelock(dis, w) 1665struct display *dis; 1666struct win *w; 1667{ 1668 debug2("ReleaseAutoWritelock: user %s, window %d\n", 1669 dis->d_user->u_name, w->w_number); 1670 1671 /* release auto writelock when user has no other display here */ 1672 if (w->w_wlock == WLOCK_AUTO && w->w_wlockuser == dis->d_user) 1673 { 1674 struct display *d; 1675 1676 for (d = displays; d; d = d->d_next) 1677 if (( d != dis) && (d->d_fore == w) && (d->d_user == dis->d_user)) 1678 break; 1679 debug3("%s %s autolock on win %d\n", 1680 dis->d_user->u_name, d ? "keeps" : "releases", w->w_number); 1681 if (!d) 1682 { 1683 w->w_wlockuser = NULL; 1684 return 0; 1685 } 1686 } 1687 return 1; 1688} 1689 1690/* 1691 * returns 0, if the lock really could be obtained 1692 */ 1693int 1694ObtainAutoWritelock(d, w) 1695struct display *d; 1696struct win *w; 1697{ 1698 if ((w->w_wlock == WLOCK_AUTO) && 1699 !AclCheckPermWin(d->d_user, ACL_WRITE, w) && 1700 !w->w_wlockuser) 1701 { 1702 debug2("%s obtained auto writelock for exported window %d\n", 1703 d->d_user->u_name, w->w_number); 1704 w->w_wlockuser = d->d_user; 1705 return 0; 1706 } 1707 return 1; 1708} 1709 1710#endif /* MULTIUSER */ 1711 1712 1713 1714/********************************************************************/ 1715 1716#ifdef COPY_PASTE 1717static void 1718paste_slowev_fn(ev, data) 1719struct event *ev; 1720char *data; 1721{ 1722 struct paster *pa = (struct paster *)data; 1723 struct win *p; 1724 1725 int l = 1; 1726 flayer = pa->pa_pastelayer; 1727 if (!flayer) 1728 pa->pa_pastelen = 0; 1729 if (!pa->pa_pastelen) 1730 return; 1731 p = Layer2Window(flayer); 1732 DoProcess(p, &pa->pa_pasteptr, &l, pa); 1733 pa->pa_pastelen -= 1 - l; 1734 if (pa->pa_pastelen > 0) 1735 { 1736 SetTimeout(&pa->pa_slowev, p->w_slowpaste); 1737 evenq(&pa->pa_slowev); 1738 } 1739} 1740#endif 1741 1742 1743static int 1744muchpending(p, ev) 1745struct win *p; 1746struct event *ev; 1747{ 1748 struct canvas *cv; 1749 for (cv = p->w_layer.l_cvlist; cv; cv = cv->c_lnext) 1750 { 1751 display = cv->c_display; 1752 if (D_status == STATUS_ON_WIN && !D_status_bell) 1753 { 1754 /* wait 'til status is gone */ 1755 debug("BLOCKING because of status\n"); 1756 ev->condpos = &const_one; 1757 ev->condneg = &D_status; 1758 return 1; 1759 } 1760 debug2("muchpending %s %d: ", D_usertty, D_blocked); 1761 debug3("%d %d %d\n", D_obufp - D_obuf, D_obufmax, D_blocked_fuzz); 1762 if (D_blocked) 1763 continue; 1764 if (D_obufp - D_obuf > D_obufmax + D_blocked_fuzz) 1765 { 1766 if (D_nonblock == 0) 1767 { 1768 debug1("obuf is full, stopping output to display %s\n", D_usertty); 1769 D_blocked = 1; 1770 continue; 1771 } 1772 debug("BLOCKING because of full obuf\n"); 1773 ev->condpos = &D_obuffree; 1774 ev->condneg = &D_obuflenmax; 1775 if (D_nonblock > 0 && !D_blockedev.queued) 1776 { 1777 debug1("created timeout of %g secs\n", D_nonblock/1000.); 1778 SetTimeout(&D_blockedev, D_nonblock); 1779 evenq(&D_blockedev); 1780 } 1781 return 1; 1782 } 1783 } 1784 return 0; 1785} 1786 1787static void 1788win_readev_fn(ev, data) 1789struct event *ev; 1790char *data; 1791{ 1792 struct win *p = (struct win *)data; 1793 char buf[IOSIZE], *bp; 1794 int size, len; 1795#ifdef PSEUDOS 1796 int wtop; 1797#endif 1798 1799 bp = buf; 1800 size = IOSIZE; 1801 1802#ifdef PSEUDOS 1803 wtop = p->w_pwin && W_WTOP(p); 1804 if (wtop) 1805 { 1806 ASSERT(sizeof(p->w_pwin->p_inbuf) == IOSIZE); 1807 size = IOSIZE - p->w_pwin->p_inlen; 1808 if (size <= 0) 1809 { 1810 ev->condpos = &const_IOSIZE; 1811 ev->condneg = &p->w_pwin->p_inlen; 1812 return; 1813 } 1814 } 1815#endif 1816 if (p->w_layer.l_cvlist && muchpending(p, ev)) 1817 return; 1818#ifdef ZMODEM 1819 if (!p->w_zdisplay) 1820#endif 1821 if (p->w_blocked) 1822 { 1823 ev->condpos = &const_one; 1824 ev->condneg = &p->w_blocked; 1825 return; 1826 } 1827 if (ev->condpos) 1828 ev->condpos = ev->condneg = 0; 1829 1830 if ((len = p->w_outlen)) 1831 { 1832 p->w_outlen = 0; 1833 WriteString(p, p->w_outbuf, len); 1834 return; 1835 } 1836 1837 debug1("going to read from window fd %d\n", ev->fd); 1838 if ((len = read(ev->fd, buf, size)) < 0) 1839 { 1840 if (errno == EINTR || errno == EAGAIN) 1841 return; 1842#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1843 if (errno == EWOULDBLOCK) 1844 return; 1845#endif 1846 debug2("Window %d: read error (errno %d) - killing window\n", p->w_number, errno); 1847 WindowDied(p); 1848 return; 1849 } 1850 if (len == 0) 1851 { 1852 debug1("Window %d: EOF - killing window\n", p->w_number); 1853 WindowDied(p); 1854 return; 1855 } 1856 debug1(" -> %d bytes\n", len); 1857#ifdef TIOCPKT 1858 if (p->w_type == W_TYPE_PTY) 1859 { 1860 if (buf[0]) 1861 { 1862 debug1("PAKET %x\n", buf[0]); 1863 if (buf[0] & TIOCPKT_NOSTOP) 1864 WNewAutoFlow(p, 0); 1865 if (buf[0] & TIOCPKT_DOSTOP) 1866 WNewAutoFlow(p, 1); 1867 } 1868 bp++; 1869 len--; 1870 } 1871#endif 1872#ifdef BUILTIN_TELNET 1873 if (p->w_type == W_TYPE_TELNET) 1874 len = TelIn(p, bp, len, buf + sizeof(buf) - (bp + len)); 1875#endif 1876 if (len == 0) 1877 return; 1878#ifdef ZMODEM 1879 if (zmodem_mode && zmodem_parse(p, bp, len)) 1880 return; 1881#endif 1882#ifdef PSEUDOS 1883 if (wtop) 1884 { 1885 debug("sending input to pwin\n"); 1886 bcopy(bp, p->w_pwin->p_inbuf + p->w_pwin->p_inlen, len); 1887 p->w_pwin->p_inlen += len; 1888 } 1889#endif 1890 WriteString(p, bp, len); 1891 return; 1892} 1893 1894 1895static void 1896win_writeev_fn(ev, data) 1897struct event *ev; 1898char *data; 1899{ 1900 struct win *p = (struct win *)data; 1901 int len; 1902 if (p->w_inlen) 1903 { 1904 debug2("writing %d bytes to win %d\n", p->w_inlen, p->w_number); 1905 if ((len = write(ev->fd, p->w_inbuf, p->w_inlen)) <= 0) 1906 len = p->w_inlen; /* dead window */ 1907 if ((p->w_inlen -= len)) 1908 bcopy(p->w_inbuf + len, p->w_inbuf, p->w_inlen); 1909 } 1910#ifdef COPY_PASTE 1911 if (p->w_paster.pa_pastelen && !p->w_slowpaste) 1912 { 1913 struct paster *pa = &p->w_paster; 1914 flayer = pa->pa_pastelayer; 1915 if (flayer) 1916 DoProcess(p, &pa->pa_pasteptr, &pa->pa_pastelen, pa); 1917 } 1918#endif 1919 return; 1920} 1921 1922 1923 1924#ifdef PSEUDOS 1925 1926static void 1927pseu_readev_fn(ev, data) 1928struct event *ev; 1929char *data; 1930{ 1931 struct win *p = (struct win *)data; 1932 char buf[IOSIZE]; 1933 int size, ptow, len; 1934 1935 size = IOSIZE; 1936 1937 ptow = W_PTOW(p); 1938 if (ptow) 1939 { 1940 ASSERT(sizeof(p->w_inbuf) == IOSIZE); 1941 size = IOSIZE - p->w_inlen; 1942 if (size <= 0) 1943 { 1944 ev->condpos = &const_IOSIZE; 1945 ev->condneg = &p->w_inlen; 1946 return; 1947 } 1948 } 1949 if (p->w_layer.l_cvlist && muchpending(p, ev)) 1950 return; 1951 if (p->w_blocked) 1952 { 1953 ev->condpos = &const_one; 1954 ev->condneg = &p->w_blocked; 1955 return; 1956 } 1957 if (ev->condpos) 1958 ev->condpos = ev->condneg = 0; 1959 1960 if ((len = p->w_outlen)) 1961 { 1962 p->w_outlen = 0; 1963 WriteString(p, p->w_outbuf, len); 1964 return; 1965 } 1966 1967 if ((len = read(ev->fd, buf, size)) <= 0) 1968 { 1969 if (errno == EINTR || errno == EAGAIN) 1970 return; 1971#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) 1972 if (errno == EWOULDBLOCK) 1973 return; 1974#endif 1975 debug2("Window %d: pseudowin read error (errno %d) -- removing pseudowin\n", p->w_number, len ? errno : 0); 1976 FreePseudowin(p); 1977 return; 1978 } 1979 /* no packet mode on pseudos! */ 1980 if (ptow) 1981 { 1982 bcopy(buf, p->w_inbuf + p->w_inlen, len); 1983 p->w_inlen += len; 1984 } 1985 WriteString(p, buf, len); 1986 return; 1987} 1988 1989static void 1990pseu_writeev_fn(ev, data) 1991struct event *ev; 1992char *data; 1993{ 1994 struct win *p = (struct win *)data; 1995 struct pseudowin *pw = p->w_pwin; 1996 int len; 1997 1998 ASSERT(pw); 1999 if (pw->p_inlen == 0) 2000 return; 2001 if ((len = write(ev->fd, pw->p_inbuf, pw->p_inlen)) <= 0) 2002 len = pw->p_inlen; /* dead pseudo */ 2003 if ((p->w_pwin->p_inlen -= len)) 2004 bcopy(p->w_pwin->p_inbuf + len, p->w_pwin->p_inbuf, p->w_pwin->p_inlen); 2005} 2006 2007 2008#endif /* PSEUDOS */ 2009 2010static void 2011win_silenceev_fn(ev, data) 2012struct event *ev; 2013char *data; 2014{ 2015 struct win *p = (struct win *)data; 2016 struct canvas *cv; 2017 debug1("FOUND silence win %d\n", p->w_number); 2018 for (display = displays; display; display = display->d_next) 2019 { 2020 for (cv = D_cvlist; cv; cv = cv->c_next) 2021 if (cv->c_layer->l_bottom == &p->w_layer) 2022 break; 2023 if (cv) 2024 continue; /* user already sees window */ 2025#ifdef MULTIUSER 2026 if (!(ACLBYTE(p->w_lio_notify, D_user->u_id) & ACLBIT(D_user->u_id))) 2027 continue; 2028#endif 2029 Msg(0, "Window %d: silence for %d seconds", p->w_number, p->w_silencewait); 2030 } 2031} 2032 2033#ifdef ZMODEM 2034 2035static int 2036zmodem_parse(p, bp, len) 2037struct win *p; 2038char *bp; 2039int len; 2040{ 2041 int i; 2042 char *b2 = bp; 2043 for (i = 0; i < len; i++, b2++) 2044 { 2045 if (p->w_zauto == 0) 2046 { 2047 for (; i < len; i++, b2++) 2048 if (*b2 == 030) 2049 break; 2050 if (i == len) 2051 break; 2052 if (i > 1 && b2[-1] == '*' && b2[-2] == '*') 2053 p->w_zauto = 3; 2054 continue; 2055 } 2056 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')) 2057 { 2058 if (++p->w_zauto < 6) 2059 continue; 2060 if (p->w_zauto == 6) 2061 p->w_zauto = 0; 2062 if (!p->w_zdisplay) 2063 { 2064 if (i > 6) 2065 WriteString(p, bp, i + 1 - 6); 2066 WriteString(p, "\r\n", 2); 2067 zmodem_found(p, *b2 == '1', b2 + 1, len - i - 1); 2068 return 1; 2069 } 2070 else if (p->w_zauto == 7 || *b2 == '8') 2071 { 2072 int se = p->w_zdisplay->d_blocked == 2 ? 'O' : '\212'; 2073 for (; i < len; i++, b2++) 2074 if (*b2 == se) 2075 break; 2076 if (i < len) 2077 { 2078 zmodem_abort(p, 0); 2079 D_blocked = 0; 2080 D_readev.condpos = D_readev.condneg = 0; 2081 while (len-- > 0) 2082 AddChar(*bp++); 2083 Flush(); 2084 Activate(D_fore ? D_fore->w_norefresh : 0); 2085 return 1; 2086 } 2087 p->w_zauto = 6; 2088 } 2089 } 2090 else 2091 p->w_zauto = *b2 == '*' ? (p->w_zauto == 2 ? 2 : 1) : 0; 2092 } 2093 if (p->w_zauto == 0 && bp[len - 1] == '*') 2094 p->w_zauto = len > 1 && bp[len - 2] == '*' ? 2 : 1; 2095 if (p->w_zdisplay) 2096 { 2097 display = p->w_zdisplay; 2098 while (len-- > 0) 2099 AddChar(*bp++); 2100 return 1; 2101 } 2102 return 0; 2103} 2104 2105static void 2106zmodem_fin(buf, len, data) 2107char *buf; 2108int len; 2109char *data; 2110{ 2111 char *s; 2112 int n; 2113 2114 if (len) 2115 RcLine(buf, strlen(buf) + 1); 2116 else 2117 { 2118 s = "\030\030\030\030\030\030\030\030\030\030"; 2119 n = strlen(s); 2120 LayProcess(&s, &n); 2121 } 2122} 2123 2124static void 2125zmodem_found(p, send, bp, len) 2126struct win *p; 2127int send; 2128char *bp; 2129int len; 2130{ 2131 char *s; 2132 int i, n; 2133 extern int zmodem_mode; 2134 2135 /* check for abort sequence */ 2136 n = 0; 2137 for (i = 0; i < len ; i++) 2138 if (bp[i] != 030) 2139 n = 0; 2140 else if (++n > 4) 2141 return; 2142 if (zmodem_mode == 3 || (zmodem_mode == 1 && p->w_type != W_TYPE_PLAIN)) 2143 { 2144 struct display *d, *olddisplay; 2145 2146 olddisplay = display; 2147 d = p->w_lastdisp; 2148 if (!d || d->d_fore != p) 2149 for (d = displays; d; d = d->d_next) 2150 if (d->d_fore == p) 2151 break; 2152 if (!d && p->w_layer.l_cvlist) 2153 d = p->w_layer.l_cvlist->c_display; 2154 if (!d) 2155 d = displays; 2156 if (!d) 2157 return; 2158 display = d; 2159 RemoveStatus(); 2160 p->w_zdisplay = display; 2161 D_blocked = 2 + send; 2162 flayer = &p->w_layer; 2163 ZmodemPage(); 2164 display = d; 2165 evdeq(&D_blockedev); 2166 D_readev.condpos = &const_IOSIZE; 2167 D_readev.condneg = &p->w_inlen; 2168 ClearAll(); 2169 GotoPos(0, 0); 2170 SetRendition(&mchar_blank); 2171 AddStr("Zmodem active\r\n\r\n"); 2172 AddStr(send ? "**\030B01" : "**\030B00"); 2173 while (len-- > 0) 2174 AddChar(*bp++); 2175 display = olddisplay; 2176 return; 2177 } 2178 flayer = &p->w_layer; 2179 Input(":", 100, INP_COOKED, zmodem_fin, NULL); 2180 s = send ? zmodem_sendcmd : zmodem_recvcmd; 2181 n = strlen(s); 2182 LayProcess(&s, &n); 2183} 2184 2185void 2186zmodem_abort(p, d) 2187struct win *p; 2188struct display *d; 2189{ 2190 struct display *olddisplay = display; 2191 struct layer *oldflayer = flayer; 2192 if (p) 2193 { 2194 if (p->w_savelayer && p->w_savelayer->l_next) 2195 { 2196 if (oldflayer == p->w_savelayer) 2197 oldflayer = flayer->l_next; 2198 flayer = p->w_savelayer; 2199 ExitOverlayPage(); 2200 } 2201 p->w_zdisplay = 0; 2202 p->w_zauto = 0; 2203 LRefreshAll(&p->w_layer, 0); 2204 } 2205 if (d) 2206 { 2207 display = d; 2208 D_blocked = 0; 2209 D_readev.condpos = D_readev.condneg = 0; 2210 Activate(D_fore ? D_fore->w_norefresh : 0); 2211 } 2212 display = olddisplay; 2213 flayer = oldflayer; 2214} 2215 2216#endif 2217