Annotation of coherent/g/usr/lib/uucp/tay104/unix/cusub.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.