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 331 snprintf(buff, sizeof(buff), 332 "Error: execvp of %s failed: %s\n", 333 argv[0], strerror(errno)); 334 write(2, buff, strlen(buff)+1); 335 } 336 close(0); close(1); close(2); /* XXX */ 337 exit(1); 338 339 default: 340 if (do_pty == 2) { 341 close(s); 342 so->s = master; 343 } else { 344 /* 345 * XXX this could block us... 346 * XXX Should set a timer here, and if accept() doesn't 347 * return after X seconds, declare it a failure 348 * The only reason this will block forever is if socket() 349 * of connect() fail in the child process 350 */ 351 so->s = socket_accept(s, NULL); 352 socket_set_xreuseaddr(so->s); 353 socket_set_oobinline(so->s); 354 } 355 socket_set_nonblock(so->s); 356 357 /* Append the telnet options now */ 358 if (so->so_m != NULL && do_pty == 1) { 359 sbappend(so, so->so_m); 360 so->so_m = NULL; 361 } 362 363 return 1; 364 } 365 } 366 #endif 367 368 #ifndef HAVE_STRDUP 369 char * 370 strdup(const char* str) 371 { 372 char *bptr; 373 int len = strlen(str); 374 375 bptr = (char *)malloc(len+1); 376 memcpy(bptr, str, len+1); 377 378 return bptr; 379 } 380 #endif 381 382 #if 0 383 void 384 snooze_hup(num) 385 int num; 386 { 387 int s, ret; 388 #ifndef NO_UNIX_SOCKETS 389 struct sockaddr_un sock_un; 390 #endif 391 struct sockaddr_in sock_in; 392 char buff[256]; 393 394 ret = -1; 395 if (slirp_socket_passwd) { 396 s = socket(AF_INET, SOCK_STREAM, 0); 397 if (s < 0) 398 slirp_exit(1); 399 sock_in.sin_family = AF_INET; 400 sock_in.sin_addr.s_addr = slirp_socket_addr; 401 sock_in.sin_port = htons(slirp_socket_port); 402 if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0) 403 slirp_exit(1); /* just exit...*/ 404 sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); 405 write(s, buff, strlen(buff)+1); 406 } 407 #ifndef NO_UNIX_SOCKETS 408 else { 409 s = socket(AF_UNIX, SOCK_STREAM, 0); 410 if (s < 0) 411 slirp_exit(1); 412 sock_un.sun_family = AF_UNIX; 413 strcpy(sock_un.sun_path, socket_path); 414 if (connect(s, (struct sockaddr *)&sock_un, 415 sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0) 416 slirp_exit(1); 417 sprintf(buff, "kill none:%d", slirp_socket_unit); 418 write(s, buff, strlen(buff)+1); 419 } 420 #endif 421 slirp_exit(0); 422 } 423 424 425 void 426 snooze() 427 { 428 sigset_t s; 429 int i; 430 431 /* Don't need our data anymore */ 432 /* XXX This makes SunOS barf */ 433 /* brk(0); */ 434 435 /* Close all fd's */ 436 for (i = 255; i >= 0; i--) 437 close(i); 438 439 signal(SIGQUIT, slirp_exit); 440 signal(SIGHUP, snooze_hup); 441 sigemptyset(&s); 442 443 /* Wait for any signal */ 444 sigsuspend(&s); 445 446 /* Just in case ... */ 447 exit(255); 448 } 449 450 void 451 relay(s) 452 int s; 453 { 454 char buf[8192]; 455 int n; 456 fd_set readfds; 457 struct ttys *ttyp; 458 459 /* Don't need our data anymore */ 460 /* XXX This makes SunOS barf */ 461 /* brk(0); */ 462 463 signal(SIGQUIT, slirp_exit); 464 signal(SIGHUP, slirp_exit); 465 signal(SIGINT, slirp_exit); 466 signal(SIGTERM, slirp_exit); 467 468 /* Fudge to get term_raw and term_restore to work */ 469 if (NULL == (ttyp = tty_attach (0, slirp_tty))) { 470 lprint ("Error: tty_attach failed in misc.c:relay()\r\n"); 471 slirp_exit (1); 472 } 473 ttyp->fd = 0; 474 ttyp->flags |= TTY_CTTY; 475 term_raw(ttyp); 476 477 while (1) { 478 FD_ZERO(&readfds); 479 480 FD_SET(0, &readfds); 481 FD_SET(s, &readfds); 482 483 n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); 484 485 if (n <= 0) 486 slirp_exit(0); 487 488 if (FD_ISSET(0, &readfds)) { 489 n = read(0, buf, 8192); 490 if (n <= 0) 491 slirp_exit(0); 492 n = writen(s, buf, n); 493 if (n <= 0) 494 slirp_exit(0); 495 } 496 497 if (FD_ISSET(s, &readfds)) { 498 n = read(s, buf, 8192); 499 if (n <= 0) 500 slirp_exit(0); 501 n = writen(0, buf, n); 502 if (n <= 0) 503 slirp_exit(0); 504 } 505 } 506 507 /* Just in case.... */ 508 exit(1); 509 } 510 #endif 511 512 #ifdef CONFIG_QEMU 513 #include "monitor.h" 514 515 void lprint(const char *format, ...) 516 { 517 va_list args; 518 519 va_start(args, format); 520 monitor_vprintf(cur_mon, format, args); 521 va_end(args); 522 } 523 #else 524 int (*lprint_print) _P((void *, const char *, va_list)); 525 char *lprint_ptr, *lprint_ptr2, **lprint_arg; 526 527 void 528 #ifdef __STDC__ 529 lprint(const char *format, ...) 530 #else 531 lprint(va_alist) va_dcl 532 #endif 533 { 534 va_list args; 535 536 #ifdef __STDC__ 537 va_start(args, format); 538 #else 539 char *format; 540 va_start(args); 541 format = va_arg(args, char *); 542 #endif 543 #if 0 544 /* If we're printing to an sbuf, make sure there's enough room */ 545 /* XXX +100? */ 546 if (lprint_sb) { 547 if ((lprint_ptr - lprint_sb->sb_wptr) >= 548 (lprint_sb->sb_datalen - (strlen(format) + 100))) { 549 int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; 550 int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; 551 int deltap = lprint_ptr - lprint_sb->sb_data; 552 553 lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, 554 lprint_sb->sb_datalen + TCP_SNDSPACE); 555 556 /* Adjust all values */ 557 lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; 558 lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; 559 lprint_ptr = lprint_sb->sb_data + deltap; 560 561 lprint_sb->sb_datalen += TCP_SNDSPACE; 562 } 563 } 564 #endif 565 if (lprint_print) 566 lprint_ptr += (*lprint_print)(*lprint_arg, format, args); 567 568 /* Check if they want output to be logged to file as well */ 569 if (lfd) { 570 /* 571 * Remove \r's 572 * otherwise you'll get ^M all over the file 573 */ 574 int len = strlen(format); 575 char *bptr1, *bptr2; 576 577 bptr1 = bptr2 = strdup(format); 578 579 while (len--) { 580 if (*bptr1 == '\r') 581 memcpy(bptr1, bptr1+1, len+1); 582 else 583 bptr1++; 584 } 585 vfprintf(lfd, bptr2, args); 586 free(bptr2); 587 } 588 va_end(args); 589 } 590 591 void 592 add_emu(buff) 593 char *buff; 594 { 595 u_int lport, fport; 596 u_int8_t tos = 0, emu = 0; 597 char buff1[256], buff2[256], buff4[128]; 598 char *buff3 = buff4; 599 struct emu_t *emup; 600 struct socket *so; 601 602 if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) { 603 lprint("Error: Bad arguments\r\n"); 604 return; 605 } 606 607 if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) { 608 lport = 0; 609 if (sscanf(buff1, "%d", &fport) != 1) { 610 lprint("Error: Bad first argument\r\n"); 611 return; 612 } 613 } 614 615 if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { 616 buff3 = 0; 617 if (sscanf(buff2, "%256s", buff1) != 1) { 618 lprint("Error: Bad second argument\r\n"); 619 return; 620 } 621 } 622 623 if (buff3) { 624 if (strcmp(buff3, "lowdelay") == 0) 625 tos = IPTOS_LOWDELAY; 626 else if (strcmp(buff3, "throughput") == 0) 627 tos = IPTOS_THROUGHPUT; 628 else { 629 lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n"); 630 return; 631 } 632 } 633 634 if (strcmp(buff1, "ftp") == 0) 635 emu = EMU_FTP; 636 else if (strcmp(buff1, "irc") == 0) 637 emu = EMU_IRC; 638 else if (strcmp(buff1, "none") == 0) 639 emu = EMU_NONE; /* ie: no emulation */ 640 else { 641 lprint("Error: Unknown service\r\n"); 642 return; 643 } 644 645 /* First, check that it isn't already emulated */ 646 for (emup = tcpemu; emup; emup = emup->next) { 647 if (emup->lport == lport && emup->fport == fport) { 648 lprint("Error: port already emulated\r\n"); 649 return; 650 } 651 } 652 653 /* link it */ 654 emup = (struct emu_t *)malloc(sizeof (struct emu_t)); 655 emup->lport = (u_int16_t)lport; 656 emup->fport = (u_int16_t)fport; 657 emup->tos = tos; 658 emup->emu = emu; 659 emup->next = tcpemu; 660 tcpemu = emup; 661 662 /* And finally, mark all current sessions, if any, as being emulated */ 663 for (so = tcb.so_next; so != &tcb; so = so->so_next) { 664 if ((lport && lport == so->so_laddr_port) || 665 (fport && fport == so->so_faddr_port)) { 666 if (emu) 667 so->so_emu = emu; 668 if (tos) 669 so->so_iptos = tos; 670 } 671 } 672 673 lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); 674 } 675 #endif 676 677 #ifdef BAD_SPRINTF 678 679 #undef vsprintf 680 #undef sprintf 681 682 /* 683 * Some BSD-derived systems have a sprintf which returns char * 684 */ 685 686 int 687 vsprintf_len(string, format, args) 688 char *string; 689 const char *format; 690 va_list args; 691 { 692 vsprintf(string, format, args); 693 return strlen(string); 694 } 695 696 int 697 #ifdef __STDC__ 698 sprintf_len(char *string, const char *format, ...) 699 #else 700 sprintf_len(va_alist) va_dcl 701 #endif 702 { 703 va_list args; 704 #ifdef __STDC__ 705 va_start(args, format); 706 #else 707 char *string; 708 char *format; 709 va_start(args); 710 string = va_arg(args, char *); 711 format = va_arg(args, char *); 712 #endif 713 vsprintf(string, format, args); 714 return strlen(string); 715 } 716 717 #endif 718 719 #if 0 720 void 721 u_sleep(int usec) 722 { 723 struct timeval t; 724 fd_set fdset; 725 726 FD_ZERO(&fdset); 727 728 t.tv_sec = 0; 729 t.tv_usec = usec * 1000; 730 731 select(0, &fdset, &fdset, &fdset, &t); 732 } 733 #endif 734 735 /* 736 * Set fd blocking and non-blocking 737 */ 738 739 void 740 fd_nonblock(int fd) 741 { 742 #ifdef FIONBIO 743 #ifdef _WIN32 744 unsigned long opt = 1; 745 #else 746 int opt = 1; 747 #endif 748 749 ioctlsocket(fd, FIONBIO, &opt); 750 #else 751 int opt; 752 753 opt = fcntl(fd, F_GETFL, 0); 754 opt |= O_NONBLOCK; 755 fcntl(fd, F_SETFL, opt); 756 #endif 757 } 758 759 void 760 fd_block(int fd) 761 { 762 #ifdef FIONBIO 763 #ifdef _WIN32 764 unsigned long opt = 0; 765 #else 766 int opt = 0; 767 #endif 768 769 ioctlsocket(fd, FIONBIO, &opt); 770 #else 771 int opt; 772 773 opt = fcntl(fd, F_GETFL, 0); 774 opt &= ~O_NONBLOCK; 775 fcntl(fd, F_SETFL, opt); 776 #endif 777 } 778 779 780 #if 0 781 /* 782 * invoke RSH 783 */ 784 int 785 rsh_exec(so,ns, user, host, args) 786 struct socket *so; 787 struct socket *ns; 788 char *user; 789 char *host; 790 char *args; 791 { 792 int fd[2]; 793 int fd0[2]; 794 int s; 795 char buff[256]; 796 797 DEBUG_CALL("rsh_exec"); 798 DEBUG_ARG("so = %lx", (long)so); 799 800 if (pipe(fd)<0) { 801 lprint("Error: pipe failed: %s\n", strerror(errno)); 802 return 0; 803 } 804 /* #ifdef HAVE_SOCKETPAIR */ 805 #if 1 806 if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) { 807 close(fd[0]); 808 close(fd[1]); 809 lprint("Error: openpty failed: %s\n", strerror(errno)); 810 return 0; 811 } 812 #else 813 if (slirp_openpty(&fd0[0], &fd0[1]) == -1) { 814 close(fd[0]); 815 close(fd[1]); 816 lprint("Error: openpty failed: %s\n", strerror(errno)); 817 return 0; 818 } 819 #endif 820 821 switch(fork()) { 822 case -1: 823 lprint("Error: fork failed: %s\n", strerror(errno)); 824 close(fd[0]); 825 close(fd[1]); 826 close(fd0[0]); 827 close(fd0[1]); 828 return 0; 829 830 case 0: 831 close(fd[0]); 832 close(fd0[0]); 833 834 /* Set the DISPLAY */ 835 if (x_port >= 0) { 836 #ifdef HAVE_SETENV 837 sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); 838 setenv("DISPLAY", buff, 1); 839 #else 840 sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); 841 putenv(buff); 842 #endif 843 } 844 845 dup2(fd0[1], 0); 846 dup2(fd0[1], 1); 847 dup2(fd[1], 2); 848 for (s = 3; s <= 255; s++) 849 close(s); 850 851 execlp("rsh","rsh","-l", user, host, args, NULL); 852 853 /* Ooops, failed, let's tell the user why */ 854 855 sprintf(buff, "Error: execlp of %s failed: %s\n", 856 "rsh", strerror(errno)); 857 write(2, buff, strlen(buff)+1); 858 close(0); close(1); close(2); /* XXX */ 859 exit(1); 860 861 default: 862 close(fd[1]); 863 close(fd0[1]); 864 ns->s=fd[0]; 865 so->s=fd0[0]; 866 867 return 1; 868 } 869 } 870 #endif 871