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/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