Subject: Re: SE GC83 GPRS card: pppd problem
To: Christos Zoulas <christos@zoulas.com>
From: Jachym Holecek <freza@liberouter.org>
List: port-hpcarm
Date: 01/30/2006 18:00:20
> On Jan 30,  5:16pm, freza@liberouter.org (Jachym Holecek) wrote:
> -- Subject: Re: SE GC83 GPRS card: pppd problem
> | 
> | I did the same last night (but offline) -- the problem was in main.c
> | (in case you really mean sys-bsd.c, I can take a look later in the
> | evening)
> 
> I really meant sys-bsd.c ...

dist/pppd/pppd/main.c contains unhandled corner case, the patch
below fixed the problem I've reproduced with Alex's setup. The
second occupy_stdfds() call is key.

	-- Jachym

--- main.c	2006-01-30 17:52:56.000000000 +0100
+++ /home/jh/main.c	2006-01-30 17:54:17.000000000 +0100
@@ -1525,6 +1525,23 @@
 }
 
 /*
+ * occupy_stdfds - make sure fds 0, 1, 2 are occupied by pointing them
+ * to the /dev/null device.
+ */
+static void
+occupy_stdfds(void)
+{
+	int fd;
+
+	while ((fd = dup(fd_devnull)) >= 0) {
+		if (fd > 2) {
+			close(fd);
+			break;
+		}
+	}
+}
+
+/*
  * safe_fork - Create a child process.  The child closes all the
  * file descriptors that we don't want to leak to a script.
  * The parent waits for the child to do this before returning.
@@ -1535,16 +1552,11 @@
 safe_fork(int infd, int outfd, int errfd)
 {
 	pid_t pid;
-	int fd, pipefd[2];
+	int pipefd[2];
 	char buf[1];
 
-	/* make sure fds 0, 1, 2 are occupied (probably not necessary) */
-	while ((fd = dup(fd_devnull)) >= 0) {
-		if (fd > 2) {
-			close(fd);
-			break;
-		}
-	}
+	/* make sure the pipes will be above fd 2 */
+	occupy_stdfds();
 
 	if (pipe(pipefd) == -1)
 		pipefd[0] = pipefd[1] = -1;
@@ -1568,6 +1580,9 @@
 	tdb_close(pppdb);
 #endif
 
+	/* we've closed some descriptors, need to ensure again */
+	occupy_stdfds();
+
 	/* make sure infd, outfd and errfd won't get tromped on below */
 	if (infd == 1 || infd == 2)
 		infd = dup(infd);
@@ -1577,28 +1592,31 @@
 		errfd = dup(errfd);
 
 	/* dup the in, out, err fds to 0, 1, 2 */
-	if (infd != 0)
+	if (infd != 0) {
 		dup2(infd, 0);
-	if (outfd != 1)
+		close(infd);
+	}
+	if (outfd != 1) {
 		dup2(outfd, 1);
-	if (errfd != 2)
+		close(outfd);
+	}
+	if (errfd != 2) {
 		dup2(errfd, 2);
+		close(errfd);
+	}
 
 	closelog();
 	if (log_to_fd > 2)
 		close(log_to_fd);
-	if (the_channel->close)
+	if (the_channel->close) {
 		(*the_channel->close)();
-	else
-		close(devfd);	/* some plugins don't have a close function */
+		notice("teh_channel close");
+	} else {
+		if (devfd > 0)
+			close(devfd);	/* some plugins don't have a close() */
+	}
 	close(fd_ppp);
 	close(fd_devnull);
-	if (infd != 0)
-		close(infd);
-	if (outfd != 1)
-		close(outfd);
-	if (errfd != 2)
-		close(errfd);
 
 	notify(fork_notifier, 0);
 	close(pipefd[0]);
@@ -1631,6 +1649,8 @@
     ++conn_running;
     pid = safe_fork(in, out, errfd);
 
+    if (pid == 0)
+	if (log_to_fd
     if (pid != 0 && log_to_fd < 0)
 	close(errfd);