misc.c revision 5d8f37ad78fc66901af50c762029a501561f3b23
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 11u_int curtime, time_fasttimo, last_slowtimo, detach_time; 12u_int detach_wait = 600000; /* 10 minutes */ 13struct emu_t *tcpemu; 14 15int 16inet_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 34char* 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 */ 49void 50getouraddr() 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 65struct quehead { 66 struct quehead *qh_link; 67 struct quehead *qh_rlink; 68}; 69 70inline void 71insque(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 82inline void 83remque(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 95int 96add_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 122extern int sys_nerr; 123extern char *sys_errlist[]; 124 125char * 126strerror(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 140int 141fork_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 150int 151slirp_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 */ 227int 228fork_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 369char * 370strdup(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 383void 384snooze_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 425void 426snooze() 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 450void 451relay(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 515void 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 524int (*lprint_print) _P((void *, const char *, va_list)); 525char *lprint_ptr, *lprint_ptr2, **lprint_arg; 526 527void 528#ifdef __STDC__ 529lprint(const char *format, ...) 530#else 531lprint(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 591void 592add_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 686int 687vsprintf_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 696int 697#ifdef __STDC__ 698sprintf_len(char *string, const char *format, ...) 699#else 700sprintf_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 720void 721u_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 739void 740fd_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 759void 760fd_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 */ 784int 785rsh_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