Annotation of coherent/g/usr/lib/uucp/tay104/unix/cusub.c, revision 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.