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
inet_strtoip(const char * str,uint32_t * ip)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
inet_iptostr(uint32_t ip)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
getouraddr()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
insque(void * a,void * b)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
remque(void * a)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
add_exec(struct ex_list ** ex_ptr,int do_pty,char * exec,int addr,int port)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 *
strerror(error)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
fork_exec(struct socket * so,const char * ex,int do_pty)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
slirp_openpty(amaster,aslave)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
fork_exec(struct socket * so,const char * ex,int do_pty)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 *
strdup(const char * str)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.h"
517
lprint(const char * format,...)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__
lprint(const char * format,...)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
add_emu(buff)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
vsprintf_len(string,format,args)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__
sprintf_len(char * string,const char * format,...)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
fd_nonblock(int fd)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
fd_block(int fd)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