1: #ifndef lint
   2: static char RCSid[] = "$Header: gap2d.c,v 2.0 85/11/21 07:23:00 jqj Exp $";
   3: #endif
   4: /*
   5:  * server for GAP-style (TransportObject=server,teletype) telnet connections
   6:  * Note that we support only GAP version 2, although a server for version 3
   7:  * exists.  The version 2 server has not been tested as thoroughly as has the
   8:  * version 3; it does NOT support RESERVE functionality.
   9:  */
  10: 
  11: /* $Log:	gap2d.c,v $
  12:  * Revision 2.0  85/11/21  07:23:00  jqj
  13:  * 4.3BSD standard release
  14:  *
  15:  * Revision 1.2  85/05/23  06:22:18  jqj
  16:  * *** empty log message ***
  17:  *
  18:  * Revision 1.2  85/05/23  06:22:18  jqj
  19:  * *** empty log message ***
  20:  *
  21:  * Revision 1.1  85/05/22  09:46:52  jqj
  22:  * Initial revision
  23:  */
  24: #include <stdio.h>
  25: #include <signal.h>
  26: #include <sgtty.h>
  27: #include <sys/types.h>
  28: #include <sys/time.h>
  29: #include <sys/uio.h>
  30: #include <sys/socket.h>
  31: #include <netns/ns.h>
  32: #include <netns/idp.h>
  33: #include <netns/sp.h>
  34: #include <sys/wait.h>
  35: #include <xnscourier/realcourierconnection.h>
  36: #include "GAP2.h"
  37: #include "gapcontrols.h"
  38: #include <xnscourier/except.h>
  39: #include <errno.h>
  40: 
  41: #define BELL    '\07'
  42: #define BANNER  "\r\n\r\n4.3 BSD UNIX (%s)\r\n\r\r\n\r%s"
  43: 
  44: int pty, net;
  45: extern CourierConnection *_serverConnection;
  46: char buf[sizeof(struct sphdr)+SPPMAXDATA];
  47: struct sphdr our_sphdr;
  48: struct iovec our_iovec[2] = {{((caddr_t)&our_sphdr), sizeof(our_sphdr)}};
  49: /*
  50:  * I/O data buffers, pointers, and counters.
  51:  */
  52: char    ptyibuf[512], *ptyip = ptyibuf;
  53: char    ptyobuf[BUFSIZ], *pfrontp = ptyobuf, *pbackp = ptyobuf;
  54: char    *netip = buf;
  55: char    netobuf[512], *nfrontp = netobuf, *nbackp = netobuf;
  56: int pcc, ncc;
  57: char    line[12];
  58: extern  char **environ;
  59: extern  int errno;
  60: 
  61: char *envinit[3];
  62: char wsenv[50];
  63: 
  64: /*
  65:  * session parameters
  66:  */
  67: Cardinal frametimeout;      /* 0 or time in seconds to wait */
  68: 
  69: 
  70: /*
  71:  * This modified version of the server is necessary since GAP specifies
  72:  * that the telnet data-transfer session occurs after the RPC to create
  73:  * it has returned!
  74:  */
  75: Server(skipcount,skippedwords)
  76:     int skipcount;
  77:     Unspecified skippedwords[];
  78: {
  79:     Cardinal _procedure;
  80:     register Unspecified *_buf;
  81:     LongCardinal programnum;
  82:     Cardinal versionnum;
  83:     Cardinal _n;
  84: 
  85: #ifdef DEBUG
  86:     BUGOUT("Server: %d %d",skipcount,skippedwords);
  87: #endif
  88:     for (;;) {
  89:         _buf = ReceiveCallMessage(&_procedure, skipcount, skippedwords);
  90:         DURING switch (_procedure) {
  91:         case 3:
  92:             server_GAP2_Delete(_buf);
  93:             break;
  94:         case 2:
  95:             server_GAP2_Create(_buf);
  96:             net = _serverConnection->fd;
  97:             gaptelnet(); /* returns on connection close */
  98:             break;
  99:         case 0:
 100:             server_GAP2_Reset(_buf);
 101:             break;
 102:         default:
 103:             NoSuchProcedureValue("GAP", _procedure);
 104:             break;
 105:         } HANDLER {
 106:             Deallocate(_buf);
 107:             switch (Exception.Code) {
 108:             case GAP2_terminalAddressInvalid:
 109:             case GAP2_terminalAddressInUse:
 110:             case GAP2_controllerDoesNotExist:
 111:             case GAP2_controllerAlreadyExists:
 112:             case GAP2_gapCommunicationError:
 113:             case GAP2_gapNotExported:
 114:             case GAP2_bugInGAPCode:
 115:             case GAP2_tooManyGateStreams:
 116:             case GAP2_inconsistentParams:
 117:             case GAP2_transmissionMediumUnavailable:
 118:             case GAP2_dialingHardwareProblem:
 119:             case GAP2_noDialingHardware:
 120:             case GAP2_badAddressFormat:
 121:             case GAP2_mediumConnectFailed:
 122:             case GAP2_illegalTransport:
 123:             case GAP2_noCommunicationHardware:
 124:             case GAP2_unimplemented:
 125:             _buf = Allocate(0);
 126:             SendAbortMessage(Exception.Code-ERROR_OFFSET, 0, _buf);
 127:             break;
 128:             default:
 129:             _buf = Allocate(0);
 130:             SendRejectMessage(unspecifiedError, 0, _buf);
 131:             break;
 132:             }
 133:         } END_HANDLER;
 134:         Deallocate(_buf);
 135:         for (;;) {
 136:             skipcount = LookAheadCallMsg(&programnum, &versionnum,
 137:                     skippedwords);
 138:             if (skipcount < 0) return(0);   /* timed out */
 139:             if (programnum != 3 || versionnum != 2)
 140:                 ExecCourierProgram(programnum, versionnum,
 141:                         skipcount, skippedwords);
 142:         }  /* loop if can't exec that program */
 143:     }
 144: }
 145: 
 146: void
 147: GAP2_Delete(session)
 148:     GAP2_SessionHandle session;
 149: {
 150: }
 151: 
 152: void
 153: GAP2_Reset()
 154: {
 155: }
 156: 
 157: GAP2_CreateResults
 158: GAP2_Create(conn, BDTproc, sessionparams, transports,
 159:         createTimeout)
 160:     CourierConnection *conn;
 161:     int BDTproc;
 162:     GAP2_SessionParameterObject sessionparams;
 163:     struct {Cardinal length;
 164:         GAP2_TransportObject *sequence;
 165:     } transports;
 166:     GAP2_WaitTime createTimeout;
 167: {
 168:     GAP2_CreateResults result;
 169:     char *c1, *c2, *host;
 170:     int t, pid;
 171:     struct sgttyb b;
 172:     char *xntoa(), *wsname();
 173:     struct sockaddr_ns who;
 174:     int whosize = sizeof(who);
 175:     LongCardinal servicetype;
 176:     GAP2_CommParamObject *cp;
 177:     GAP2_Duplexity duplexity;   /* fullDuplex, halfDuplex */
 178: 
 179: #ifdef DEBUG
 180:     BUGOUT("CREATE");
 181: #endif
 182:     switch (sessionparams.designator) {
 183:     case ttyHost:
 184:         frametimeout = sessionparams.ttyHost_case.frameTimeout/1000;
 185:         /* could set other parameters here */
 186:         break;
 187:     default:
 188:         raise(GAP2_unimplemented, 0);
 189:         /*NOTREACHED*/
 190:     }
 191:     if (transports.length != 2) {
 192:         raise(GAP2_illegalTransport);
 193:         /*NOTREACHED*/
 194:     }
 195:     switch (transports.sequence[0].designator) {
 196:     case rs232c:    /* maybe some day */
 197:         cp = &transports.sequence[0].rs232c_case.commParams;
 198:         if (cp->accessDetail.designator == directConn) {
 199:             duplexity = cp->duplex;
 200:             servicetype = 0; /* fake it */
 201:             break;
 202:         }
 203:         raise(GAP2_noCommunicationHardware, 0);
 204:         /*NOTREACHED*/
 205:     default:
 206:         raise(GAP2_illegalTransport, 0);
 207:         /*NOTREACHED*/
 208:     }
 209:     if (transports.sequence[1].designator != teletype)
 210:       raise(GAP2_illegalTransport, 0);
 211:     /* ignore createTimeout */
 212:     /* ignore credentials and verifier */
 213: 
 214:     for (c1 = "pq"; *c1 != 0; c1++)
 215:       for (c2 = "0123456789abcdef"; *c2 != 0; c2++) {
 216:           sprintf(line, "/dev/pty%c%c", *c1, *c2);
 217:           pty = open(line, 2);
 218:           if (pty < 0) continue;
 219:           line[strlen("/dev/")] = 't';
 220:           t = open(line, 2);
 221:           if (t > 0) goto gotpty;
 222:           close(pty);
 223:       }
 224:     raise(GAP2_tooManyGateStreams, 0);
 225:     /*NOTREACHED*/
 226:  gotpty:
 227:     getpeername(_serverConnection->fd, &who, &whosize);
 228:     host = wsname(who.sns_addr);
 229: #ifdef DEBUG
 230:     BUGOUT("gotpty <%s> %d <%s>",line, pty, host);
 231: #endif
 232:     ioctl(t, TIOCGETP, &b);
 233:     b.sg_flags = CRMOD|XTABS|ANYP;
 234:     ioctl(t, TIOCSETP, &b);
 235:     ioctl(pty, TIOCGETP, &b);
 236:     if (duplexity == fullduplex)
 237:       b.sg_flags |= ECHO;
 238:     else
 239:       b.sg_flags &= ~ECHO;
 240:     ioctl(pty, TIOCSETP, &b);
 241:     /* we do the fork now so we can return failures as REPORTS */
 242:     pid = fork();
 243:     if (pid < 0) {
 244:         close(pty); close(t);
 245:         raise(GAP2_tooManyGateStreams, 0);
 246:         /*NOTREACHED*/
 247:     }
 248:     else if (pid == 0) {    /* in the execed fork */
 249:         sleep(1);   /* let parent get ready for us */
 250:         close(_serverConnection->fd); /* close net */
 251:         close(pty);
 252:         dup2(t, 0);
 253:         dup2(t, 1);
 254:         dup2(t, 2);
 255:         if (t > 2) close(t);
 256:         envinit[0] = "TERM=network";
 257:         envinit[1] = sprintf(wsenv, "WORKSTATION=%s",
 258:                      xntoa(who.sns_addr));
 259:         envinit[2] = (char*) 0;
 260: #ifdef DEBUG
 261:         BUGOUT("about to exec /bin/login");
 262: #endif
 263:         execl("/bin/login","login", "-h", host, 0);
 264: #ifdef DEBUG
 265:         BUGOUT("exec of /bin/login failed");
 266: #endif
 267:         perror("/bin/login");
 268:         exit(1);
 269:         /*NOTREACHED*/
 270:     }
 271:     close(t);
 272: #ifdef DEBUG
 273:     BUGOUT("fork successful");
 274: #endif
 275:     result.session[0] = pid;
 276:     return(result);
 277: }
 278: 
 279: jmp_buf childdiedbuf;
 280: 
 281: /*
 282:  * Main loop.  Select from pty and network, and
 283:  * hand data to telnet receiver finite state machine.
 284:  * Returns 0 on orderly shutdown, 1 on abnormal shutdown.
 285:  */
 286: gaptelnet()
 287: {
 288:     int on = 1;
 289:     char hostname[32];
 290:     int childdied();
 291:     int ibits = 0, obits = 0;
 292:     register int c;
 293:     struct sphdr *si = (struct sphdr *)buf;
 294:     static struct timeval timeout = {600,0};
 295:     int keepalives = 0;
 296:     int i;
 297: 
 298: #ifdef DEBUG
 299:     BUGOUT("gaptelnet net=%d,pty=%d",net,pty);
 300: #endif
 301:     if (setjmp(childdiedbuf) != 0)
 302:       return(0);        /* child died */
 303:     signal(SIGCHLD, childdied);
 304:     signal(SIGTSTP, SIG_IGN);
 305:     ioctl(net, FIONBIO, &on);
 306:     ioctl(pty, FIONBIO, &on);
 307: 
 308: 
 309:     /*
 310: 	 * Show banner that getty never gave.
 311: 	 */
 312:     gethostname(hostname, sizeof (hostname));
 313:     sprintf(nfrontp, BANNER, hostname, "");
 314:     nfrontp += strlen(nfrontp);
 315:     /*
 316: 	 * Send status message indicating we're ready to go
 317: 	 */
 318:     changeSPPopts(net, GAPCTLnone, 1);
 319:     sendoobdata(GAPCTLmediumUp);
 320:     for (;;) {
 321: #ifdef DEBUG
 322:         BUGOUT("looping in gaptelnet");
 323: #endif
 324:         ibits = obits = 0;
 325:         /*
 326: 		 * Never look for input if there's still
 327: 		 * stuff in the corresponding output buffer
 328: 		 */
 329:         if (nfrontp - nbackp || pcc > 0)
 330:             obits |= (1 << net);
 331:         else
 332:             ibits |= (1 << pty);
 333:         if (pfrontp - pbackp || ncc > 0)
 334:             obits |= (1 << pty);
 335:         else
 336:             ibits |= (1 << net);
 337:         if (ncc < 0 && pcc < 0)
 338:             break;
 339:         timeout.tv_sec = 600;
 340:         timeout.tv_usec = 0;
 341:         select(16, &ibits, &obits, 0, &timeout);
 342:         if (ibits == 0 && obits == 0) {
 343:             /* timeout means no activity for a long time */
 344: #ifdef DEBUG
 345:             BUGOUT("timeout from select");
 346: #endif
 347:             if (keepalives++ < 2) {
 348:               /* first 2 times through send warning */
 349:                 if (nfrontp == nbackp && pcc == 0) {
 350:                     /* but only if not blocked on output */
 351: #define WARNING "\r\nYou've been idle much too long.  Respond or log off.\r\n"
 352:                     strcpy(nfrontp, WARNING);
 353:                     nfrontp += sizeof(WARNING);
 354:                 }
 355:                 sleep(5);
 356:                 continue;
 357:             }
 358: #ifdef DEBUG
 359:             BUGOUT("keepalive expired -- calling cleanup");
 360: #endif
 361:             /* keepalive count has expired */
 362:             cleanup();
 363:             return(1);
 364:         }
 365: 
 366:         /*
 367: 		 * Something to read from the network...
 368: 		 */
 369:         if (ibits & (1 << net)) {
 370:             ncc = read(net, buf, sizeof(buf));
 371: #ifdef DEBUG
 372:             BUGOUT("read from net %d",ncc);
 373: #endif
 374:             if (ncc < 0 && errno == EWOULDBLOCK)
 375:                 ncc = 0;
 376:             else if (ncc < sizeof(struct sphdr)) {
 377: #ifdef DEBUG
 378:                 BUGOUT("short read, %d.  calling cleanup",ncc);
 379: #endif
 380:                 cleanup(); /* will probably fail or block */
 381:                 return(1);
 382:             }
 383:             else if (si->sp_cc & SP_OB) {
 384:                 /* a status or OOB control */
 385:                 switch (buf[sizeof(struct sphdr)]) {
 386:                 case GAPCTLinterrupt:
 387:                     /* shove interrupt char in buffer */
 388:                     interrupt();
 389:                     break; /* from switch */
 390:                 case GAPCTLareYouThere:
 391:                     sendoobdata(GAPCTLiAmHere);
 392:                     break; /* from switch */
 393:                 default:
 394:                     /* Ignore other controls instead of:
 395: 					 * sendoobdata(
 396: 					 *     GAPCTLunexpectedRemoteBehavior);
 397: 					 */
 398:                     break; /* from switch */
 399:                 }
 400:                 ncc = 0; /* no chars here */
 401:             }
 402:             else if (si->sp_dt==GAPCTLnone) {
 403:                 /* the normal case */
 404:                 ncc -= sizeof(struct sphdr);
 405:                 netip = buf + sizeof(struct sphdr);
 406:                 keepalives = 0;
 407:             }
 408:             else if(si->sp_dt==GAPCTLcleanup) {
 409: #ifdef DEBUG
 410:                 BUGOUT("got CLEANUP packet.  Done");
 411: #endif
 412:                 cleanup(); /* normal termination */
 413:                 return(0);
 414:             }
 415:             else if (si->sp_dt==SPPSST_END) {
 416:                 /* got premature termination */
 417:                 quitquit(net, pty);
 418:                 return(1);
 419:             }
 420:         }
 421: 
 422:         /*
 423: 		 * Something to read from the pty...
 424: 		 */
 425:         if (ibits & (1 << pty)) {
 426:             if (frametimeout > 0) sleep(frametimeout);
 427:             pcc = read(pty, ptyibuf, sizeof(ptyibuf));
 428: #ifdef DEBUG
 429:             BUGOUT("read from pty %d",pcc);
 430: #endif
 431:             if (pcc < 0 && errno == EWOULDBLOCK)
 432:                 pcc = 0;
 433:             else if (pcc <= 0) {
 434: #ifdef DEBUG
 435:                 BUGOUT("short read from pty. Calling cleanup");
 436: #endif
 437:                 cleanup();
 438:                 return(1); /* ?? abnormal termination */
 439:             }
 440:             ptyip = ptyibuf;
 441:         }
 442: 
 443:         while (pcc > 0) {
 444:             if ((&netobuf[sizeof(netobuf)] - nfrontp) < 2)
 445:                 break;
 446:             *nfrontp++ = *ptyip++ & 0377; pcc--;
 447:         }
 448:         if ((obits & (1 << net)) && (nfrontp - nbackp) > 0)
 449:             netflush();
 450:         while (ncc > 0) {
 451:             if ((&ptyobuf[sizeof(ptyobuf)] - pfrontp) < 2) break;
 452:             *pfrontp++ = *netip++ & 0377;
 453:             ncc--;
 454:         }
 455:         if ((obits & (1 << pty)) && (pfrontp - pbackp) > 0)
 456:             ptyflush();
 457:     }
 458:     /* we should never get to here */
 459: #ifdef DEBUG
 460:     BUGOUT("broke out of for(;;) somehow.  calling cleanup");
 461: #endif
 462:     cleanup();
 463:     return(0);
 464: }
 465: 
 466: /*
 467:  * Send out of band data to other end of network
 468:  */
 469: sendoobdata(value)
 470:     u_char value;
 471: {
 472:     struct {
 473:         struct sphdr hdr;
 474:         char val;
 475:     } oob;
 476:     oob.hdr = our_sphdr;
 477:     oob.val = value;
 478: #ifdef DEBUG
 479:     BUGOUT("sendoobdata 0%o",value);
 480: #endif
 481:     send(net, &oob, sizeof(oob), MSG_OOB);
 482: }
 483: 
 484: /*
 485:  * Send interrupt to process on other side of pty.
 486:  * If it is in raw mode, just write NULL;
 487:  * otherwise, write intr char.
 488:  */
 489: interrupt()
 490: {
 491:     struct sgttyb b;
 492:     struct tchars tchars;
 493: 
 494:     ptyflush(); /* half-hearted */
 495:     ioctl(pty, TIOCGETP, &b);
 496:     if (b.sg_flags & RAW) {
 497:         *pfrontp++ = '\0';
 498:         return;
 499:     }
 500:     *pfrontp++ = ioctl(pty, TIOCGETC, &tchars) < 0 ?
 501:         '\177' : tchars.t_intrc;
 502: }
 503: 
 504: ptyflush()
 505: {
 506:     register int n;
 507: 
 508:     if ((n = pfrontp - pbackp) > 0)
 509:         n = write(pty, pbackp, n);
 510: #ifdef DEBUG
 511:     BUGOUT("ptyflush wrote %d",n);
 512: #endif
 513:     if (n < 0)
 514:         return;
 515:     pbackp += n;
 516:     if (pbackp >= pfrontp)  /* actually, > is an error */
 517:         pbackp = pfrontp = ptyobuf;
 518: }
 519: 
 520: netflush()
 521: {
 522:     register int n;
 523: 
 524:     if ((n = nfrontp - nbackp) > 0) {
 525:         our_iovec[1].iov_len = ((n > SPPMAXDATA) ? SPPMAXDATA : n);
 526:         our_iovec[1].iov_base = nbackp;
 527:         n = writev(net, our_iovec, 2) - sizeof(struct sphdr);
 528:     }
 529: #ifdef DEBUG
 530:     BUGOUT("netflush wrote %d",n);
 531:     if (our_iovec[0].iov_base != (char*)&our_sphdr)
 532:         BUGOUT("Oops:  our_iovec clobbered");
 533:     BUGOUT("header: %d %d, %d %d %d %d %d %d",
 534:         our_sphdr.sp_cc, our_sphdr.sp_dt,
 535:         our_sphdr.sp_sid, our_sphdr.sp_did, our_sphdr.sp_seq,
 536:         our_sphdr.sp_ack, our_sphdr.sp_alo);
 537: #endif
 538:     if (n < 0) {
 539:         if (errno == EWOULDBLOCK)
 540:             return;
 541:         /* should blow this guy away... */
 542:         return;
 543:     }
 544:     nbackp += n;
 545:     if (nbackp >= nfrontp)  /* actually , > is an error */
 546:         nbackp = nfrontp = netobuf;
 547: }
 548: 
 549: /*
 550:  * handle receipt of an SPPSST_END packet
 551:  * This is currently an error, since client didn't send "cleanup" first
 552:  */
 553: quitquit()
 554: {
 555:     changeSPPopts(net, SPPSST_ENDREPLY, 1);
 556:     write(net, &our_sphdr, sizeof(our_sphdr));
 557:     sleep(3);
 558: 
 559:     rmut();
 560:     vhangup();  /* XXX */
 561:     shutdown(net, 1);
 562:     close(net);
 563: }
 564: 
 565: /*
 566:  * shut down the data connection for one reason or another
 567:  */
 568: cleanup()
 569: {
 570:     int fdmask;
 571:     struct timeval timeout;
 572:     struct sphdr *si = (struct sphdr *)buf;
 573:     int off = 0;
 574: 
 575:     signal(SIGCHLD, SIG_IGN);
 576:     sendoobdata(GAPCTLcleanup);
 577:     changeSPPopts(net, SPPSST_END, 1);
 578:     if (write(net, &our_sphdr, sizeof(our_sphdr)) < 0) {
 579:         fdmask = 1<<net;
 580:         timeout.tv_sec = 10;
 581:         while (select(net+1,&fdmask,(int*)0, (int*)0, &timeout) > 0 &&
 582:                read(net,buf,sizeof(buf)) >= sizeof(struct sphdr)) {
 583: #ifdef DEBUG
 584:             BUGOUT("cleanup -- got packet");
 585: #endif
 586:             if ((si->sp_cc & SP_OB)
 587:                 && si->sp_dt == SPPSST_ENDREPLY) {
 588:                 changeSPPopts(net, SPPSST_ENDREPLY, 1);
 589:                 write(net, &our_sphdr, sizeof(our_sphdr));
 590: #ifdef DEBUG
 591:                 BUGOUT("cleanup -- wrote ENDREPLY");
 592: #endif
 593:                 sleep(1);
 594:                 changeSPPopts(net,0,0);
 595:                 ioctl(net, FIONBIO, &off);
 596:                 rmut();
 597:                 vhangup();  /* XXX */
 598:                 return;
 599:             }
 600:             /* loop: ignore everything except ENDREPLY */
 601:             fdmask = 1<<net;
 602:             timeout.tv_sec = 10;
 603:         }
 604:         /* timed out or read failed */
 605:         changeSPPopts(net, SPPSST_ENDREPLY, 1);
 606:         write(net, &our_sphdr, sizeof(our_sphdr));
 607:         sleep(1);
 608:     }
 609:     shutdown(net, 1);
 610:     close(net);
 611:     rmut();
 612:     vhangup();  /* XXX */
 613: }
 614: 
 615: /*
 616:  * SIGCHLD interrupt handler
 617:  */
 618: childdied()
 619: {
 620: #ifdef DEBUG
 621:     BUGOUT("child died");
 622: #endif
 623:     cleanup();
 624:     longjmp(childdiedbuf, -1);
 625: }
 626: 
 627: changeSPPopts(s, stream, eom)
 628:     int s;          /* SPP socket */
 629:     u_char stream;      /* datastream type */
 630:     char eom;       /* Boolean EOM */
 631: {
 632:     our_sphdr.sp_dt = stream;
 633:     our_sphdr.sp_cc = (eom ? SP_EM : 0);
 634: }
 635: 
 636: 
 637: #include <utmp.h>
 638: 
 639: struct  utmp wtmp;
 640: char    wtmpf[] = "/usr/adm/wtmp";
 641: char    utmp[] = "/etc/utmp";
 642: #define SCPYN(a, b) strncpy(a, b, sizeof (a))
 643: #define SCMPN(a, b) strncmp(a, b, sizeof (a))
 644: 
 645: rmut()
 646: {
 647:     register f;
 648:     int found = 0;
 649: 
 650:     f = open(utmp, 2);
 651:     if (f >= 0) {
 652:         while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) {
 653:             if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0)
 654:                 continue;
 655:             lseek(f, -(long)sizeof (wtmp), 1);
 656:             SCPYN(wtmp.ut_name, "");
 657:             SCPYN(wtmp.ut_host, "");
 658:             time(&wtmp.ut_time);
 659:             write(f, (char *)&wtmp, sizeof (wtmp));
 660:             found++;
 661:         }
 662:         close(f);
 663:     }
 664:     if (found) {
 665:         f = open(wtmpf, 1);
 666:         if (f >= 0) {
 667:             SCPYN(wtmp.ut_line, line+5);
 668:             SCPYN(wtmp.ut_name, "");
 669:             SCPYN(wtmp.ut_host, "");
 670:             time(&wtmp.ut_time);
 671:             lseek(f, (long)0, 2);
 672:             write(f, (char *)&wtmp, sizeof (wtmp));
 673:             close(f);
 674:         }
 675:     }
 676:     chmod(line, 0666);
 677:     chown(line, 0, 0);
 678:     line[strlen("/dev/")] = 'p';
 679:     chmod(line, 0666);
 680:     chown(line, 0, 0);
 681: }
 682: 
 683: /*
 684:  * Convert network-format xns address
 685:  * to ascii
 686:  * --Replace this with a clearinghouse name lookup someday.
 687:  */
 688: char *
 689: wsname(addr)
 690:     struct ns_addr addr;
 691: {
 692:     static char b[50];
 693:     char temp[10];
 694:     int i;
 695: 
 696:     /* net */
 697:     sprintf(b, "%D.", ntohl(ns_netof(addr)));
 698:     /* skip leading zeros */
 699:     for(i=0; (addr.x_host.c_host[i] == (char) 0); i++) ;
 700:     /* print the rest */
 701:     for(; i < 6; i++) {
 702:         sprintf(temp,"%x", addr.x_host.c_host[i]);
 703:         strcat(b, temp);
 704:         if(i != 5) strcat(b, ":");
 705:     }
 706:     return (b);
 707: }
 708: 
 709: /*
 710:   * generate an xns address that "DE" can parse.
 711:   * This goes in the environment.  Should be the same as above
 712:   */
 713: char *
 714: xntoa(addr)
 715:     struct ns_addr addr;
 716: {
 717:     static char b[50];
 718:     char temp[10];
 719:     int i;
 720: 
 721:     /* net */
 722:     sprintf(b, "%X#", ntohl(ns_netof(addr)));
 723:     /* print the rest */
 724:     for(i=0; i < 6; i++) {
 725:         sprintf(temp,"%x", addr.x_host.c_host[i]);
 726:         strcat(b, temp);
 727:         if(i != 5) strcat(b, ".");
 728:     }
 729:     return (b);
 730: }
 731: 
 732: #ifdef DEBUG
 733: BUGOUT(str,a,b,c,d,e,f,g,h)
 734:     char *str;
 735: {
 736:     FILE *fd;
 737:     fd = fopen("/tmp/GAP2d.log","a");
 738:     fprintf(fd,str,a,b,c,d,e,f,g,h);
 739:     putc('\n',fd);
 740:     fclose(fd);
 741: }
 742: #endif

