forkoff()

Markus Friedl markus at openbsd.org
Tue Feb 5 08:09:42 EST 2002


On Mon, Feb 04, 2002 at 03:00:19PM -0500, Nicolas Williams wrote:
> Please review the function below, forkoff(), meant to be used in
> clientloop.c instead of daemon() and the code in process_escapes().
> 
> The intention is to make ~D ( like ~& but also detach) possible and to
> make it possible for ssh -f (or ssh -f -f - see other thread on this)
> to detach, not just forkoff().
> 
> I also intend to use the same detach technique in a feature patch for
> the hang-on-exit behaviour that's been hashed to death. I.e., I might
> like to add an option to control ssh's behaviour when the remote session
> exits, the behaviours being: wait for the channel to be closed [current,
> default], close all channels and exit, background, detach and force
> exit.
> 
> To make detaching and some of the hang-on-exit options work correctly I
> need a way to force a channel closed and to do it in way that is
> correct wrt to the SSHv2 protocol. The forkoff() function below does
> that, I think, but it would be nice to have confirmation.
> 
> Comments?
> 
> Nico
> 
> static
> void
> forkoff(int stop_listening, int detach)
> {
> 	pid_t pid;
> 	int fd;
> 	Channel *c;
> 
> 	/* Restore tty modes. */
> 	leave_raw_mode();
> 
> 	/* Stop listening for new connections. */
> 	if (stop_listening)
> 		channel_stop_listening();
> 
> 	fprintf(stderr, "Forking off into the background - %s",
> 		stop_listening ? "no longer listening" : "still listening");
> 
> 	/* Fork into background. */
> 	pid = fork();
> 	if (pid < 0) {
> 		error("fork: %.100s", strerror(errno));
> 		return;
> 	}
> 	if (pid != 0) {	/* This is the parent. */
> 		/* The parent just exits. */
> 		exit(0);
> 	}
> 
> 	c = channel_lookup(session_ident);

^^ there is no channel for ssh1
in ssh1 login sessions are different from, say, tcp-fwded channels.

> 	if (c == NULL)
> 		error("couldn't lookup session channel");
> 
> 	/* The child continues serving connections. */
> 	/* fake EOF on stdin */
> 	if (compat20) {
> 		buffer_append(&stdin_buffer, "\004", 1);

i don't like the \004 magic in the current code.

> 	} else if (!stdin_eof) {
> 		/*
> 		 * Sending SSH_CMSG_EOF alone does not always appear
> 		 * to be enough.  So we try to send an EOF character
> 		 * first.
> 		 */
> 		packet_start(SSH_CMSG_STDIN_DATA);
> 		packet_put_string("\004", 1);
> 		packet_send();
> 		/* Close stdin. */
> 		stdin_eof = 1;
> 		if (buffer_len(&stdin_buffer) == 0) {
> 			packet_start(SSH_CMSG_EOF);
> 			packet_send();
> 		}
> 	}
> 
> 	if (detach) {
> 		/*
> 		 * There should be a chan_wont_read()/chan_wont_write()
> 		 * API, differing only in the debug messages used.
> 		 */
> 		chan_read_failed(c);
> 		chan_write_failed(c);
^^^ you cannot call chan_xxx_failed for every channel state,
	please check nchan2.ms

> 		channel_close_fds(c);

you still want to keep the channel? why?

> 		fd = open(_PATH_DEVNULL, O_RDWR, 0);
> 		if (fd < 0)
> 			return;
> 		(void) dup2(fd, STDIN_FILENO);
> 		(void) dup2(fd, STDOUT_FILENO);
> 		(void) dup2(fd, STDERR_FILENO);
> 		if (fd > 2)
> 			(void) close(fd);
> 		(void) setsid();
> 	}

i'm not sure this works like expected.



More information about the openssh-unix-dev mailing list