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