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