1 /* 2 * X.29 server 3 * 4 * Frank Pronk (...!ubc-vision!pronk) 5 * April, September 1984 6 * 7 * Laboratory for Computational Vision 8 * University of British Columbia 9 * Copyright (c) 10 */ 11 12 #include <sys/param.h> 13 #include <sys/socket.h> 14 #include <sys/stat.h> 15 #include <sys/wait.h> 16 17 #include <netccitt/x25.h> 18 19 #include <errno.h> 20 #include <netdb.h> 21 #include <sgtty.h> 22 #include <signal.h> 23 24 #include "../h/x29.h" 25 26 #define BUFSIZ 1024 27 #define MAXARGS 10 /* maximum size of server argument list */ 28 29 #define X25NET 0 /* no ITI parameters */ 30 #define CCITT1978 1 /* 1978 CCITT standard parameter set */ 31 #define CCITT1980 2 /* 1980 CCITT standard parameter set */ 32 33 34 char pibuf[BUFSIZ], fibuf[BUFSIZ]; 35 int pty, net; 36 extern char **environ; 37 extern int errno; 38 char line[sizeof("/dev/ptyp0")]; 39 char console[] = "/dev/console"; 40 short packet_size; 41 char *tracefn; /* trace file name */ 42 char *server; 43 short send_banner; 44 struct sockaddr_x25 sock; 45 46 int reapchild(); 47 struct net *lookup (); 48 49 char ccitt1978_prof[] = { /* initial profile */ 50 Q_BIT, X29_SET_AND_READ_PARMS, 51 X29_ECHO_CODE, 1, /* echo on */ 52 X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */ 53 X29_IDLE_TIMER_CODE, 0, /* off */ 54 X29_AUX_DEV_CONTROL_CODE, 0, /* off */ 55 X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */ 56 X29_BREAK_PROCEDURE_CODE, 21, 57 X29_PADDING_CODE, 0, /* off */ 58 X29_LINE_FOLDING_CODE, 0, /* off */ 59 X29_TRANSMISSION_SPEED_CODE, 0, 60 X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */ 61 }; 62 63 char ccitt1980_prof[] = { /* initial profile */ 64 Q_BIT, X29_SET_AND_READ_PARMS, 65 X29_ECHO_CODE, 1, /* echo on */ 66 X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */ 67 X29_IDLE_TIMER_CODE, 0, /* off */ 68 X29_AUX_DEV_CONTROL_CODE, 0, /* off */ 69 X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */ 70 X29_BREAK_PROCEDURE_CODE, 21, 71 X29_PADDING_CODE, 0, /* off */ 72 X29_LINE_FOLDING_CODE, 0, /* off */ 73 X29_TRANSMISSION_SPEED_CODE, 0, 74 X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */ 75 76 X29_LF_AFTER_CR, 4, /* lf after cr from terminal */ 77 X29_EDITING, 1, /* on */ 78 X29_CHARACTER_DELETE, CERASE, 79 X29_LINE_DELETE, CKILL, 80 X29_LINE_DISPLAY, CRPRNT, 81 }; 82 83 char datapac_prof[] = { /* Canadian X.25 network */ 84 Q_BIT, X29_SET_AND_READ_PARMS, 85 X29_ECHO_CODE, 1, /* echo on */ 86 X29_FORWARDING_SIGNAL_CODE, 126, /* forward on all cntl */ 87 X29_IDLE_TIMER_CODE, 0, /* off */ 88 X29_AUX_DEV_CONTROL_CODE, 0, /* off */ 89 X29_RECEIVE_NET_MSGS_CODE, 1, /* xmit network msgs */ 90 X29_BREAK_PROCEDURE_CODE, 21, 91 X29_PADDING_CODE, 0, /* off */ 92 X29_LINE_FOLDING_CODE, 0, /* off */ 93 X29_TRANSMISSION_SPEED_CODE, 0, 94 X29_XON_XOFF_CODE, 1, /* enable XON/XOFF */ 95 96 X29_LF_AFTER_CR, 4, /* lf after cr from terminal */ 97 X29_EDITING, 1, /* on */ 98 X29_CHARACTER_DELETE, CERASE, 99 X29_LINE_DELETE, CKILL, 100 X29_LINE_DISPLAY, CRPRNT, 101 102 /* 103 * This rubbish can be removed when Datapac 104 * adopts the 1980 standard parameter set. 105 */ 106 107 0, 0, /* national parameter marker */ 108 123, 0, /* parity off */ 109 }; 110 111 struct net { 112 char *n_name; /* generic name */ 113 short n_type; /* see defines above */ 114 char *n_profile; /* initial profile */ 115 short n_proflen; /* length of n_profile */ 116 } *netp, nets[] = { 117 "x.25", X25NET, 0, 0, 118 "1978", CCITT1978, ccitt1978_prof, sizeof(ccitt1978_prof), 119 "ccitt1978", CCITT1978, ccitt1978_prof, sizeof(ccitt1978_prof), 120 "1980", CCITT1980, ccitt1980_prof, sizeof(ccitt1980_prof), 121 "ccitt1980", CCITT1980, ccitt1980_prof, sizeof(ccitt1980_prof), 122 "datapac", CCITT1980, datapac_prof, sizeof(datapac_prof), 123 0, 0, 0, 0 124 }; 125 126 main(argc, argv) 127 register char **argv; 128 { 129 register int s, pid; 130 register char *p; 131 132 #ifdef waterloo 133 /* 134 * If this host doesn't support X.25, give up. 135 */ 136 s = socket(AF_CCITT, SOCK_STREAM, 0); 137 if (s < 0 && errno == EPROTONOSUPPORT) 138 fatal(2, "X.25 is not supported on this machine"); 139 close(s); 140 #endif 141 netp = lookup ("ccitt1978"); 142 sock.x25_family = AF_CCITT; 143 sock.x25_opts.op_flags = X25_MQBIT; 144 sock.x25_udata[0] = ITI_CALL; 145 sock.x25_udlen = 4; 146 147 for (argv++; argc > 1; argc--, argv++) 148 if (**argv == '-') 149 for (p = *argv+1; *p; p++) 150 switch (*p) { 151 case 'b': 152 send_banner++; 153 break; 154 155 case 'c': 156 if (argc > 1) { 157 argc--; argv++; 158 if ((netp = lookup (*argv)) == 0) 159 fatal(1, "Unknown network type"); 160 } 161 break; 162 163 case 'p': 164 if (argc > 1) { 165 argc--; argv++; 166 strcpy (sock.x25_udata, *argv); 167 } 168 break; 169 170 case 'r': 171 sock.x25_opts.op_flags |= X25_REVERSE_CHARGE; 172 break; 173 174 case 't': 175 if (argc > 1) { 176 argc--; argv++; 177 tracefn = *argv; 178 } 179 else fatal(1, "missing trace file"); 180 break; 181 182 default: 183 fatal (1, "usage: x29d -b -c nettype -p protocol -r -t trace_file server"); 184 } 185 else 186 server = *argv; 187 if (server == 0) 188 fatal (1, "no server specified"); 189 if (fork()) 190 exit(0); 191 for (s = 0; s < 10; s++) 192 (void) close(s); 193 (void) open("/", 0); 194 (void) dup2(0, 1); 195 (void) dup2(0, 2); 196 { int tt = open("/dev/tty", 2); 197 if (tt > 0) { 198 ioctl(tt, TIOCNOTTY, (char *)0); 199 close(tt); 200 } 201 } 202 203 while((s = socket(AF_CCITT, SOCK_STREAM, 0)) < 0) 204 sleep(60); 205 while (bind(s, (caddr_t)&sock, sizeof (sock)) < 0) 206 sleep(60); 207 signal(SIGCHLD, reapchild); 208 listen(s, 5); 209 210 for (;;) { 211 struct sockaddr_x25 from; 212 int fromlen = sizeof (from); 213 214 if ((net = accept(s, (caddr_t)&from, &fromlen)) < 0) { 215 if (errno != EINTR) 216 sleep (60); 217 continue; 218 } 219 while ((pid = fork()) < 0) 220 sleep(60); 221 if (pid == 0) { 222 signal(SIGCHLD, SIG_DFL); 223 doit(&from); 224 } 225 close(net); 226 } 227 /*NOTREACHED*/ 228 } 229 230 struct net * 231 lookup (name) 232 char *name; 233 { 234 register struct net *np; 235 236 for (np = nets; np->n_name; np++) 237 if (strcmp (np->n_name, name) == 0) 238 return (np); 239 return (0); 240 } 241 242 reapchild() 243 { 244 union wait status; 245 246 while (wait3(&status, WNOHANG, 0) > 0) 247 ; 248 } 249 250 char *envinit[] = { "TERM=ccitt", 0 }; 251 int cleanup(); 252 253 /* 254 * Get a pty, scan input lines. 255 */ 256 doit(who) 257 struct sockaddr_x25 *who; 258 { 259 register char *cp; 260 register int i, p, t; 261 struct sgttyb b; 262 struct stat sb; 263 264 strcpy(line, "/dev/ptyp0"); 265 cp = line; 266 for (t = 'p'; ; t++) { 267 cp[strlen("/dev/pty")] = t; 268 if (stat(line, &sb) < 0) 269 break; 270 for (i = 0; i < 16; i++) { 271 cp[strlen("/dev/ptyp")] = "0123456789abcdef"[i]; 272 p = open(cp, 2); 273 if (p > 0) 274 goto gotpty; 275 } 276 } 277 fatal(net, "All pty ports in use"); 278 /*NOTREACHED*/ 279 gotpty: 280 pty = p; 281 (void) dup2(net, 0); 282 cp[strlen("/dev/")] = 't'; 283 t = open("/dev/tty", 2); 284 if (t >= 0) { 285 ioctl(t, TIOCNOTTY, (char *)0); 286 close(t); 287 } 288 t = open(cp, 2); /* slave side of pty */ 289 if (t < 0) 290 fatalperror(cp, errno); 291 ioctl(t, TIOCGETP, (char *)&b); 292 b.sg_flags = CRMOD|XTABS|ANYP|ECHO; 293 ioctl(t, TIOCSETP, &b); 294 packet_size = 1 << who->x25_opts.op_psize; 295 if ((i = fork()) < 0) 296 fatalperror("fork", errno); 297 if (i) 298 x29d(); 299 close(net); 300 close(p); 301 (void) dup2(t, 0); 302 (void) dup2(t, 1); 303 (void) dup2(t, 2); 304 close(t); 305 environ = envinit; 306 call_server (who); 307 /*NOTREACHED*/ 308 } 309 310 call_server (who) 311 struct sockaddr_x25 *who; 312 { 313 register struct hostent *hp = 0; 314 register char *p, **ap; 315 char *args[MAXARGS]; 316 struct stat st; 317 struct hostent *getx25hostbyaddr(); 318 int ccitt = 0; 319 320 p = server; 321 while (*p && *p != ' ' && *p != '\t') /* split program from args */ 322 p++; 323 if (*p) 324 *p++ = '\0'; 325 ap = args; 326 while (*p) { 327 while (*p == ' ' || *p == '\t') 328 p++; 329 if (ap < &args[MAXARGS-2]) 330 *ap++ = p; 331 if (strcmp(p, "-ccitt") == 0) 332 ccitt = 1; 333 while (*p && *p != ' ' && *p != '\t') 334 p++; 335 if (*p) 336 *p++ = '\0'; 337 } 338 if (stat (server, &st) < 0) 339 fatalperror (server, errno); 340 /* 341 * For security: if running as root, switch to user 342 * and group id of server. This prevents privately 343 * maintainted or bogus servers from getting super- 344 * user permissions. 345 */ 346 if (getuid() == 0) { 347 setgid (st.st_gid); 348 setuid (st.st_uid); 349 } 350 if (hp = getx25hostbyaddr (who->x25_addr)) 351 *ap++ = hp->h_name; 352 else 353 *ap++ = (char *)who->x25_addr; 354 /* 355 * If the -ccitt flag was given, add another argument 356 * to tell login if charging is being reversed or not. 357 */ 358 if (ccitt) 359 *ap++ = (who->x25_opts.op_flags & X25_REVERSE_CHARGE) ? "y" : "n"; 360 *ap = 0; 361 execv (server, args); 362 fatalperror (server, errno); 363 /*NOTREACHED*/ 364 } 365 366 fatal(f, msg) 367 int f; 368 char *msg; 369 { 370 register char *p; 371 char buf[BUFSIZ], *index(); 372 373 p = buf; 374 if (f == net) 375 *p++ = 0; 376 strcpy(p, "x29d: "); 377 strcat(p, msg); 378 strcat(p, "\n"); 379 (void) write(f, p, (index(p, '\n')-p)+1); 380 exit(1); 381 } 382 383 fatalperror(msg, err) 384 char *msg; 385 { 386 char buf[BUFSIZ]; 387 extern char *sys_errlist[]; 388 389 strcpy(buf, msg); 390 strcat(buf, ": "); 391 strcat(buf, sys_errlist[err]); 392 fatal(net, buf); 393 } 394 395 /* 396 * Main loop. Select from pty and network, and 397 * hand data to iti receiver. 398 */ 399 x29d() 400 { 401 register int pcc, fcc, cc; 402 register char *fbp; 403 int pgrp, x25_interrupt(), on = 1; 404 char hostname[32]; 405 406 ioctl(net, FIONBIO, (char *)&on); 407 ioctl(pty, FIONBIO, (char *)&on); 408 ioctl(pty, TIOCPKT, (char *)&on); 409 ioctl(pty, TIOCREMECHO, (char *)&on); /* enable special pty mode */ 410 signal(SIGPIPE, SIG_IGN); /* why not cleanup? --kwl */ 411 signal(SIGTSTP, SIG_IGN); 412 signal(SIGCHLD, cleanup); 413 signal(SIGHUP, cleanup); 414 415 signal(SIGTTOU, SIG_IGN); 416 signal(SIGURG, x25_interrupt); /* for out-of-band data */ 417 pgrp = -getpgrp(0); 418 ioctl(net, SIOCSPGRP, (char *)&pgrp); 419 420 if (netp->n_proflen) 421 (void) write(net, netp->n_profile, netp->n_proflen); 422 423 /* 424 * Show banner that getty never gave. 425 */ 426 if (send_banner) { 427 gethostname(hostname, sizeof (hostname)); 428 #ifdef BSD4_3 429 strcpy(pibuf+1, "\r\n\r\n4.3 BSD UNIX ("); 430 #else 431 strcpy(pibuf+1, "\r\n\r\n4.2 BSD UNIX ("); 432 #endif 433 strcat(pibuf+1, hostname); 434 strcat(pibuf+1, ")\r\n\r\n"); 435 pcc = strlen(pibuf+1) + 1; 436 } else 437 pcc = 0; 438 439 fcc = 0; 440 for (;;) { 441 int ibits, obits; 442 443 ibits = obits = 0; 444 /* 445 * Never look for input if there's still 446 * stuff in the corresponding output buffer 447 */ 448 if (fcc >= 0) /* net connection alive? */ 449 if (fcc && pcc >= 0) /* output pending? */ 450 obits |= (1 << pty); 451 else 452 if (pcc >= 0) /* pty still alive? */ 453 ibits |= (1 << net); 454 if (pcc >= 0) /* pty connection alive? */ 455 if (pcc && fcc >= 0) /* output pending? */ 456 obits |= (1 << net); 457 else 458 if (fcc >= 0) /* net still alive? */ 459 ibits |= (1 << pty); 460 if(ibits == 0 && obits == 0) 461 break; 462 (void) select(16, &ibits, &obits, (int *)0, 0); 463 if (ibits == 0 && obits == 0) { 464 sleep(5); 465 continue; 466 } 467 468 /* 469 * Something to read from the network... 470 */ 471 if (ibits & (1 << net)) { 472 fcc = read(net, fibuf, BUFSIZ); 473 fbp = fibuf+1; 474 if (fcc < 0 && errno == EWOULDBLOCK) 475 fcc = 0; 476 else if(fcc <= 0) 477 fcc = -1; 478 else { 479 if (tracefn) 480 x29d_trace("netread", fibuf, fcc); 481 if(fibuf[0] & Q_BIT) { 482 x29_qbit(fcc); 483 fcc = 0; 484 } else 485 fcc--; 486 } 487 } 488 489 /* 490 * Something to read from the pty... 491 */ 492 if (ibits & (1 << pty)) { 493 pcc = read(pty, pibuf, packet_size+1); 494 if (pcc < 0 && errno == EWOULDBLOCK) 495 pcc = 0; 496 else if (pcc <= 0) 497 pcc = -1; 498 else if(pibuf[0] != 0) { /* non-data packet */ 499 if (pibuf[0] & TIOCPKT_IOCTL) 500 pcc = set_x29_parameters(); 501 else 502 pcc = 0; 503 } else /* data packet */ 504 pibuf[0] = 0; 505 } 506 507 if ((obits & (1<<net)) && pcc > 0) 508 if((cc = write(net, pibuf, pcc)) == pcc) { 509 if(tracefn) 510 x29d_trace("netwrite", pibuf, pcc); 511 pcc = 0; 512 } else { 513 extern char *sys_errlist[]; 514 515 if(tracefn) 516 x29d_trace("netwrite", 517 sys_errlist[errno], 518 strlen(sys_errlist[errno])); 519 520 } 521 522 if ((obits & (1 << pty)) && fcc > 0) { 523 cc = write(pty, fbp, fcc); 524 if (cc > 0) { 525 fcc -= cc; 526 fbp += cc; 527 } 528 } 529 } 530 cleanup(); 531 } 532 533 534 /* 535 * Send interrupt to process on other side of pty. 536 * If it is in raw mode, just write NULL; 537 * otherwise, write intr char. 538 */ 539 540 x25_interrupt() 541 { 542 struct sgttyb b; 543 struct tchars tchars; 544 int zero = 0; 545 546 signal(SIGURG, x25_interrupt); 547 ioctl(pty, TIOCGETP, (char *)&b); 548 if (b.sg_flags & RAW) 549 (void) write(pty, "\0", 1); 550 else { 551 ioctl(pty, TIOCFLUSH, (char *)&zero); 552 ioctl(pty, TIOCGETC, (char *)&tchars); 553 (void) write(pty, &tchars.t_intrc, 1); 554 } 555 } 556 557 cleanup() 558 { 559 struct sgttyb sg; 560 struct stat st; 561 562 ioctl(pty, TIOCGETP, (char *)&sg); /* flushes output buffer */ 563 ioctl(pty, TIOCSETP, (char *)&sg); 564 (void) stat(line, &st); 565 rmut(); 566 vhangup(); /* XXX */ 567 setuid(st.st_uid); 568 exit(1); 569 } 570 571 /* 572 * Map unix tty modes and special characters 573 * into x29 parameters. 574 */ 575 576 set_x29_parameters() 577 { 578 register char *p; 579 register int f; 580 struct sgttyb b; 581 582 if (netp->n_type == X25NET) 583 return (0); 584 ioctl(pty, TIOCGETP, (char *)&b); 585 f = b.sg_flags; 586 p = pibuf; 587 *p++ = Q_BIT; 588 *p++ = X29_SET_PARMS; 589 *p++ = X29_ESCAPE_TO_CMD_CODE; *p++ = (f & (RAW|CBREAK)) == 0; 590 *p++ = X29_ECHO_CODE; *p++ = (f & ECHO) != 0; 591 *p++ = X29_FORWARDING_SIGNAL_CODE; *p++ = (f & (RAW|CBREAK)) ? 0 : 126; 592 593 /* 594 * The value of 10 (0.5 seconds) for the idle timer when 595 * in raw or cbreak mode is a compromise value. For good 596 * interactive response this value should be as low as 597 * possible; for reasonable efficiency with file transfers 598 * this value should be at fairly high. This number should 599 * be changed to suit local requirements. 600 */ 601 602 *p++ = X29_IDLE_TIMER_CODE; *p++ = (f & (RAW|CBREAK)) ? 10 : 0; 603 *p++ = X29_AUX_DEV_CONTROL_CODE;*p++ = (f & TANDEM) != 0; 604 *p++ = X29_XON_XOFF_CODE; *p++ = (f & RAW) == 0; 605 if(netp->n_type == CCITT1980) { 606 struct ltchars ltc; 607 608 ioctl(pty, TIOCGLTC, (char *)<c); 609 *p++ = X29_LF_AFTER_CR; 610 *p++ = (f & (RAW|CBREAK) || (f & ECHO) == 0) ? 0 : 4; 611 *p++ = X29_EDITING; 612 *p++ = (f & (RAW|CBREAK)) == 0; 613 *p++ = X29_CHARACTER_DELETE; 614 *p++ = (f & (RAW|CBREAK)) || b.sg_erase & 0200 ? 615 0 : b.sg_erase; 616 *p++ = X29_LINE_DELETE; 617 *p++ = (f & (RAW|CBREAK)) || b.sg_kill & 0200 ? 618 0 : b.sg_kill; 619 *p++ = X29_LINE_DISPLAY; 620 *p++ = (f & (RAW|CBREAK)) || ltc.t_rprntc & 0200 ? 621 0 : ltc.t_rprntc; 622 } 623 return (p - pibuf); 624 } 625 626 /* 627 * Process Q BIT (control) packets from the net. 628 * The only message that we are interested in are 629 * those indicating output is being discarded. 630 */ 631 632 x29_qbit(n) 633 { 634 register char *p; 635 636 switch (fibuf[1]) { 637 case X29_SET_PARMS: 638 case X29_SET_AND_READ_PARMS: 639 case X29_PARAMETER_INDICATION: 640 case X29_INDICATION_OF_BREAK: 641 for(p = &fibuf[2]; p < fibuf+n; p++) { 642 if(*p == X29_TRANSMISSION_SPEED_CODE) { 643 static char speeds[] = { 644 B110, B0, B300, B1200, B600, 645 B0, B0, B0, B0, B0, B0, B0, 646 B2400, B4800, B9600, EXTA }; 647 struct sgttyb b; 648 649 if(*++p >= 0 && *p < sizeof(speeds)) { 650 ioctl(pty, TIOCGETP, (char *)&b); 651 b.sg_ispeed = b.sg_ospeed = speeds[*p]; 652 ioctl(pty, TIOCSETN, (char *)&b); 653 } 654 } else if(*p == X29_DISCARD_OUTPUT_CODE && *++p != 0) { 655 char message[4]; 656 657 /* 658 * Always re-enable normal output 659 */ 660 message[0] = Q_BIT; 661 message[1] = X29_SET_PARMS; 662 message[2] = X29_DISCARD_OUTPUT_CODE; 663 message[3] = 0; 664 (void) write(net, message, sizeof(message)); 665 if(tracefn) 666 x29d_trace("netwrite", message, 4); 667 } 668 } 669 return; 670 671 default: { 672 register char *p2; 673 char buf[BUFSIZ*4]; 674 static int fd; 675 676 /* 677 * Bad news - we received an x29 error message or 678 * some other unknown packet. Dump the contents 679 * of the packet on the console. 680 */ 681 p = buf; 682 for(p2 = "x29d: unknown q-bit packet: "; *p++ = *p2++; ); 683 for(p2 = fibuf+1; p2 < fibuf+n; p2++) 684 if(*p2 >= ' ' && *p2 < 0177) 685 *p++ = *p2; 686 else { 687 *p++ = '\\'; 688 *p++ = ((*p2 & 0300) >> 6) + '0'; 689 *p++ = ((*p2 & 070) >> 3) + '0'; 690 *p++ = (*p2 & 07) + '0'; 691 } 692 *p++ = '\n'; 693 if(fd <= 0) 694 fd = open(console, 1); 695 (void) write(fd, buf, p-buf); 696 } 697 } 698 } 699 700 /* 701 * HACK! 702 * This program does not use or need any stdio routines. 703 * Defining this procedure prevents all of the stdio 704 * code from being loaded. 705 */ 706 707 exit(code) 708 { 709 _exit(code); 710 } 711 712 #include <utmp.h> 713 714 struct utmp wtmp; 715 char wtmpf[] = "/usr/adm/wtmp"; 716 char utmp[] = "/etc/utmp"; 717 #define SCPYN(a, b) strncpy(a, b, sizeof (a)) 718 #define SCMPN(a, b) strncmp(a, b, sizeof (a)) 719 720 rmut() 721 { 722 register int f, found = 0; 723 724 f = open(utmp, 2); 725 if (f >= 0) { 726 while(read(f, (char *)&wtmp, sizeof (wtmp)) == sizeof (wtmp)) { 727 if (SCMPN(wtmp.ut_line, line+5) || wtmp.ut_name[0]==0) 728 continue; 729 (void) lseek(f, -(long)sizeof (wtmp), 1); 730 SCPYN(wtmp.ut_name, ""); 731 SCPYN(wtmp.ut_host, ""); 732 time(&wtmp.ut_time); 733 (void) write(f, (char *)&wtmp, sizeof (wtmp)); 734 found++; 735 } 736 close(f); 737 } 738 if (found) { 739 f = open(wtmpf, 1); 740 if (f >= 0) { 741 SCPYN(wtmp.ut_line, line+5); 742 SCPYN(wtmp.ut_name, ""); 743 SCPYN(wtmp.ut_host, ""); 744 time(&wtmp.ut_time); 745 (void) lseek(f, (long)0, 2); 746 (void) write(f, (char *)&wtmp, sizeof (wtmp)); 747 close(f); 748 } 749 } 750 chmod(line, 0666); 751 chown(line, 0, 0); 752 line[strlen("/dev/")] = 'p'; 753 chmod(line, 0666); 754 chown(line, 0, 0); 755 } 756 757 x29d_trace(s, bp, n) 758 char *s, *bp; 759 { 760 static int fd; 761 char buf[BUFSIZ*4]; 762 register char *p1, *p2; 763 764 for(p1 = buf; *s; *p1++ = *s++); 765 *p1++ = ':'; 766 *p1++ = ' '; 767 for(p2=bp; p2 < bp+n; p2++) 768 if(*p2 >= ' ' && *p2 < 0177) 769 *p1++ = *p2; 770 else { 771 *p1++ = '\\'; 772 *p1++ = ((*p2 & 0300) >> 6) + '0'; 773 *p1++ = ((*p2 & 070) >> 3) + '0'; 774 *p1++ = (*p2 & 07) + '0'; 775 } 776 *p1++ = '\n'; 777 if(fd <= 0) 778 fd = creat(tracefn, 0666); 779 (void) write(fd, buf, p1-buf); 780 } 781