1 /* 2 * Copyright (c) 1995 Danny Gasparovski. 3 * 4 * Please read the file COPYRIGHT for the 5 * terms and conditions of the copyright. 6 */ 7 8 #define WANT_SYS_IOCTL_H 9 #include <slirp.h> 10 11 u_int curtime, time_fasttimo, last_slowtimo, detach_time; 12 u_int detach_wait = 600000; /* 10 minutes */ 13 struct emu_t *tcpemu; 14 15 int 16 inet_strtoip(const char* str, uint32_t *ip) 17 { 18 int comp[4]; 19 20 if (sscanf(str, "%d.%d.%d.%d", &comp[0], &comp[1], &comp[2], &comp[3]) != 4) 21 return -1; 22 23 if ((unsigned)comp[0] >= 256 || 24 (unsigned)comp[1] >= 256 || 25 (unsigned)comp[2] >= 256 || 26 (unsigned)comp[3] >= 256) 27 return -1; 28 29 *ip = (uint32_t)((comp[0] << 24) | (comp[1] << 16) | 30 (comp[2] << 8) | comp[3]); 31 return 0; 32 } 33 34 char* inet_iptostr(uint32_t ip) 35 { 36 static char buff[32]; 37 38 snprintf(buff, sizeof(buff), "%d.%d.%d.%d", 39 (ip >> 24) & 255, 40 (ip >> 16) & 255, 41 (ip >> 8) & 255, 42 ip & 255); 43 return buff; 44 } 45 46 /* 47 * Get our IP address and put it in our_addr 48 */ 49 void 50 getouraddr() 51 { 52 char* hostname = host_name(); 53 SockAddress hostaddr; 54 55 our_addr_ip = loopback_addr_ip; 56 57 if (sock_address_init_resolve( &hostaddr, hostname, 0, 0 ) < 0) 58 return; 59 60 our_addr_ip = sock_address_get_ip(&hostaddr); 61 if (our_addr_ip == (uint32_t)-1) 62 our_addr_ip = loopback_addr_ip; 63 } 64 65 struct quehead { 66 struct quehead *qh_link; 67 struct quehead *qh_rlink; 68 }; 69 70 inline void 71 insque(void *a, void *b) 72 { 73 register struct quehead *element = (struct quehead *) a; 74 register struct quehead *head = (struct quehead *) b; 75 element->qh_link = head->qh_link; 76 head->qh_link = (struct quehead *)element; 77 element->qh_rlink = (struct quehead *)head; 78 ((struct quehead *)(element->qh_link))->qh_rlink 79 = (struct quehead *)element; 80 } 81 82 inline void 83 remque(void *a) 84 { 85 register struct quehead *element = (struct quehead *) a; 86 ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; 87 ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; 88 element->qh_rlink = NULL; 89 /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */ 90 } 91 92 /* #endif */ 93 94 95 int 96 add_exec(struct ex_list **ex_ptr, int do_pty, char *exec, int addr, int port) 97 { 98 struct ex_list *tmp_ptr; 99 100 /* First, check if the port is "bound" */ 101 for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { 102 if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr) 103 return -1; 104 } 105 106 tmp_ptr = *ex_ptr; 107 *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list)); 108 (*ex_ptr)->ex_fport = port; 109 (*ex_ptr)->ex_addr = addr; 110 (*ex_ptr)->ex_pty = do_pty; 111 (*ex_ptr)->ex_exec = (do_pty == 3) ? exec : strdup(exec); 112 (*ex_ptr)->ex_next = tmp_ptr; 113 return 0; 114 } 115 116 #ifndef HAVE_STRERROR 117 118 /* 119 * For systems with no strerror 120 */ 121 122 extern int sys_nerr; 123 extern char *sys_errlist[]; 124 125 char * 126 strerror(error) 127 int error; 128 { 129 if (error < sys_nerr) 130 return sys_errlist[error]; 131 else 132 return "Unknown error."; 133 } 134 135 #endif 136 137 138 #ifdef _WIN32 139 140 int 141 fork_exec(struct socket *so, const char *ex, int do_pty) 142 { 143 /* not implemented */ 144 return 0; 145 } 146 147 #else 148 149 #ifndef CONFIG_QEMU 150 int 151 slirp_openpty(amaster, aslave) 152 int *amaster, *aslave; 153 { 154 register int master, slave; 155 156 #ifdef HAVE_GRANTPT 157 char *ptr; 158 159 if ((master = open("/dev/ptmx", O_RDWR)) < 0 || 160 grantpt(master) < 0 || 161 unlockpt(master) < 0 || 162 (ptr = ptsname(master)) == NULL) { 163 close(master); 164 return -1; 165 } 166 167 if ((slave = open(ptr, O_RDWR)) < 0 || 168 ioctl(slave, I_PUSH, "ptem") < 0 || 169 ioctl(slave, I_PUSH, "ldterm") < 0 || 170 ioctl(slave, I_PUSH, "ttcompat") < 0) { 171 close(master); 172 close(slave); 173 return -1; 174 } 175 176 *amaster = master; 177 *aslave = slave; 178 return 0; 179 180 #else 181 182 static char line[] = "/dev/ptyXX"; 183 register const char *cp1, *cp2; 184 185 for (cp1 = "pqrsPQRS"; *cp1; cp1++) { 186 line[8] = *cp1; 187 for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) { 188 line[9] = *cp2; 189 if ((master = open(line, O_RDWR, 0)) == -1) { 190 if (errno == ENOENT) 191 return (-1); /* out of ptys */ 192 } else { 193 line[5] = 't'; 194 /* These will fail */ 195 (void) chown(line, getuid(), 0); 196 (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); 197 #ifdef HAVE_REVOKE 198 (void) revoke(line); 199 #endif 200 if ((slave = open(line, O_RDWR, 0)) != -1) { 201 *amaster = master; 202 *aslave = slave; 203 return 0; 204 } 205 (void) close(master); 206 line[5] = 'p'; 207 } 208 } 209 } 210 errno = ENOENT; /* out of ptys */ 211 return (-1); 212 #endif 213 } 214 #endif 215 216 /* 217 * XXX This is ugly 218 * We create and bind a socket, then fork off to another 219 * process, which connects to this socket, after which we 220 * exec the wanted program. If something (strange) happens, 221 * the accept() call could block us forever. 222 * 223 * do_pty = 0 Fork/exec inetd style 224 * do_pty = 1 Fork/exec using slirp.telnetd 225 * do_ptr = 2 Fork/exec using pty 226 */ 227 int 228 fork_exec(struct socket *so, const char *ex, int do_pty) 229 { 230 int s; 231 int master = -1; 232 const char *argv[256]; 233 #if 0 234 char buff[256]; 235 #endif 236 /* don't want to clobber the original */ 237 char *bptr; 238 const char *curarg; 239 int c, i; 240 241 DEBUG_CALL("fork_exec"); 242 DEBUG_ARG("so = %lx", (long)so); 243 DEBUG_ARG("ex = %lx", (long)ex); 244 DEBUG_ARG("do_pty = %lx", (long)do_pty); 245 246 if (do_pty == 2) { 247 #if 0 248 if (slirp_openpty(&master, &s) == -1) { 249 lprint("Error: openpty failed: %s\n", strerror(errno)); 250 return 0; 251 } 252 #else 253 return 0; 254 #endif 255 } else { 256 if ((s = socket_anyaddr_server(0, SOCKET_STREAM)) < 0) { 257 lprint("Error: inet socket: %s\n", errno_str); 258 return 0; 259 } 260 } 261 262 switch(fork()) { 263 case -1: 264 lprint("Error: fork failed: %s\n", strerror(errno)); 265 close(s); 266 if (do_pty == 2) 267 close(master); 268 return 0; 269 270 case 0: 271 /* Set the DISPLAY */ 272 if (do_pty == 2) { 273 (void) close(master); 274 #ifdef TIOCSCTTY /* XXXXX */ 275 (void) setsid(); 276 ioctl(s, TIOCSCTTY, (char *)NULL); 277 #endif 278 } else { 279 SockAddress addr; 280 socket_get_address(s, &addr); 281 socket_close(s); 282 /* 283 * Connect to the socket 284 * XXX If any of these fail, we're in trouble! 285 */ 286 s = socket_loopback_client(sock_address_get_port(&addr), SOCKET_STREAM); 287 } 288 289 #if 0 290 if (x_port >= 0) { 291 #ifdef HAVE_SETENV 292 sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); 293 setenv("DISPLAY", buff, 1); 294 #else 295 sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); 296 putenv(buff); 297 #endif 298 } 299 #endif 300 dup2(s, 0); 301 dup2(s, 1); 302 dup2(s, 2); 303 for (s = getdtablesize() - 1; s >= 3; s--) 304 close(s); 305 306 i = 0; 307 bptr = strdup(ex); /* No need to free() this */ 308 if (do_pty == 1) { 309 /* Setup "slirp.telnetd -x" */ 310 argv[i++] = "slirp.telnetd"; 311 argv[i++] = "-x"; 312 argv[i++] = bptr; 313 } else 314 do { 315 /* Change the string into argv[] */ 316 curarg = bptr; 317 while (*bptr != ' ' && *bptr != (char)0) 318 bptr++; 319 c = *bptr; 320 *bptr++ = (char)0; 321 argv[i++] = strdup(curarg); 322 } while (c); 323 324 argv[i] = NULL; 325 execvp(argv[0], (char **)argv); 326 327 /* Ooops, failed, let's tell the user why */ 328 { 329 char buff[256]; 330 int ret; 331 332 snprintf(buff, sizeof(buff), 333 "Error: execvp of %s failed: %s\n", 334 argv[0], strerror(errno)); 335 do { 336 ret =write(2, buff, strlen(buff)+1); 337 } while (ret < 0 && errno == EINTR); 338 } 339 close(0); close(1); close(2); /* XXX */ 340 exit(1); 341 342 default: 343 if (do_pty == 2) { 344 close(s); 345 so->s = master; 346 } else { 347 /* 348 * XXX this could block us... 349 * XXX Should set a timer here, and if accept() doesn't 350 * return after X seconds, declare it a failure 351 * The only reason this will block forever is if socket() 352 * of connect() fail in the child process 353 */ 354 so->s = socket_accept(s, NULL); 355 socket_set_xreuseaddr(so->s); 356 socket_set_oobinline(so->s); 357 } 358 socket_set_nonblock(so->s); 359 360 /* Append the telnet options now */ 361 if (so->so_m != NULL && do_pty == 1) { 362 sbappend(so, so->so_m); 363 so->so_m = NULL; 364 } 365 366 return 1; 367 } 368 } 369 #endif 370 371 #ifndef HAVE_STRDUP 372 char * 373 strdup(const char* str) 374 { 375 char *bptr; 376 int len = strlen(str); 377 378 bptr = (char *)malloc(len+1); 379 memcpy(bptr, str, len+1); 380 381 return bptr; 382 } 383 #endif 384 385 #if 0 386 void 387 snooze_hup(num) 388 int num; 389 { 390 int s, ret; 391 #ifndef NO_UNIX_SOCKETS 392 struct sockaddr_un sock_un; 393 #endif 394 struct sockaddr_in sock_in; 395 char buff[256]; 396 397 ret = -1; 398 if (slirp_socket_passwd) { 399 s = socket(AF_INET, SOCK_STREAM, 0); 400 if (s < 0) 401 slirp_exit(1); 402 sock_in.sin_family = AF_INET; 403 sock_in.sin_addr.s_addr = slirp_socket_addr; 404 sock_in.sin_port = htons(slirp_socket_port); 405 if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0) 406 slirp_exit(1); /* just exit...*/ 407 sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); 408 write(s, buff, strlen(buff)+1); 409 } 410 #ifndef NO_UNIX_SOCKETS 411 else { 412 s = socket(AF_UNIX, SOCK_STREAM, 0); 413 if (s < 0) 414 slirp_exit(1); 415 sock_un.sun_family = AF_UNIX; 416 strcpy(sock_un.sun_path, socket_path); 417 if (connect(s, (struct sockaddr *)&sock_un, 418 sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0) 419 slirp_exit(1); 420 sprintf(buff, "kill none:%d", slirp_socket_unit); 421 write(s, buff, strlen(buff)+1); 422 } 423 #endif 424 slirp_exit(0); 425 } 426 427 428 void 429 snooze() 430 { 431 sigset_t s; 432 int i; 433 434 /* Don't need our data anymore */ 435 /* XXX This makes SunOS barf */ 436 /* brk(0); */ 437 438 /* Close all fd's */ 439 for (i = 255; i >= 0; i--) 440 close(i); 441 442 signal(SIGQUIT, slirp_exit); 443 signal(SIGHUP, snooze_hup); 444 sigemptyset(&s); 445 446 /* Wait for any signal */ 447 sigsuspend(&s); 448 449 /* Just in case ... */ 450 exit(255); 451 } 452 453 void 454 relay(s) 455 int s; 456 { 457 char buf[8192]; 458 int n; 459 fd_set readfds; 460 struct ttys *ttyp; 461 462 /* Don't need our data anymore */ 463 /* XXX This makes SunOS barf */ 464 /* brk(0); */ 465 466 signal(SIGQUIT, slirp_exit); 467 signal(SIGHUP, slirp_exit); 468 signal(SIGINT, slirp_exit); 469 signal(SIGTERM, slirp_exit); 470 471 /* Fudge to get term_raw and term_restore to work */ 472 if (NULL == (ttyp = tty_attach (0, slirp_tty))) { 473 lprint ("Error: tty_attach failed in misc.c:relay()\r\n"); 474 slirp_exit (1); 475 } 476 ttyp->fd = 0; 477 ttyp->flags |= TTY_CTTY; 478 term_raw(ttyp); 479 480 while (1) { 481 FD_ZERO(&readfds); 482 483 FD_SET(0, &readfds); 484 FD_SET(s, &readfds); 485 486 n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); 487 488 if (n <= 0) 489 slirp_exit(0); 490 491 if (FD_ISSET(0, &readfds)) { 492 n = read(0, buf, 8192); 493 if (n <= 0) 494 slirp_exit(0); 495 n = writen(s, buf, n); 496 if (n <= 0) 497 slirp_exit(0); 498 } 499 500 if (FD_ISSET(s, &readfds)) { 501 n = read(s, buf, 8192); 502 if (n <= 0) 503 slirp_exit(0); 504 n = writen(0, buf, n); 505 if (n <= 0) 506 slirp_exit(0); 507 } 508 } 509 510 /* Just in case.... */ 511 exit(1); 512 } 513 #endif 514 515 #ifdef CONFIG_QEMU 516 #include "monitor/monitor.h" 517 518 void lprint(const char *format, ...) 519 { 520 va_list args; 521 522 va_start(args, format); 523 monitor_vprintf(cur_mon, format, args); 524 va_end(args); 525 } 526 #else 527 int (*lprint_print) _P((void *, const char *, va_list)); 528 char *lprint_ptr, *lprint_ptr2, **lprint_arg; 529 530 void 531 #ifdef __STDC__ 532 lprint(const char *format, ...) 533 #else 534 lprint(va_alist) va_dcl 535 #endif 536 { 537 va_list args; 538 539 #ifdef __STDC__ 540 va_start(args, format); 541 #else 542 char *format; 543 va_start(args); 544 format = va_arg(args, char *); 545 #endif 546 #if 0 547 /* If we're printing to an sbuf, make sure there's enough room */ 548 /* XXX +100? */ 549 if (lprint_sb) { 550 if ((lprint_ptr - lprint_sb->sb_wptr) >= 551 (lprint_sb->sb_datalen - (strlen(format) + 100))) { 552 int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; 553 int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; 554 int deltap = lprint_ptr - lprint_sb->sb_data; 555 556 lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, 557 lprint_sb->sb_datalen + TCP_SNDSPACE); 558 559 /* Adjust all values */ 560 lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; 561 lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; 562 lprint_ptr = lprint_sb->sb_data + deltap; 563 564 lprint_sb->sb_datalen += TCP_SNDSPACE; 565 } 566 } 567 #endif 568 if (lprint_print) 569 lprint_ptr += (*lprint_print)(*lprint_arg, format, args); 570 571 /* Check if they want output to be logged to file as well */ 572 if (lfd) { 573 /* 574 * Remove \r's 575 * otherwise you'll get ^M all over the file 576 */ 577 int len = strlen(format); 578 char *bptr1, *bptr2; 579 580 bptr1 = bptr2 = strdup(format); 581 582 while (len--) { 583 if (*bptr1 == '\r') 584 memcpy(bptr1, bptr1+1, len+1); 585 else 586 bptr1++; 587 } 588 vfprintf(lfd, bptr2, args); 589 free(bptr2); 590 } 591 va_end(args); 592 } 593 594 void 595 add_emu(buff) 596 char *buff; 597 { 598 u_int lport, fport; 599 u_int8_t tos = 0, emu = 0; 600 char buff1[256], buff2[256], buff4[128]; 601 char *buff3 = buff4; 602 struct emu_t *emup; 603 struct socket *so; 604 605 if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) { 606 lprint("Error: Bad arguments\r\n"); 607 return; 608 } 609 610 if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) { 611 lport = 0; 612 if (sscanf(buff1, "%d", &fport) != 1) { 613 lprint("Error: Bad first argument\r\n"); 614 return; 615 } 616 } 617 618 if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { 619 buff3 = 0; 620 if (sscanf(buff2, "%256s", buff1) != 1) { 621 lprint("Error: Bad second argument\r\n"); 622 return; 623 } 624 } 625 626 if (buff3) { 627 if (strcmp(buff3, "lowdelay") == 0) 628 tos = IPTOS_LOWDELAY; 629 else if (strcmp(buff3, "throughput") == 0) 630 tos = IPTOS_THROUGHPUT; 631 else { 632 lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n"); 633 return; 634 } 635 } 636 637 if (strcmp(buff1, "ftp") == 0) 638 emu = EMU_FTP; 639 else if (strcmp(buff1, "irc") == 0) 640 emu = EMU_IRC; 641 else if (strcmp(buff1, "none") == 0) 642 emu = EMU_NONE; /* ie: no emulation */ 643 else { 644 lprint("Error: Unknown service\r\n"); 645 return; 646 } 647 648 /* First, check that it isn't already emulated */ 649 for (emup = tcpemu; emup; emup = emup->next) { 650 if (emup->lport == lport && emup->fport == fport) { 651 lprint("Error: port already emulated\r\n"); 652 return; 653 } 654 } 655 656 /* link it */ 657 emup = (struct emu_t *)malloc(sizeof (struct emu_t)); 658 emup->lport = (u_int16_t)lport; 659 emup->fport = (u_int16_t)fport; 660 emup->tos = tos; 661 emup->emu = emu; 662 emup->next = tcpemu; 663 tcpemu = emup; 664 665 /* And finally, mark all current sessions, if any, as being emulated */ 666 for (so = tcb.so_next; so != &tcb; so = so->so_next) { 667 if ((lport && lport == so->so_laddr_port) || 668 (fport && fport == so->so_faddr_port)) { 669 if (emu) 670 so->so_emu = emu; 671 if (tos) 672 so->so_iptos = tos; 673 } 674 } 675 676 lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); 677 } 678 #endif 679 680 #ifdef BAD_SPRINTF 681 682 #undef vsprintf 683 #undef sprintf 684 685 /* 686 * Some BSD-derived systems have a sprintf which returns char * 687 */ 688 689 int 690 vsprintf_len(string, format, args) 691 char *string; 692 const char *format; 693 va_list args; 694 { 695 vsprintf(string, format, args); 696 return strlen(string); 697 } 698 699 int 700 #ifdef __STDC__ 701 sprintf_len(char *string, const char *format, ...) 702 #else 703 sprintf_len(va_alist) va_dcl 704 #endif 705 { 706 va_list args; 707 #ifdef __STDC__ 708 va_start(args, format); 709 #else 710 char *string; 711 char *format; 712 va_start(args); 713 string = va_arg(args, char *); 714 format = va_arg(args, char *); 715 #endif 716 vsprintf(string, format, args); 717 return strlen(string); 718 } 719 720 #endif 721 722 #if 0 723 void 724 u_sleep(int usec) 725 { 726 struct timeval t; 727 fd_set fdset; 728 729 FD_ZERO(&fdset); 730 731 t.tv_sec = 0; 732 t.tv_usec = usec * 1000; 733 734 select(0, &fdset, &fdset, &fdset, &t); 735 } 736 #endif 737 738 /* 739 * Set fd blocking and non-blocking 740 */ 741 742 void 743 fd_nonblock(int fd) 744 { 745 #ifdef FIONBIO 746 #ifdef _WIN32 747 unsigned long opt = 1; 748 #else 749 int opt = 1; 750 #endif 751 752 ioctlsocket(fd, FIONBIO, &opt); 753 #else 754 int opt; 755 756 opt = fcntl(fd, F_GETFL, 0); 757 opt |= O_NONBLOCK; 758 fcntl(fd, F_SETFL, opt); 759 #endif 760 } 761 762 void 763 fd_block(int fd) 764 { 765 #ifdef FIONBIO 766 #ifdef _WIN32 767 unsigned long opt = 0; 768 #else 769 int opt = 0; 770 #endif 771 772 ioctlsocket(fd, FIONBIO, &opt); 773 #else 774 int opt; 775 776 opt = fcntl(fd, F_GETFL, 0); 777 opt &= ~O_NONBLOCK; 778 fcntl(fd, F_SETFL, opt); 779 #endif 780 } 781 782 783 #if 0 784 /* 785 * invoke RSH 786 */ 787 int 788 rsh_exec(so,ns, user, host, args) 789 struct socket *so; 790 struct socket *ns; 791 char *user; 792 char *host; 793 char *args; 794 { 795 int fd[2]; 796 int fd0[2]; 797 int s; 798 char buff[256]; 799 800 DEBUG_CALL("rsh_exec"); 801 DEBUG_ARG("so = %lx", (long)so); 802 803 if (pipe(fd)<0) { 804 lprint("Error: pipe failed: %s\n", strerror(errno)); 805 return 0; 806 } 807 /* #ifdef HAVE_SOCKETPAIR */ 808 #if 1 809 if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) { 810 close(fd[0]); 811 close(fd[1]); 812 lprint("Error: openpty failed: %s\n", strerror(errno)); 813 return 0; 814 } 815 #else 816 if (slirp_openpty(&fd0[0], &fd0[1]) == -1) { 817 close(fd[0]); 818 close(fd[1]); 819 lprint("Error: openpty failed: %s\n", strerror(errno)); 820 return 0; 821 } 822 #endif 823 824 switch(fork()) { 825 case -1: 826 lprint("Error: fork failed: %s\n", strerror(errno)); 827 close(fd[0]); 828 close(fd[1]); 829 close(fd0[0]); 830 close(fd0[1]); 831 return 0; 832 833 case 0: 834 close(fd[0]); 835 close(fd0[0]); 836 837 /* Set the DISPLAY */ 838 if (x_port >= 0) { 839 #ifdef HAVE_SETENV 840 sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); 841 setenv("DISPLAY", buff, 1); 842 #else 843 sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); 844 putenv(buff); 845 #endif 846 } 847 848 dup2(fd0[1], 0); 849 dup2(fd0[1], 1); 850 dup2(fd[1], 2); 851 for (s = 3; s <= 255; s++) 852 close(s); 853 854 execlp("rsh","rsh","-l", user, host, args, NULL); 855 856 /* Ooops, failed, let's tell the user why */ 857 858 sprintf(buff, "Error: execlp of %s failed: %s\n", 859 "rsh", strerror(errno)); 860 write(2, buff, strlen(buff)+1); 861 close(0); close(1); close(2); /* XXX */ 862 exit(1); 863 864 default: 865 close(fd[1]); 866 close(fd0[1]); 867 ns->s=fd[0]; 868 so->s=fd0[0]; 869 870 return 1; 871 } 872 } 873 #endif 874