Esempio n. 1
0
int
sigvec(int sig, struct sigvec *nvec, struct sigvec *ovec)
{
        struct sigaction nact;
        struct sigaction oact;
        struct sigaction *nactp;
        void (*ohandler)(), (*nhandler)();

        if (sig <= 0 || sig >= NSIG) {
                errno = EINVAL;
                return -1;
        }

        ohandler = _siguhandler[sig];

        if (nvec) {
		_sigaction(sig, (struct sigaction *)0, &nact);
                nhandler = nvec->sv_handler; 
                _siguhandler[sig] = nhandler;
                if (nhandler != SIG_DFL && nhandler != SIG_IGN)
                        nact.sa_handler = (void (*)())sigvechandler;
		else
			nact.sa_handler = nhandler;
		mask2set(nvec->sv_mask, &nact.sa_mask);
		/*
		if ( sig == SIGTSTP || sig == SIGSTOP )
			nact.sa_handler = SIG_DFL; 	*/
		nact.sa_flags = SA_SIGINFO;
		if (!(nvec->sv_flags & SV_INTERRUPT))
			nact.sa_flags |= SA_RESTART;
		if (nvec->sv_flags & SV_RESETHAND)
			nact.sa_flags |= SA_RESETHAND;
		if (nvec->sv_flags & SV_ONSTACK)
			nact.sa_flags |= SA_ONSTACK;
		nactp = &nact;
        } else
		nactp = (struct sigaction *)0;

        if (_sigaction(sig, nactp, &oact) < 0) {
                _siguhandler[sig] = ohandler;
                return -1;
        }

        if (ovec) {
		if (oact.sa_handler == SIG_DFL || oact.sa_handler == SIG_IGN)
			ovec->sv_handler = oact.sa_handler;
		else
			ovec->sv_handler = ohandler;
		ovec->sv_mask = set2mask(&oact.sa_mask);
		ovec->sv_flags = 0;
		if (oact.sa_flags & SA_ONSTACK)
			ovec->sv_flags |= SV_ONSTACK;
		if (oact.sa_flags & SA_RESETHAND)
			ovec->sv_flags |= SV_RESETHAND;
		if (!(oact.sa_flags & SA_RESTART))
			ovec->sv_flags |= SV_INTERRUPT;
	}
			
        return 0;
}
Esempio n. 2
0
int
__system(const char *command)
{
	pid_t pid, savedpid;
	int pstat;
	struct sigaction ign, intact, quitact;
	sigset_t newsigblock, oldsigblock;

	if (!command)		/* just checking... */
		return(1);

	(void)sigemptyset(&newsigblock);
	(void)sigaddset(&newsigblock, SIGCHLD);
	(void)sigaddset(&newsigblock, SIGINT);
	(void)sigaddset(&newsigblock, SIGQUIT);
	(void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
	switch(pid = vfork()) {
	case -1:			/* error */
		(void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
		return (-1);
	case 0:				/* child */
		/*
		 * Restore original signal dispositions and exec the command.
		 */
		(void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
		execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
		_exit(127);
	}
	/* 
	 * If we are running means that the child has either completed
	 * its execve, or has failed.
	 * Block SIGINT/QUIT because sh -c handles it and wait for
	 * it to clean up.
	 */
	memset(&ign, 0, sizeof(ign));
	ign.sa_handler = SIG_IGN;
	(void)sigemptyset(&ign.sa_mask);
	(void)_sigaction(SIGINT, &ign, &intact);
	(void)_sigaction(SIGQUIT, &ign, &quitact);
	savedpid = pid;
	do {
		pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
	} while (pid == -1 && errno == EINTR);
	(void)_sigaction(SIGINT, &intact, NULL);
	(void)_sigaction(SIGQUIT,  &quitact, NULL);
	(void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
	return(pid == -1 ? -1 : pstat);
}
Esempio n. 3
0
void
abort()
{
	struct sigaction act;

	/*
	 * POSIX requires we flush stdio buffers on abort.
	 * XXX ISO C requires that abort() be async-signal-safe.
	 */
	if (__cleanup)
		(*__cleanup)();

	sigfillset(&act.sa_mask);
	/*
	 * Don't block SIGABRT to give any handler a chance; we ignore
	 * any errors -- ISO C doesn't allow abort to return anyway.
	 */
	sigdelset(&act.sa_mask, SIGABRT);
	(void)_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
	(void)raise(SIGABRT);

	/*
	 * If SIGABRT was ignored, or caught and the handler returns, do
	 * it again, only harder.
	 */
	act.sa_handler = SIG_DFL;
	act.sa_flags = 0;
	sigfillset(&act.sa_mask);
	(void)_sigaction(SIGABRT, &act, NULL);
	sigdelset(&act.sa_mask, SIGABRT);
	(void)_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
	(void)raise(SIGABRT);
	exit(1);
}
Esempio n. 4
0
int
daemon(int nochdir, int noclose)
{
	struct sigaction osa, sa;
	int fd;
	pid_t newgrp;
	int oerrno;
	int osa_ok;

	/* A SIGHUP may be thrown when the parent exits below. */
	sigemptyset(&sa.sa_mask);
	sa.sa_handler = SIG_IGN;
	sa.sa_flags = 0;
	osa_ok = _sigaction(SIGHUP, &sa, &osa);

	switch (fork()) {
	case -1:
		return (-1);
	case 0:
		break;
	default:
		_exit(0);
	}

	newgrp = setsid();
	oerrno = errno;
	if (osa_ok != -1)
		_sigaction(SIGHUP, &osa, NULL);

	if (newgrp == -1) {
		errno = oerrno;
		return (-1);
	}

	if (!nochdir)
		chdir("/");

	if (!noclose && (fd = _open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
		_dup2(fd, STDIN_FILENO);
		_dup2(fd, STDOUT_FILENO);
		_dup2(fd, STDERR_FILENO);
		if (fd > 2)
			_close(fd);
	}
	return (0);
}
Esempio n. 5
0
int
__system(const char *command)
{
	pid_t pid, savedpid;
	int pstat;
	struct sigaction ign, intact, quitact;
	sigset_t newsigblock, oldsigblock;

	if (!command)		/* just checking... */
		return(1);

	/*
	 * Ignore SIGINT and SIGQUIT, block SIGCHLD. Remember to save
	 * existing signal dispositions.
	 */
	ign.sa_handler = SIG_IGN;
	(void)sigemptyset(&ign.sa_mask);
	ign.sa_flags = 0;
	(void)_sigaction(SIGINT, &ign, &intact);
	(void)_sigaction(SIGQUIT, &ign, &quitact);
	(void)sigemptyset(&newsigblock);
	(void)sigaddset(&newsigblock, SIGCHLD);
	(void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
	switch(pid = fork()) {
	case -1:			/* error */
		break;
	case 0:				/* child */
		/*
		 * Restore original signal dispositions and exec the command.
		 */
		(void)_sigaction(SIGINT, &intact, NULL);
		(void)_sigaction(SIGQUIT,  &quitact, NULL);
		(void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
		execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
		_exit(127);
	default:			/* parent */
		savedpid = pid;
		do {
			pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
		} while (pid == -1 && errno == EINTR);
		break;
	}
	(void)_sigaction(SIGINT, &intact, NULL);
	(void)_sigaction(SIGQUIT,  &quitact, NULL);
	(void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
	return(pid == -1 ? -1 : pstat);
}
Esempio n. 6
0
int
ucbsigvec(int sig, struct sigvec *nvec, struct sigvec *ovec)
{
	struct sigaction nact;
	struct sigaction oact;
	struct sigaction *nactp;
	void (*ohandler)(), (*nhandler)();

	if (sig <= 0 || sig >= NSIG) {
		errno = EINVAL;
		return (-1);
	}

	if ((intptr_t)ovec == -1 || (intptr_t)nvec == -1) {
		errno = EFAULT;
		return (-1);
	}

	ohandler = _siguhandler[sig];

	if (nvec) {
		_sigaction(sig, (struct sigaction *)0, &nact);
		nhandler = nvec->sv_handler;
		/*
		 * To be compatible with the behavior of SunOS 4.x:
		 * If the new signal handler is SIG_IGN or SIG_DFL,
		 * do not change the signal's entry in the handler array.
		 * This allows a child of vfork(2) to set signal handlers
		 * to SIG_IGN or SIG_DFL without affecting the parent.
		 */
		if (nhandler != SIG_DFL && nhandler != SIG_IGN) {
			_siguhandler[sig] = nhandler;
			nact.sa_handler = (void (*)())ucbsigvechandler;
		} else {
			nact.sa_handler = nhandler;
		}
		mask2set(nvec->sv_mask, &nact.sa_mask);
		if (sig == SIGKILL || sig == SIGSTOP)
			nact.sa_handler = SIG_DFL;
		nact.sa_flags = SA_SIGINFO;
		if (!(nvec->sv_flags & SV_INTERRUPT))
			nact.sa_flags |= SA_RESTART;
		if (nvec->sv_flags & SV_RESETHAND)
			nact.sa_flags |= SA_RESETHAND;
		if (nvec->sv_flags & SV_ONSTACK)
			nact.sa_flags |= SA_ONSTACK;
		nactp = &nact;
	} else
		nactp = (struct sigaction *)0;

	if (_sigaction(sig, nactp, &oact) < 0) {
		_siguhandler[sig] = ohandler;
		return (-1);
	}

	if (ovec) {
		if (oact.sa_handler == SIG_DFL || oact.sa_handler == SIG_IGN)
			ovec->sv_handler = oact.sa_handler;
		else
			ovec->sv_handler = ohandler;
		ovec->sv_mask = set2mask(&oact.sa_mask);
		ovec->sv_flags = 0;
		if (oact.sa_flags & SA_ONSTACK)
			ovec->sv_flags |= SV_ONSTACK;
		if (oact.sa_flags & SA_RESETHAND)
			ovec->sv_flags |= SV_RESETHAND;
		if (!(oact.sa_flags & SA_RESTART))
			ovec->sv_flags |= SV_INTERRUPT;
	}

	return (0);
}
Esempio n. 7
0
char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{
	ssize_t nr;
	int input, output, save_errno, i, need_restart;
	char ch, *p, *end;
	struct termios term, oterm;
	struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
	struct sigaction savetstp, savettin, savettou, savepipe;

	/* I suppose we could alloc on demand in this case (XXX). */
	if (bufsiz == 0) {
		errno = EINVAL;
		return(NULL);
	}

restart:
	for (i = 0; i < NSIG; i++)
		signo[i] = 0;
	nr = -1;
	save_errno = 0;
	need_restart = 0;
	/*
	 * Read and write to /dev/tty if available.  If not, read from
	 * stdin and write to stderr unless a tty is required.
	 */
	if ((flags & RPP_STDIN) ||
	    (input = output = _open(_PATH_TTY, O_RDWR)) == -1) {
		if (flags & RPP_REQUIRE_TTY) {
			errno = ENOTTY;
			return(NULL);
		}
		input = STDIN_FILENO;
		output = STDERR_FILENO;
	}

	/*
	 * Turn off echo if possible.
	 * If we are using a tty but are not the foreground pgrp this will
	 * generate SIGTTOU, so do it *before* installing the signal handlers.
	 */
	if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
		memcpy(&term, &oterm, sizeof(term));
		if (!(flags & RPP_ECHO_ON))
			term.c_lflag &= ~(ECHO | ECHONL);
		if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
			term.c_cc[VSTATUS] = _POSIX_VDISABLE;
		(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
	} else {
		memset(&term, 0, sizeof(term));
		term.c_lflag |= ECHO;
		memset(&oterm, 0, sizeof(oterm));
		oterm.c_lflag |= ECHO;
	}

	/*
	 * Catch signals that would otherwise cause the user to end
	 * up with echo turned off in the shell.  Don't worry about
	 * things like SIGXCPU and SIGVTALRM for now.
	 */
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;		/* don't restart system calls */
	sa.sa_handler = handler;
	(void)_sigaction(SIGALRM, &sa, &savealrm);
	(void)_sigaction(SIGHUP, &sa, &savehup);
	(void)_sigaction(SIGINT, &sa, &saveint);
	(void)_sigaction(SIGPIPE, &sa, &savepipe);
	(void)_sigaction(SIGQUIT, &sa, &savequit);
	(void)_sigaction(SIGTERM, &sa, &saveterm);
	(void)_sigaction(SIGTSTP, &sa, &savetstp);
	(void)_sigaction(SIGTTIN, &sa, &savettin);
	(void)_sigaction(SIGTTOU, &sa, &savettou);

	if (!(flags & RPP_STDIN))
		(void)_write(output, prompt, strlen(prompt));
	end = buf + bufsiz - 1;
	p = buf;
	while ((nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
		if (p < end) {
			if ((flags & RPP_SEVENBIT))
				ch &= 0x7f;
			if (isalpha(ch)) {
				if ((flags & RPP_FORCELOWER))
					ch = (char)tolower(ch);
				if ((flags & RPP_FORCEUPPER))
					ch = (char)toupper(ch);
			}
			*p++ = ch;
		}
	}
	*p = '\0';
	save_errno = errno;
	if (!(term.c_lflag & ECHO))
		(void)_write(output, "\n", 1);

	/* Restore old terminal settings and signals. */
	if (memcmp(&term, &oterm, sizeof(term)) != 0) {
		while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
		    errno == EINTR && !signo[SIGTTOU])
			continue;
	}
	(void)_sigaction(SIGALRM, &savealrm, NULL);
	(void)_sigaction(SIGHUP, &savehup, NULL);
	(void)_sigaction(SIGINT, &saveint, NULL);
	(void)_sigaction(SIGQUIT, &savequit, NULL);
	(void)_sigaction(SIGPIPE, &savepipe, NULL);
	(void)_sigaction(SIGTERM, &saveterm, NULL);
	(void)_sigaction(SIGTSTP, &savetstp, NULL);
	(void)_sigaction(SIGTTIN, &savettin, NULL);
	(void)_sigaction(SIGTTOU, &savettou, NULL);
	if (input != STDIN_FILENO)
		(void)_close(input);

	/*
	 * If we were interrupted by a signal, resend it to ourselves
	 * now that we have restored the signal handlers.
	 */
	for (i = 0; i < NSIG; i++) {
		if (signo[i]) {
			kill(getpid(), i);
			switch (i) {
			case SIGTSTP:
			case SIGTTIN:
			case SIGTTOU:
				need_restart = 1;
			}
		}
	}
	if (need_restart)
		goto restart;

	if (save_errno)
		errno = save_errno;
	return(nr == -1 ? NULL : buf);
}
Esempio n. 8
0
char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{
	ssize_t nr;
	int input, output, save_errno;
	char ch, *p, *end;
	struct termios term, oterm;
	struct sigaction sa, saveint, savehup, savequit, saveterm;
	struct sigaction savetstp, savettin, savettou;
	locale_t loc = __current_locale();

	/* I suppose we could alloc on demand in this case (XXX). */
	if (bufsiz == 0) {
		errno = EINVAL;
		return(NULL);
	}

restart:
	/*
	 * Read and write to /dev/tty if available.  If not, read from
	 * stdin and write to stderr unless a tty is required.
	 */
	if ((input = output = _open(_PATH_TTY, O_RDWR)) == -1) {
		if (flags & RPP_REQUIRE_TTY) {
			errno = ENOTTY;
			return(NULL);
		}
		input = STDIN_FILENO;
		output = STDERR_FILENO;
	}

	/*
	 * Catch signals that would otherwise cause the user to end
	 * up with echo turned off in the shell.  Don't worry about
	 * things like SIGALRM and SIGPIPE for now.
	 */
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;		/* don't restart system calls */
	sa.sa_handler = handler;
	(void)_sigaction(SIGINT, &sa, &saveint);
	(void)_sigaction(SIGHUP, &sa, &savehup);
	(void)_sigaction(SIGQUIT, &sa, &savequit);
	(void)_sigaction(SIGTERM, &sa, &saveterm);
	(void)_sigaction(SIGTSTP, &sa, &savetstp);
	(void)_sigaction(SIGTTIN, &sa, &savettin);
	(void)_sigaction(SIGTTOU, &sa, &savettou);

	/* Turn off echo if possible. */
	if (tcgetattr(input, &oterm) == 0) {
		memcpy(&term, &oterm, sizeof(term));
		if (!(flags & RPP_ECHO_ON))
			term.c_lflag &= ~(ECHO | ECHONL);
		if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
			term.c_cc[VSTATUS] = _POSIX_VDISABLE;
		(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
	} else {
		memset(&term, 0, sizeof(term));
		memset(&oterm, 0, sizeof(oterm));
	}

	(void)_write(output, prompt, strlen(prompt));
	end = buf + bufsiz - 1;
	for (p = buf; (nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r';) {
		if (p < end) {
			if ((flags & RPP_SEVENBIT))
				ch &= 0x7f;
			if (isalpha_l(ch, loc)) {
				if ((flags & RPP_FORCELOWER))
					ch = tolower_l(ch, loc);
				if ((flags & RPP_FORCEUPPER))
					ch = toupper_l(ch, loc);
			}
			*p++ = ch;
		}
	}
	*p = '\0';
	save_errno = errno;
	if (!(term.c_lflag & ECHO))
		(void)_write(output, "\n", 1);

	/* Restore old terminal settings and signals. */
	if (memcmp(&term, &oterm, sizeof(term)) != 0)
		(void)tcsetattr(input, TCSANOW|TCSASOFT, &oterm);
	(void)_sigaction(SIGINT, &saveint, NULL);
	(void)_sigaction(SIGHUP, &savehup, NULL);
	(void)_sigaction(SIGQUIT, &savequit, NULL);
	(void)_sigaction(SIGTERM, &saveterm, NULL);
	(void)_sigaction(SIGTSTP, &savetstp, NULL);
	(void)_sigaction(SIGTTIN, &savettin, NULL);
	(void)_sigaction(SIGTTOU, &savettou, NULL);
	if (input != STDIN_FILENO)
		(void)_close(input);

	/*
	 * If we were interrupted by a signal, resend it to ourselves
	 * now that we have restored the signal handlers.
	 */
	if (signo) {
		kill(getpid(), signo); 
		switch (signo) {
		case SIGTSTP:
		case SIGTTIN:
		case SIGTTOU:
			signo = 0;
			goto restart;
		}
	}

	errno = save_errno;
	return(nr == -1 ? NULL : buf);
}
Esempio n. 9
0
int rcmd_af(char **ahost, unsigned short rport, const char *locuser,
    const char *remuser, const char *cmd, int *fd2p, int af)
{
	int s, timo = 1;
	ssize_t retval;
	pid_t pid;
	struct sockaddr_storage caddr, faddr;
	struct sockaddr_in *sin;
	struct sockaddr_in6 *sin6;
	struct addrinfo hints;
	struct addrinfo *res, *resp;
	size_t addrlen;
	int rc;
#define	MAX_SHORTSTRLEN 6
	char aport[MAX_SHORTSTRLEN];
	char c;
	int lport = 0;
#ifdef SYSV
	sigset_t oldmask;
	sigset_t newmask;
	struct sigaction oldaction;
	struct sigaction newaction;
#else
	int oldmask;
#endif /* SYSV */
	fd_set fdset;
	int selret;
	char *addr;
	static char hostname[MAXHOSTNAMELEN];
	socklen_t len;
	char abuf[INET6_ADDRSTRLEN];

	if (!(af == AF_INET || af == AF_INET6 || af == AF_UNSPEC)) {
		errno = EAFNOSUPPORT;
		return (-1);
	}

	pid = getpid();
	memset(&hints, 0, sizeof (hints));
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_CANONNAME;
	if (af == AF_INET6) {
		hints.ai_flags |= AI_V4MAPPED;
		hints.ai_family = AF_UNSPEC;
	} else {
		hints.ai_family = af;
	}
	(void) snprintf(aport, MAX_SHORTSTRLEN, "%u", ntohs(rport));
	rc = getaddrinfo(*ahost, aport, &hints, &res);
	if (rc != 0) {
		(void) fprintf(stderr,
		    _dgettext(TEXT_DOMAIN, "%s: unknown host%s\n"),
		    *ahost, rc == EAI_AGAIN ? " (try again later)" : "");
		return (-1);
	}
	resp = res;
	(void) strlcpy(hostname, res->ai_canonname, MAXHOSTNAMELEN);
	*ahost = hostname;
#ifdef SYSV
	/* ignore SIGPIPE */
	bzero((char *)&newaction, sizeof (newaction));
	newaction.sa_handler = SIG_IGN;
	(void) _sigaction(SIGPIPE, &newaction, &oldaction);

	/* block SIGURG */
	bzero((char *)&newmask, sizeof (newmask));
	(void) _sigaddset(&newmask, SIGURG);
	(void) _sigprocmask(SIG_BLOCK, &newmask, &oldmask);
#else
	oldmask = _sigblock(sigmask(SIGURG));
#endif /* SYSV */
	for (;;) {
		s = rresvport_af(&lport, res->ai_family);
		if (s < 0) {
			int af = res->ai_family;

			/*
			 * See if we have any addresses of a different type
			 * to try.
			 */
			while (res != NULL && res->ai_family == af)
				res = res->ai_next;

			if (res != NULL)
				continue;

			if (errno == EAGAIN)
				(void) fprintf(stderr,
				    _dgettext(TEXT_DOMAIN,
				    "socket: All ports in use\n"));
			else
				perror("rcmd: socket");
#ifdef SYSV
			/* restore original SIGPIPE handler */
			(void) _sigaction(SIGPIPE, &oldaction,
			    (struct sigaction *)0);

			/* restore original signal mask */
			(void) _sigprocmask(SIG_SETMASK, &oldmask,
			    (sigset_t *)0);
#else
			sigsetmask(oldmask);
#endif /* SYSV */
			freeaddrinfo(resp);
			return (-1);
		}
		bzero((char *)&caddr, sizeof (caddr));
		bcopy(res->ai_addr, &caddr, res->ai_addrlen);
		addrlen = res->ai_addrlen;
		if (af == AF_INET6 && res->ai_addr->sa_family == AF_INET) {
			struct in6_addr ia6;
			struct sockaddr_in6 *in6addr;
			IN6_INADDR_TO_V4MAPPED(&((struct sockaddr_in *)
			    res->ai_addr)->sin_addr, &ia6);
			in6addr = (struct sockaddr_in6 *)&caddr;
			in6addr->sin6_addr = ia6;
			in6addr->sin6_family = AF_INET6;
			addrlen = sizeof (struct sockaddr_in6);
		}
		(void) _fcntl(s, F_SETOWN, pid);
		if (connect(s, (struct sockaddr *)&caddr, addrlen) >= 0)
			break;
		(void) close(s);
		if (errno == EADDRINUSE) {
			lport = 0;
			continue;
		}
		if (errno == ECONNREFUSED && timo <= 16) {
			(void) sleep(timo);
			timo *= 2;
			continue;
		}
		if (res->ai_next != NULL) {
			int oerrno = errno;
			if (res->ai_addr->sa_family == AF_INET6)
				addr = (char *)&((struct sockaddr_in6 *)
				    res->ai_addr)->sin6_addr;
			else
				addr = (char *)&((struct sockaddr_in *)
				    res->ai_addr)->sin_addr;
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN, "connect to address %s: "),
			    inet_ntop(res->ai_addr->sa_family, addr,
			    abuf, sizeof (abuf)));
			errno = oerrno;
			perror(0);
			res = res->ai_next;
			if (res->ai_addr->sa_family == AF_INET6)
				addr = (char *)&((struct sockaddr_in6 *)
				    res->ai_addr)->sin6_addr;
			else
				addr = (char *)&((struct sockaddr_in *)
				    res->ai_addr)->sin_addr;
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN, "Trying %s...\n"),
			    inet_ntop(res->ai_addr->sa_family, addr,
			    abuf, sizeof (abuf)));
			continue;
		}
		perror(*ahost);
		freeaddrinfo(resp);
#ifdef SYSV
		/* restore original SIGPIPE handler */
		(void) _sigaction(SIGPIPE, &oldaction,
		    (struct sigaction *)0);

		/* restore original signal mask */
		(void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
#else
		sigsetmask(oldmask);
#endif /* SYSV */
		return (-1);
	}
	lport = 0;
	if (fd2p == 0) {
		(void) write(s, "", 1);
	} else {
		int s2 = rresvport_af(&lport, res->ai_family), s3;

		len = (socklen_t)sizeof (faddr);

		if (s2 < 0)
			goto bad;
		(void) listen(s2, 1);
		(void) snprintf(aport, MAX_SHORTSTRLEN, "%d", lport);
		if (write(s, aport, strlen(aport)+1) != strlen(aport)+1) {
			perror(_dgettext(TEXT_DOMAIN,
			    "write: setting up stderr"));
			(void) close(s2);
			goto bad;
		}
		FD_ZERO(&fdset);
		FD_SET(s, &fdset);
		FD_SET(s2, &fdset);
		while ((selret = select(FD_SETSIZE, &fdset, (fd_set *)0,
		    (fd_set *)0, (struct timeval *)0)) > 0) {
			if (FD_ISSET(s, &fdset)) {
				/*
				 *	Something's wrong:  we should get no
				 *	data on this connection at this point,
				 *	so we assume that the connection has
				 *	gone away.
				 */
				(void) close(s2);
				goto bad;
			}
			if (FD_ISSET(s2, &fdset)) {
				/*
				 *	We assume this is an incoming connect
				 *	request and proceed normally.
				 */
				s3 = accept(s2, (struct sockaddr *)&faddr,
				    &len);
				FD_CLR(s2, &fdset);
				(void) close(s2);
				if (s3 < 0) {
					perror("accept");
					lport = 0;
					goto bad;
				}
				else
					break;
			}
		}
		if (selret == -1) {
			/*
			 *	This should not happen, and we treat it as
			 *	a fatal error.
			 */
			(void) close(s2);
			goto bad;
		}

		*fd2p = s3;
		switch (faddr.ss_family) {
		case AF_INET:
			sin = (struct sockaddr_in *)&faddr;
			if (ntohs(sin->sin_port) >= IPPORT_RESERVED) {
				(void) fprintf(stderr,
				    _dgettext(TEXT_DOMAIN,
					"socket: protocol failure in circuit "
					"setup.\n"));
				goto bad2;
			}
			break;
		case AF_INET6:
			sin6 = (struct sockaddr_in6 *)&faddr;
			if (ntohs(sin6->sin6_port) >= IPPORT_RESERVED) {
				(void) fprintf(stderr,
				    _dgettext(TEXT_DOMAIN,
					"socket: protocol failure in circuit "
					"setup.\n"));
				goto bad2;
			}
			break;
		default:
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN,
			    "socket: protocol failure in circuit setup.\n"));
			goto bad2;
		}
	}
	(void) write(s, locuser, strlen(locuser)+1);
	(void) write(s, remuser, strlen(remuser)+1);
	(void) write(s, cmd, strlen(cmd)+1);
	retval = read(s, &c, 1);
	if (retval != 1) {
		if (retval == 0) {
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN,
			    "Protocol error, %s closed connection\n"),
			    *ahost);
		} else if (retval < 0) {
			perror(*ahost);
		} else {
			(void) fprintf(stderr,
			    _dgettext(TEXT_DOMAIN,
			    "Protocol error, %s sent %d bytes\n"),
			    *ahost, retval);
		}
		goto bad2;
	}
	if (c != 0) {
		while (read(s, &c, 1) == 1) {
			(void) write(2, &c, 1);
			if (c == '\n')
				break;
		}
		goto bad2;
	}
#ifdef SYSV
	/* restore original SIGPIPE handler */
	(void) _sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);

	/* restore original signal mask */
	(void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
#else
	sigsetmask(oldmask);
#endif /* SYSV */
	freeaddrinfo(resp);
	return (s);
bad2:
	if (lport)
		(void) close(*fd2p);
bad:
	(void) close(s);
#ifdef SYSV
	/* restore original SIGPIPE handler */
	(void) _sigaction(SIGPIPE, &oldaction, (struct sigaction *)0);

	/* restore original signal mask */
	(void) _sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)0);
#else
	sigsetmask(oldmask);
#endif /* SYSV */
	freeaddrinfo(resp);
	return (-1);
}