Defined functions

BUGOUT defined in line 733; used 24 times
GAP2_Create defined in line 157; never used
GAP2_Delete defined in line 146; never used
GAP2_Reset defined in line 152; never used
Server defined in line 75; never used
changeSPPopts defined in line 627; used 6 times
childdied defined in line 618; used 2 times
cleanup defined in line 568; used 6 times
gaptelnet defined in line 286; used 1 times
  • in line 97
interrupt defined in line 489; used 1 times
netflush defined in line 520; used 1 times
ptyflush defined in line 504; used 2 times
quitquit defined in line 553; used 1 times
rmut defined in line 645; used 3 times
sendoobdata defined in line 469; used 3 times
wsname defined in line 688; used 2 times
xntoa defined in line 713; used 2 times

Defined variables

GAP2_CreateResults defined in line 157; used 1 times
RCSid defined in line 2; never used
buf defined in line 46; used 9 times
envinit defined in line 61; used 3 times
line defined in line 57; used 12 times
ncc defined in line 56; used 12 times
net defined in line 44; used 30 times
netip defined in line 54; used 2 times
netobuf defined in line 55; used 5 times
nfrontp defined in line 55; used 13 times
our_iovec defined in line 48; used 4 times
our_sphdr defined in line 47; used 21 times
pcc defined in line 56; used 10 times
pfrontp defined in line 53; used 9 times
pty defined in line 44; used 19 times
ptyibuf defined in line 52; used 4 times
ptyip defined in line 52; used 2 times
ptyobuf defined in line 53; used 5 times
utmp defined in line 641; used 1 times
wsenv defined in line 62; used 1 times
wtmp defined in line 639; used 17 times
wtmpf defined in line 640; used 1 times

Defined macros

BANNER defined in line 42; used 1 times
BELL defined in line 41; never used
SCMPN defined in line 643; used 1 times
SCPYN defined in line 642; used 5 times
WARNING defined in line 351; used 2 times
Last modified: 1986-03-13
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 2994
Valid CSS Valid XHTML 1.0 Strict