|
|
1.1 ! root 1: /* cusub.c ! 2: System dependent routines for cu. ! 3: ! 4: Copyright (C) 1992 Ian Lance Taylor ! 5: ! 6: This file is part of the Taylor UUCP package. ! 7: ! 8: This program is free software; you can redistribute it and/or ! 9: modify it under the terms of the GNU General Public License as ! 10: published by the Free Software Foundation; either version 2 of the ! 11: License, or (at your option) any later version. ! 12: ! 13: This program is distributed in the hope that it will be useful, but ! 14: WITHOUT ANY WARRANTY; without even the implied warranty of ! 15: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 16: General Public License for more details. ! 17: ! 18: You should have received a copy of the GNU General Public License ! 19: along with this program; if not, write to the Free Software ! 20: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ! 21: ! 22: The author of the program may be contacted at [email protected] or ! 23: c/o Infinity Development Systems, P.O. Box 520, Waltham, MA 02254. ! 24: */ ! 25: ! 26: #include "uucp.h" ! 27: ! 28: #if USE_RCS_ID ! 29: const char cusub_rcsid[] = "$Id: cusub.c,v 1.1 93/07/30 08:02:24 bin Exp Locker: bin $"; ! 30: #endif ! 31: ! 32: #include "uudefs.h" ! 33: #include "uuconf.h" ! 34: #include "sysdep.h" ! 35: #include "system.h" ! 36: #include "cu.h" ! 37: #include "conn.h" ! 38: #include "prot.h" ! 39: ! 40: #include <errno.h> ! 41: ! 42: /* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA. */ ! 43: #ifndef EAGAIN ! 44: #ifndef EWOULDBLOCK ! 45: #define EAGAIN (-1) ! 46: #define EWOULDBLOCK (-1) ! 47: #else /* defined (EWOULDBLOCK) */ ! 48: #define EAGAIN EWOULDBLOCK ! 49: #endif /* defined (EWOULDBLOCK) */ ! 50: #else /* defined (EAGAIN) */ ! 51: #ifndef EWOULDBLOCK ! 52: #define EWOULDBLOCK EAGAIN ! 53: #endif /* ! defined (EWOULDBLOCK) */ ! 54: #endif /* defined (EAGAIN) */ ! 55: ! 56: #ifndef ENODATA ! 57: #define ENODATA EAGAIN ! 58: #endif ! 59: ! 60: /* Local variables. */ ! 61: ! 62: /* The EOF character, as set by fsysdep_terminal_raw. */ ! 63: static char bSeof; ! 64: ! 65: /* The SUSP character, as set by fsysdep_terminal_raw. */ ! 66: static char bStstp; ! 67: ! 68: /* Local functions. */ ! 69: ! 70: static const char *zsport_line P((const struct uuconf_port *qport)); ! 71: static void uscu_child P((struct sconnection *qconn, int opipe)); ! 72: static RETSIGTYPE uscu_alarm P((int isig)); ! 73: static int cscu_escape P((char *pbcmd, const char *zlocalname)); ! 74: static RETSIGTYPE uscu_alarm_kill P((int isig)); ! 75: ! 76: /* Return the device name for a port, or NULL if none. */ ! 77: ! 78: static const char * ! 79: zsport_line (qport) ! 80: const struct uuconf_port *qport; ! 81: { ! 82: const char *zline; ! 83: ! 84: if (qport == NULL) ! 85: return NULL; ! 86: ! 87: switch (qport->uuconf_ttype) ! 88: { ! 89: default: ! 90: case UUCONF_PORTTYPE_STDIN: ! 91: return NULL; ! 92: case UUCONF_PORTTYPE_MODEM: ! 93: zline = qport->uuconf_u.uuconf_smodem.uuconf_zdevice; ! 94: break; ! 95: case UUCONF_PORTTYPE_DIRECT: ! 96: zline = qport->uuconf_u.uuconf_sdirect.uuconf_zdevice; ! 97: break; ! 98: case UUCONF_PORTTYPE_TCP: ! 99: case UUCONF_PORTTYPE_TLI: ! 100: return NULL; ! 101: } ! 102: ! 103: if (zline == NULL) ! 104: zline = qport->uuconf_zname; ! 105: return zline; ! 106: } ! 107: ! 108: /* Check whether the user has legitimate access to a port. */ ! 109: ! 110: boolean ! 111: fsysdep_port_access (qport) ! 112: struct uuconf_port *qport; ! 113: { ! 114: const char *zline; ! 115: char *zfree; ! 116: boolean fret; ! 117: ! 118: zline = zsport_line (qport); ! 119: if (zline == NULL) ! 120: return TRUE; ! 121: ! 122: zfree = NULL; ! 123: if (*zline != '/') ! 124: { ! 125: zfree = zbufalc (sizeof "/dev/" + strlen (zline)); ! 126: sprintf (zfree, "/dev/%s", zline); ! 127: zline = zfree; ! 128: } ! 129: ! 130: fret = access (zline, R_OK | W_OK) == 0; ! 131: ubuffree (zfree); ! 132: return fret; ! 133: } ! 134: ! 135: /* Return whether the given port is named by the given line. */ ! 136: ! 137: boolean ! 138: fsysdep_port_is_line (qport, zline) ! 139: struct uuconf_port *qport; ! 140: const char *zline; ! 141: { ! 142: const char *zpline; ! 143: char *zfree1, *zfree2; ! 144: boolean fret; ! 145: ! 146: zpline = zsport_line (qport); ! 147: if (zpline == NULL) ! 148: return FALSE; ! 149: ! 150: if (strcmp (zline, zpline) == 0) ! 151: return TRUE; ! 152: ! 153: zfree1 = NULL; ! 154: zfree2 = NULL; ! 155: if (*zline != '/') ! 156: { ! 157: zfree1 = zbufalc (sizeof "/dev/" + strlen (zline)); ! 158: sprintf (zfree1, "/dev/%s", zline); ! 159: zline = zfree1; ! 160: } ! 161: if (*zpline != '/') ! 162: { ! 163: zfree2 = zbufalc (sizeof "/dev/" + strlen (zpline)); ! 164: sprintf (zfree2, "/dev/%s", zpline); ! 165: zpline = zfree2; ! 166: } ! 167: ! 168: fret = strcmp (zline, zpline) == 0; ! 169: ubuffree (zfree1); ! 170: ubuffree (zfree2); ! 171: return fret; ! 172: } ! 173: ! 174: /* The cu program wants the system dependent layer to handle the ! 175: details of copying data from the communications port to the ! 176: terminal. This copying need only be done while executing ! 177: fsysdep_cu. On Unix, however, we set up a subprocess to do it all ! 178: the time. This subprocess must be controllable via the ! 179: fsysdep_cu_copy function. ! 180: ! 181: We keep a pipe open to the subprocess. When we want it to stop we ! 182: send it a signal, and then wait for it to write a byte to us over ! 183: the pipe. */ ! 184: ! 185: /* The subprocess pid. */ ! 186: static volatile pid_t iSchild; ! 187: ! 188: /* The pipe from the subprocess. */ ! 189: static int oSpipe; ! 190: ! 191: /* When we tell the child to stop, it sends this. */ ! 192: #define CHILD_STOPPED ('S') ! 193: ! 194: /* When we tell the child to start, it sends this. */ ! 195: #define CHILD_STARTED ('G') ! 196: ! 197: /* Initialize the subprocess, and have it start copying data. */ ! 198: ! 199: boolean ! 200: fsysdep_cu_init (qconn) ! 201: struct sconnection *qconn; ! 202: { ! 203: int ai[2]; ! 204: ! 205: /* Write out anything we may have buffered up during the chat ! 206: script. We do this before forking the child only to make it easy ! 207: to move the child into a separate executable. */ ! 208: while (iPrecend != iPrecstart) ! 209: { ! 210: char *z; ! 211: int c; ! 212: ! 213: z = abPrecbuf + iPrecstart; ! 214: if (iPrecend > iPrecstart) ! 215: c = iPrecend - iPrecstart; ! 216: else ! 217: c = CRECBUFLEN - iPrecstart; ! 218: ! 219: iPrecstart = (iPrecstart + c) % CRECBUFLEN; ! 220: ! 221: while (c > 0) ! 222: { ! 223: int cwrote; ! 224: ! 225: cwrote = write (1, z, c); ! 226: if (cwrote <= 0) ! 227: { ! 228: if (cwrote < 0) ! 229: ulog (LOG_ERROR, "write: %s", strerror (errno)); ! 230: else ! 231: ulog (LOG_ERROR, "Line disconnected"); ! 232: return FALSE; ! 233: } ! 234: c -= cwrote; ! 235: z += cwrote; ! 236: } ! 237: } ! 238: ! 239: if (pipe (ai) < 0) ! 240: { ! 241: ulog (LOG_ERROR, "pipe: %s", strerror (errno)); ! 242: return FALSE; ! 243: } ! 244: ! 245: iSchild = ixsfork (); ! 246: if (iSchild < 0) ! 247: { ! 248: ulog (LOG_ERROR, "fork: %s", strerror (errno)); ! 249: return FALSE; ! 250: } ! 251: ! 252: if (iSchild == 0) ! 253: { ! 254: (void) close (ai[0]); ! 255: uscu_child (qconn, ai[1]); ! 256: /*NOTREACHED*/ ! 257: } ! 258: ! 259: (void) close (ai[1]); ! 260: ! 261: oSpipe = ai[0]; ! 262: ! 263: return TRUE; ! 264: } ! 265: ! 266: /* Copy all data from the terminal to the communications port. If we ! 267: see an escape character following a newline character, read the ! 268: next character and return it. */ ! 269: ! 270: boolean ! 271: fsysdep_cu (qconn, pbcmd, zlocalname) ! 272: struct sconnection *qconn; ! 273: char *pbcmd; ! 274: const char *zlocalname; ! 275: { ! 276: boolean fstart; ! 277: char b; ! 278: int c; ! 279: ! 280: fstart = TRUE; ! 281: ! 282: while (TRUE) ! 283: { ! 284: if (fsysdep_catch ()) ! 285: usysdep_start_catch (); ! 286: else ! 287: { ! 288: ulog (LOG_ERROR, (const char *) NULL); ! 289: return FALSE; ! 290: } ! 291: ! 292: c = read (0, &b, 1); ! 293: ! 294: usysdep_end_catch (); ! 295: ! 296: if (c <= 0) ! 297: break; ! 298: ! 299: if (fstart && b == *zCuvar_escape) ! 300: { ! 301: c = cscu_escape (pbcmd, zlocalname); ! 302: if (c <= 0) ! 303: break; ! 304: if (*pbcmd != b) ! 305: { ! 306: write (1, pbcmd, 1); ! 307: ! 308: /* For Unix, we let the eof character be the same as ! 309: '.', and we let the suspend character (if any) be the ! 310: same as 'z'. */ ! 311: if (*pbcmd == bSeof) ! 312: *pbcmd = '.'; ! 313: if (*pbcmd == bStstp) ! 314: *pbcmd = 'z'; ! 315: return TRUE; ! 316: } ! 317: } ! 318: if (! fconn_write (qconn, &b, (size_t) 1)) ! 319: return FALSE; ! 320: fstart = strchr (zCuvar_eol, b) != NULL; ! 321: } ! 322: ! 323: if (c < 0) ! 324: { ! 325: if (errno != EINTR) ! 326: ulog (LOG_ERROR, "read: %s", strerror (errno)); ! 327: else ! 328: ulog (LOG_ERROR, (const char *) NULL); ! 329: return FALSE; ! 330: } ! 331: ! 332: /* I'm not sure what's best in this case. */ ! 333: ulog (LOG_ERROR, "End of file on terminal"); ! 334: return FALSE; ! 335: } ! 336: ! 337: /* A SIGALRM handler that sets fScu_alarm and optionally longjmps. */ ! 338: ! 339: volatile sig_atomic_t fScu_alarm; ! 340: ! 341: static RETSIGTYPE ! 342: uscu_alarm (isig) ! 343: int isig; ! 344: { ! 345: #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET ! 346: (void) signal (isig, uscu_alarm); ! 347: #endif ! 348: ! 349: fScu_alarm = TRUE; ! 350: ! 351: #if HAVE_RESTARTABLE_SYSCALLS ! 352: if (fSjmp) ! 353: longjmp (sSjmp_buf, 1); ! 354: #endif ! 355: } ! 356: ! 357: /* We've just seen an escape character. We print the host name, ! 358: optionally after a 1 second delay. We read the next character from ! 359: the terminal and return it. The 1 second delay on the host name is ! 360: mostly to be fancy; it lets ~~ look smoother. */ ! 361: ! 362: static int ! 363: cscu_escape (pbcmd, zlocalname) ! 364: char *pbcmd; ! 365: const char *zlocalname; ! 366: { ! 367: CATCH_PROTECT int c; ! 368: ! 369: write (1, zCuvar_escape, 1); ! 370: ! 371: fScu_alarm = FALSE; ! 372: usset_signal (SIGALRM, uscu_alarm, TRUE, (boolean *) NULL); ! 373: ! 374: if (fsysdep_catch ()) ! 375: { ! 376: usysdep_start_catch (); ! 377: alarm (1); ! 378: } ! 379: ! 380: c = 0; ! 381: ! 382: while (TRUE) ! 383: { ! 384: if (fScu_alarm) ! 385: { ! 386: char b; ! 387: ! 388: fScu_alarm = FALSE; ! 389: b = '['; ! 390: write (1, &b, 1); ! 391: write (1, zlocalname, strlen (zlocalname)); ! 392: b = ']'; ! 393: write (1, &b, 1); ! 394: } ! 395: ! 396: if (c <= 0) ! 397: c = read (0, pbcmd, 1); ! 398: if (c >= 0 || errno != EINTR) ! 399: { ! 400: usysdep_end_catch (); ! 401: usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); ! 402: alarm (0); ! 403: return c; ! 404: } ! 405: } ! 406: } ! 407: ! 408: /* A SIGALRM handler which does nothing but send a signal to the child ! 409: process and schedule another alarm. POSIX.1 permits kill and alarm ! 410: from a signal handler. The reference to static data may or may not ! 411: be permissible. */ ! 412: ! 413: static volatile sig_atomic_t iSsend_sig; ! 414: ! 415: static RETSIGTYPE ! 416: uscu_alarm_kill (isig) ! 417: int isig; ! 418: { ! 419: #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET ! 420: (void) signal (isig, uscu_alarm_kill); ! 421: #endif ! 422: ! 423: (void) kill (iSchild, iSsend_sig); ! 424: ! 425: alarm (1); ! 426: } ! 427: ! 428: /* Start or stop copying data from the communications port to the ! 429: terminal. We send a signal to the child process to tell it what to ! 430: do. Unfortunately, there are race conditions in the child, so we ! 431: keep sending it a signal once a second until it responds. We send ! 432: SIGUSR1 to make it start copying, and SIGUSR2 to make it stop. */ ! 433: ! 434: boolean ! 435: fsysdep_cu_copy (fcopy) ! 436: boolean fcopy; ! 437: { ! 438: int ierr; ! 439: int c; ! 440: ! 441: usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL); ! 442: if (fcopy) ! 443: iSsend_sig = SIGUSR1; ! 444: else ! 445: iSsend_sig = SIGUSR2; ! 446: ! 447: uscu_alarm_kill (SIGALRM); ! 448: ! 449: alarm (1); ! 450: ! 451: while (TRUE) ! 452: { ! 453: char b; ! 454: ! 455: c = read (oSpipe, &b, 1); ! 456: ! 457: #if DEBUG > 1 ! 458: if (c > 0) ! 459: DEBUG_MESSAGE1 (DEBUG_INCOMING, ! 460: "fsysdep_cu_copy: Got '%d'", b); ! 461: #endif ! 462: ! 463: if ((c < 0 && errno != EINTR) ! 464: || c == 0 ! 465: || (c > 0 && b == (fcopy ? CHILD_STARTED : CHILD_STOPPED))) ! 466: break; ! 467: ! 468: /* If none of the above conditions were true, then we either got ! 469: an EINTR error, in which case we probably timed out and the ! 470: SIGALRM handler resent the signal, or we read the wrong ! 471: character, in which case we will just read again from the ! 472: pipe. */ ! 473: } ! 474: ! 475: ierr = errno; ! 476: ! 477: usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); ! 478: alarm (0); ! 479: ! 480: if (c > 0) ! 481: return TRUE; ! 482: ! 483: if (c == 0) ! 484: ulog (LOG_ERROR, "EOF on child pipe"); ! 485: else ! 486: ulog (LOG_ERROR, "read: %s", strerror (ierr)); ! 487: ! 488: return FALSE; ! 489: } ! 490: ! 491: /* Shut down cu by killing the child process. */ ! 492: ! 493: boolean ! 494: fsysdep_cu_finish () ! 495: { ! 496: (void) close (oSpipe); ! 497: ! 498: /* We hit the child with SIGTERM, give it two seconds to die, and ! 499: then send a SIGKILL. */ ! 500: if (kill (iSchild, SIGTERM) < 0) ! 501: { ! 502: /* Don't give an error if the child has already died. */ ! 503: if (errno != ESRCH) ! 504: ulog (LOG_ERROR, "kill: %s", strerror (errno)); ! 505: } ! 506: ! 507: usset_signal (SIGALRM, uscu_alarm_kill, TRUE, (boolean *) NULL); ! 508: iSsend_sig = SIGKILL; ! 509: alarm (2); ! 510: ! 511: (void) ixswait ((unsigned long) iSchild, "child"); ! 512: ! 513: usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL); ! 514: alarm (0); ! 515: ! 516: return TRUE; ! 517: } ! 518: ! 519: /* Code for the child process. */ ! 520: ! 521: /* This signal handler just records the signal. In this case we only ! 522: care about which signal we received most recently. */ ! 523: ! 524: static volatile sig_atomic_t iSchild_sig; ! 525: ! 526: static RETSIGTYPE ! 527: uscu_child_handler (isig) ! 528: int isig; ! 529: { ! 530: #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET ! 531: (void) signal (isig, uscu_child_handler); ! 532: #endif ! 533: ! 534: iSchild_sig = isig; ! 535: ! 536: #if HAVE_RESTARTABLE_SYSCALLS ! 537: if (fSjmp) ! 538: longjmp (sSjmp_buf, 1); ! 539: #endif /* HAVE_RESTARTABLE_SYSCALLS */ ! 540: } ! 541: ! 542: /* The child process. This copies the port to the terminal, except ! 543: when it is stopped by a signal. It would be reasonable to write a ! 544: separate program for this, probably passing it the port on stdin. ! 545: This would reduce the memory requirements, since we wouldn't need a ! 546: second process holding all the configuration stuff, and also let it ! 547: work reasonably on 680x0 versions of MINIX. */ ! 548: ! 549: static void ! 550: uscu_child (qconn, opipe) ! 551: struct sconnection *qconn; ! 552: int opipe; ! 553: { ! 554: CATCH_PROTECT int oport; ! 555: CATCH_PROTECT boolean fstopped, fgot; ! 556: CATCH_PROTECT int cwrite; ! 557: CATCH_PROTECT char abbuf[1024]; ! 558: ! 559: /* It would be nice if we could just use fsserial_read, but that ! 560: will log signals that we don't want logged. There should be a ! 561: generic way to extract the file descriptor from the port. */ ! 562: if (qconn->qport == NULL) ! 563: oport = 0; ! 564: else ! 565: { ! 566: switch (qconn->qport->uuconf_ttype) ! 567: { ! 568: #if DEBUG > 0 ! 569: default: ! 570: ulog (LOG_FATAL, "uscu_child: Can't happen"); ! 571: oport = -1; ! 572: break; ! 573: #endif ! 574: case UUCONF_PORTTYPE_STDIN: ! 575: oport = 0; ! 576: break; ! 577: case UUCONF_PORTTYPE_MODEM: ! 578: case UUCONF_PORTTYPE_DIRECT: ! 579: case UUCONF_PORTTYPE_TCP: ! 580: case UUCONF_PORTTYPE_TLI: ! 581: oport = ((struct ssysdep_conn *) qconn->psysdep)->o; ! 582: break; ! 583: } ! 584: } ! 585: ! 586: usset_signal (SIGUSR1, uscu_child_handler, TRUE, (boolean *) NULL); ! 587: usset_signal (SIGUSR2, uscu_child_handler, TRUE, (boolean *) NULL); ! 588: usset_signal (SIGINT, SIG_IGN, TRUE, (boolean *) NULL); ! 589: usset_signal (SIGQUIT, SIG_IGN, TRUE, (boolean *) NULL); ! 590: usset_signal (SIGPIPE, SIG_DFL, TRUE, (boolean *) NULL); ! 591: usset_signal (SIGTERM, uscu_child_handler, TRUE, (boolean *) NULL); ! 592: ! 593: fstopped = FALSE; ! 594: fgot = FALSE; ! 595: iSchild_sig = 0; ! 596: cwrite = 0; ! 597: ! 598: if (fsysdep_catch ()) ! 599: usysdep_start_catch (); ! 600: ! 601: while (TRUE) ! 602: { ! 603: int isig; ! 604: int c; ! 605: ! 606: /* There is a race condition here between checking the signal ! 607: and receiving a new and possibly different one. This is ! 608: solved by having the parent resend the signal until it gets a ! 609: response. */ ! 610: isig = iSchild_sig; ! 611: iSchild_sig = 0; ! 612: if (isig != 0) ! 613: { ! 614: char b; ! 615: ! 616: if (isig == SIGTERM) ! 617: exit (EXIT_SUCCESS); ! 618: ! 619: if (isig == SIGUSR1) ! 620: { ! 621: fstopped = FALSE; ! 622: b = CHILD_STARTED; ! 623: } ! 624: else ! 625: { ! 626: fstopped = TRUE; ! 627: b = CHILD_STOPPED; ! 628: cwrite = 0; ! 629: } ! 630: ! 631: c = write (opipe, &b, 1); ! 632: ! 633: /* Apparently on some systems we can get EAGAIN here. */ ! 634: if (c < 0 && ! 635: (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA)) ! 636: c = 0; ! 637: ! 638: if (c <= 0) ! 639: { ! 640: /* Should we give an error message here? */ ! 641: (void) kill (getppid (), SIGHUP); ! 642: exit (EXIT_FAILURE); ! 643: } ! 644: } ! 645: ! 646: if (fstopped) ! 647: pause (); ! 648: else if (cwrite > 0) ! 649: { ! 650: char *zbuf; ! 651: ! 652: zbuf = abbuf; ! 653: while (cwrite > 0) ! 654: { ! 655: c = write (1, zbuf, cwrite); ! 656: ! 657: /* Apparently on some systems we can get EAGAIN here. */ ! 658: if (c < 0 && ! 659: (errno == EAGAIN ! 660: || errno == EWOULDBLOCK ! 661: || errno == ENODATA)) ! 662: c = 0; ! 663: ! 664: if (c < 0 && errno == EINTR) ! 665: break; ! 666: if (c <= 0) ! 667: { ! 668: /* Should we give an error message here? */ ! 669: (void) kill (getppid (), SIGHUP); ! 670: exit (EXIT_FAILURE); ! 671: } ! 672: cwrite -= c; ! 673: zbuf += c; ! 674: } ! 675: } ! 676: else ! 677: { ! 678: /* On some systems apparently read will return 0 until ! 679: something has been written to the port. We therefore ! 680: accept a 0 return until after we have managed to read ! 681: something. Setting errno to 0 apparently avoids a ! 682: problem on Coherent. */ ! 683: errno = 0; ! 684: c = read (oport, abbuf, sizeof abbuf); ! 685: ! 686: /* Apparently on some systems we can get EAGAIN here. */ ! 687: if (c < 0 && ! 688: (errno == EAGAIN || errno == EWOULDBLOCK || errno == ENODATA)) ! 689: c = 0; ! 690: ! 691: if ((c == 0 && fgot) ! 692: || (c < 0 && errno != EINTR)) ! 693: { ! 694: /* This can be a normal way to exit, depending on just ! 695: how the connection is dropped. */ ! 696: (void) kill (getppid (), SIGHUP); ! 697: exit (EXIT_SUCCESS); ! 698: } ! 699: if (c > 0) ! 700: { ! 701: fgot = TRUE; ! 702: cwrite = c; ! 703: } ! 704: } ! 705: } ! 706: } ! 707: ! 708: /* Terminal control routines. */ ! 709: ! 710: /* Whether file descriptor 0 is attached to a terminal or not. */ ! 711: static boolean fSterm; ! 712: ! 713: /* Whether we are doing local echoing. */ ! 714: static boolean fSlocalecho; ! 715: ! 716: /* The original state of the terminal. */ ! 717: static sterminal sSterm_orig; ! 718: ! 719: /* The new state of the terminal. */ ! 720: static sterminal sSterm_new; ! 721: ! 722: #if ! HAVE_BSD_TTY ! 723: #ifdef SIGTSTP ! 724: /* Whether SIGTSTP is being ignored. */ ! 725: static boolean fStstp_ignored; ! 726: #endif ! 727: #endif ! 728: ! 729: /* Set the terminal into raw mode. */ ! 730: ! 731: boolean ! 732: fsysdep_terminal_raw (flocalecho) ! 733: boolean flocalecho; ! 734: { ! 735: fSlocalecho = flocalecho; ! 736: ! 737: /* This defaults may be overriden below. */ ! 738: bSeof = '\004'; ! 739: bStstp = '\032'; ! 740: ! 741: if (! fgetterminfo (0, &sSterm_orig)) ! 742: { ! 743: fSterm = FALSE; ! 744: return TRUE; ! 745: } ! 746: ! 747: fSterm = TRUE; ! 748: ! 749: sSterm_new = sSterm_orig; ! 750: ! 751: #if HAVE_BSD_TTY ! 752: ! 753: /* We use CBREAK mode rather than RAW mode, because RAW mode turns ! 754: off all output processing, which we don't want to do. This means ! 755: that we have to disable the interrupt characters, which we do by ! 756: setting them to -1. */ ! 757: bSeof = sSterm_orig.stchars.t_eofc; ! 758: ! 759: sSterm_new.stchars.t_intrc = -1; ! 760: sSterm_new.stchars.t_quitc = -1; ! 761: sSterm_new.stchars.t_startc = -1; ! 762: sSterm_new.stchars.t_stopc = -1; ! 763: sSterm_new.stchars.t_eofc = -1; ! 764: sSterm_new.stchars.t_brkc = -1; ! 765: ! 766: bStstp = sSterm_orig.sltchars.t_suspc; ! 767: ! 768: sSterm_new.sltchars.t_suspc = -1; ! 769: sSterm_new.sltchars.t_dsuspc = -1; ! 770: sSterm_new.sltchars.t_rprntc = -1; ! 771: sSterm_new.sltchars.t_flushc = -1; ! 772: sSterm_new.sltchars.t_werasc = -1; ! 773: sSterm_new.sltchars.t_lnextc = -1; ! 774: ! 775: if (! flocalecho) ! 776: { ! 777: sSterm_new.stty.sg_flags |= (CBREAK | ANYP); ! 778: sSterm_new.stty.sg_flags &=~ (ECHO | CRMOD | TANDEM); ! 779: } ! 780: else ! 781: { ! 782: sSterm_new.stty.sg_flags |= (CBREAK | ANYP | ECHO); ! 783: sSterm_new.stty.sg_flags &=~ (CRMOD | TANDEM); ! 784: } ! 785: ! 786: #endif /* HAVE_BSD_TTY */ ! 787: ! 788: #if HAVE_SYSV_TERMIO ! 789: ! 790: bSeof = sSterm_new.c_cc[VEOF]; ! 791: if (! flocalecho) ! 792: sSterm_new.c_lflag &=~ (ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHONL); ! 793: else ! 794: sSterm_new.c_lflag &=~ (ICANON | ISIG); ! 795: sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL); ! 796: sSterm_new.c_oflag &=~ (OPOST); ! 797: sSterm_new.c_cc[VMIN] = 1; ! 798: sSterm_new.c_cc[VTIME] = 0; ! 799: ! 800: #endif /* HAVE_SYSV_TERMIO */ ! 801: ! 802: #if HAVE_POSIX_TERMIOS ! 803: ! 804: bSeof = sSterm_new.c_cc[VEOF]; ! 805: bStstp = sSterm_new.c_cc[VSUSP]; ! 806: if (! flocalecho) ! 807: sSterm_new.c_lflag &=~ ! 808: (ICANON | IEXTEN | ISIG | ECHO | ECHOE | ECHOK | ECHONL); ! 809: else ! 810: sSterm_new.c_lflag &=~ (ICANON | IEXTEN | ISIG); ! 811: sSterm_new.c_iflag &=~ (INLCR | IGNCR | ICRNL); ! 812: sSterm_new.c_oflag &=~ (OPOST); ! 813: sSterm_new.c_cc[VMIN] = 1; ! 814: sSterm_new.c_cc[VTIME] = 0; ! 815: ! 816: #endif /* HAVE_POSIX_TERMIOS */ ! 817: ! 818: if (! fsetterminfo (0, &sSterm_new)) ! 819: { ! 820: ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno)); ! 821: return FALSE; ! 822: } ! 823: ! 824: return TRUE; ! 825: } ! 826: ! 827: /* Restore the terminal to its original setting. */ ! 828: ! 829: boolean ! 830: fsysdep_terminal_restore () ! 831: { ! 832: if (! fSterm) ! 833: return TRUE; ! 834: ! 835: if (! fsetterminfo (0, &sSterm_orig)) ! 836: { ! 837: ulog (LOG_ERROR, "Can't restore terminal: %s", strerror (errno)); ! 838: return FALSE; ! 839: } ! 840: return TRUE; ! 841: } ! 842: ! 843: /* Read a line from the terminal. This will be called after ! 844: fsysdep_terminal_raw has been called. */ ! 845: ! 846: char * ! 847: zsysdep_terminal_line (zprompt) ! 848: const char *zprompt; ! 849: { ! 850: CATCH_PROTECT size_t cbuf = 0; ! 851: CATCH_PROTECT char *zbuf = NULL; ! 852: CATCH_PROTECT size_t cgot = 0; ! 853: ! 854: if (zprompt != NULL && *zprompt != '\0') ! 855: (void) write (1, zprompt, strlen (zprompt)); ! 856: ! 857: /* Forgot about any previous SIGINT or SIGQUIT signals we may have ! 858: received. We don't worry about the race condition here, since we ! 859: can't get these signals from the terminal at the moment and it's ! 860: not too likely that somebody else will be sending them to us. */ ! 861: afSignal[INDEXSIG_SIGINT] = 0; ! 862: afSignal[INDEXSIG_SIGQUIT] = 0; ! 863: ! 864: if (! fsysdep_terminal_restore ()) ! 865: return NULL; ! 866: ! 867: if (fsysdep_catch ()) ! 868: { ! 869: usysdep_start_catch (); ! 870: cbuf = 0; ! 871: zbuf = NULL; ! 872: cgot = 0; ! 873: } ! 874: ! 875: while (TRUE) ! 876: { ! 877: char b; ! 878: int c; ! 879: ! 880: if (afSignal[INDEXSIG_SIGINT] ! 881: || afSignal[INDEXSIG_SIGQUIT]) ! 882: { ! 883: usysdep_end_catch (); ! 884: /* Make sure the signal is logged. */ ! 885: ulog (LOG_ERROR, (const char *) NULL); ! 886: /* Return an empty string. */ ! 887: cgot = 0; ! 888: break; ! 889: } ! 890: ! 891: /* There's a race here between checking the signals and calling ! 892: read. It just means that the user will have to hit ^C more ! 893: than once. */ ! 894: ! 895: c = read (0, &b, 1); ! 896: if (c < 0) ! 897: { ! 898: if (errno == EINTR) ! 899: continue; ! 900: usysdep_end_catch (); ! 901: ulog (LOG_ERROR, "read: %s", strerror (errno)); ! 902: (void) fsysdep_terminal_raw (fSlocalecho); ! 903: return NULL; ! 904: } ! 905: if (c == 0) ! 906: { ! 907: /* I'm not quite sure what to do here. */ ! 908: usysdep_end_catch (); ! 909: ulog (LOG_ERROR, "EOF on terminal"); ! 910: (void) fsysdep_terminal_raw (fSlocalecho); ! 911: return NULL; ! 912: } ! 913: ! 914: if (cgot >= cbuf) ! 915: { ! 916: char *znew; ! 917: ! 918: cbuf += 64; ! 919: znew = zbufalc (cbuf); ! 920: if (zbuf != NULL) ! 921: { ! 922: memcpy (znew, zbuf, cgot); ! 923: ubuffree (zbuf); ! 924: } ! 925: zbuf = znew; ! 926: } ! 927: ! 928: zbuf[cgot] = b; ! 929: ! 930: ++cgot; ! 931: ! 932: if (b == '\n') ! 933: { ! 934: usysdep_end_catch (); ! 935: break; ! 936: } ! 937: } ! 938: ! 939: if (cgot >= cbuf) ! 940: { ! 941: char *znew; ! 942: ! 943: ++cbuf; ! 944: znew = zbufalc (cbuf); ! 945: if (zbuf != NULL) ! 946: { ! 947: memcpy (znew, zbuf, cgot); ! 948: ubuffree (zbuf); ! 949: } ! 950: zbuf = znew; ! 951: } ! 952: ! 953: zbuf[cgot] = '\0'; ! 954: ! 955: if (! fsysdep_terminal_raw (fSlocalecho)) ! 956: return NULL; ! 957: ! 958: return zbuf; ! 959: } ! 960: ! 961: /* Write a line to the terminal with a trailing newline. */ ! 962: ! 963: boolean ! 964: fsysdep_terminal_puts (zline) ! 965: const char *zline; ! 966: { ! 967: char *zalc, *zprint; ! 968: size_t clen; ! 969: ! 970: if (zline == NULL) ! 971: { ! 972: zalc = zbufalc (2); ! 973: clen = 0; ! 974: } ! 975: else ! 976: { ! 977: clen = strlen (zline); ! 978: zalc = zbufalc (clen + 2); ! 979: memcpy (zalc, zline, clen); ! 980: } ! 981: ! 982: if (fSterm) ! 983: { ! 984: zalc[clen] = '\r'; ! 985: ++clen; ! 986: } ! 987: zalc[clen] = '\n'; ! 988: ++clen; ! 989: ! 990: zprint = zalc; ! 991: while (clen > 0) ! 992: { ! 993: int c; ! 994: ! 995: c = write (1, zprint, clen); ! 996: if (c <= 0) ! 997: { ! 998: ubuffree (zalc); ! 999: ulog (LOG_ERROR, "write: %s", strerror (errno)); ! 1000: return FALSE; ! 1001: } ! 1002: clen -= c; ! 1003: zprint += c; ! 1004: } ! 1005: ! 1006: ubuffree (zalc); ! 1007: ! 1008: return TRUE; ! 1009: } ! 1010: ! 1011: /* Allow or disallow signals from the terminal. */ ! 1012: ! 1013: boolean ! 1014: fsysdep_terminal_signals (faccept) ! 1015: boolean faccept; ! 1016: { ! 1017: #if HAVE_BSD_TTY ! 1018: ! 1019: if (faccept) ! 1020: { ! 1021: sSterm_new.stchars.t_intrc = sSterm_orig.stchars.t_intrc; ! 1022: sSterm_new.stchars.t_quitc = sSterm_orig.stchars.t_quitc; ! 1023: } ! 1024: else ! 1025: { ! 1026: sSterm_new.stchars.t_intrc = -1; ! 1027: sSterm_new.stchars.t_quitc = -1; ! 1028: } ! 1029: ! 1030: #else /* ! HAVE_BSD_TTY */ ! 1031: ! 1032: if (faccept) ! 1033: sSterm_new.c_lflag |= ISIG; ! 1034: else ! 1035: sSterm_new.c_lflag &=~ ISIG; ! 1036: ! 1037: #ifdef SIGTSTP ! 1038: /* We only want to get SIGINT and SIGQUIT, not SIGTSTP. This ! 1039: function will be called with faccept TRUE before it is called ! 1040: with faccept FALSE, so fStstp_ignored will be correctly ! 1041: initialized. */ ! 1042: if (faccept) ! 1043: usset_signal (SIGTSTP, SIG_IGN, FALSE, &fStstp_ignored); ! 1044: else if (! fStstp_ignored) ! 1045: usset_signal (SIGTSTP, SIG_DFL, TRUE, (boolean *) NULL); ! 1046: #endif ! 1047: ! 1048: #endif /* ! HAVE_BSD_TTY */ ! 1049: ! 1050: if (! fsetterminfo (0, &sSterm_new)) ! 1051: { ! 1052: ulog (LOG_ERROR, "Can't set terminal: %s", strerror (errno)); ! 1053: return FALSE; ! 1054: } ! 1055: ! 1056: return TRUE; ! 1057: } ! 1058: ! 1059: /* Start up a command, or possibly just a shell. Optionally attach ! 1060: stdin or stdout to the port. We attach directly to the port, ! 1061: rather than copying the data ourselves. */ ! 1062: ! 1063: boolean ! 1064: fsysdep_shell (qconn, zcmd, tcmd) ! 1065: struct sconnection *qconn; ! 1066: const char *zcmd; ! 1067: enum tshell_cmd tcmd; ! 1068: { ! 1069: const char *azargs[4]; ! 1070: int oread, owrite; ! 1071: int aidescs[3]; ! 1072: pid_t ipid; ! 1073: ! 1074: azargs[0] = "/bin/sh"; ! 1075: if (zcmd == NULL || *zcmd == '\0') ! 1076: azargs[1] = NULL; ! 1077: else ! 1078: { ! 1079: azargs[1] = "-c"; ! 1080: azargs[2] = zcmd; ! 1081: azargs[3] = NULL; ! 1082: } ! 1083: ! 1084: if (qconn->qport == NULL) ! 1085: { ! 1086: oread = 0; ! 1087: owrite = 1; ! 1088: } ! 1089: else ! 1090: { ! 1091: switch (qconn->qport->uuconf_ttype) ! 1092: { ! 1093: default: ! 1094: oread = owrite = -1; ! 1095: break; ! 1096: case UUCONF_PORTTYPE_STDIN: ! 1097: oread = 0; ! 1098: owrite = 1; ! 1099: break; ! 1100: case UUCONF_PORTTYPE_MODEM: ! 1101: case UUCONF_PORTTYPE_DIRECT: ! 1102: case UUCONF_PORTTYPE_TCP: ! 1103: case UUCONF_PORTTYPE_TLI: ! 1104: oread = owrite = ((struct ssysdep_conn *) qconn->psysdep)->o; ! 1105: break; ! 1106: } ! 1107: } ! 1108: ! 1109: aidescs[0] = 0; ! 1110: aidescs[1] = 1; ! 1111: aidescs[2] = 2; ! 1112: ! 1113: if (tcmd == SHELL_STDIN_FROM_PORT || tcmd == SHELL_STDIO_ON_PORT) ! 1114: aidescs[0] = oread; ! 1115: if (tcmd == SHELL_STDOUT_TO_PORT || tcmd == SHELL_STDIO_ON_PORT) ! 1116: aidescs[1] = owrite; ! 1117: ! 1118: ipid = ixsspawn (azargs, aidescs, FALSE, TRUE, (const char *) NULL, ! 1119: FALSE, FALSE, (const char *) NULL, ! 1120: (const char *) NULL, (const char *) NULL); ! 1121: if (ipid < 0) ! 1122: { ! 1123: ulog (LOG_ERROR, "ixsspawn (/bin/sh): %s", strerror (errno)); ! 1124: return FALSE; ! 1125: } ! 1126: ! 1127: return ixswait ((unsigned long) ipid, "shell") == 0; ! 1128: } ! 1129: ! 1130: /* Change directories. */ ! 1131: ! 1132: boolean ! 1133: fsysdep_chdir (zdir) ! 1134: const char *zdir; ! 1135: { ! 1136: if (zdir == NULL || *zdir == '\0') ! 1137: { ! 1138: zdir = getenv ("HOME"); ! 1139: if (zdir == NULL) ! 1140: { ! 1141: ulog (LOG_ERROR, "HOME not defined"); ! 1142: return FALSE; ! 1143: } ! 1144: } ! 1145: if (chdir (zdir) < 0) ! 1146: { ! 1147: ulog (LOG_ERROR, "chdir (%s): %s", zdir, strerror (errno)); ! 1148: return FALSE; ! 1149: } ! 1150: return TRUE; ! 1151: } ! 1152: ! 1153: /* Suspend the current process. */ ! 1154: ! 1155: boolean ! 1156: fsysdep_suspend () ! 1157: { ! 1158: #ifndef SIGTSTP ! 1159: return fsysdep_terminal_puts ("[process suspension not supported]"); ! 1160: #else ! 1161: return kill (getpid (), SIGTSTP) == 0; ! 1162: #endif ! 1163: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.