[Pkg-sysvinit-devel] Bug#457896: Bug#457896: (fwd) Re: Using startpar in makefile mode and failing getpt()

Kel Modderman kel at otaku42.de
Sun Jan 4 14:29:38 UTC 2009


On Thursday 01 January 2009 21:33:34 Petter Reinholdtsen wrote:
> Here is a patch I wrote a year ago to work around the getpt() problem.
> It uses a copy of the glibc getpt() function until /dev/pts is
> mounted, this working around the fact that the glibc getpt() only
> probe once if /dev/pts exist.

Did you receive feedback about it? I notice it has not been applied to startpar
version 0.52.

> 
> ----- Forwarded message from Petter Reinholdtsen <pere at hungry.com> -----
> 
> Date: Thu, 28 Feb 2008 12:21:16 +0100
> From: Petter Reinholdtsen <pere at hungry.com>
> To: Stephan Kulow
> Cc: "Dr. Werner Fink"
> Subject: Re: Using startpar in makefile mode and failing getpt()
> 
> [Stephan Kulow]
> > /etc/init.d/boot is the script executed by inittab and this one will 
> > mount important file systems before calling startpar. boot.localfs
> > will remount them later.
> 
> Aha.  That explains it.  I try to work around it by replacing getpt().
> The version in glibc will only check once if the required files and
> partitions are present, and refuse to check again when the environment
> change while the process is running.  My replacement do not have that
> problem.
> 
> I've had to patch startpar a bit to get it working on Debian, and here
> is the complete patch, relative to version 0.50.
> 
>  - I had to change the path used to find the rc*.d/ directories.
>  - I added debug modus to get more output while figuring out what is
>    wrong
>  - I added the getpt() hack.  Currently protected using an #ifdef to
>    be able to test without it.

Do you think it is important to protect this hack with #ifdef's ?

> 
> When I test startpar in makefile mode with debugging enabled and the
> getpt() hack disabled, it try to run the same scripts several times.
> When processing rc2.d/ (skipped rcS.d/ because of the getpt()
> problem), it try to run rc.local three times, and both stop-bootlogd
> and sysklogd twice.  Any idea why this happen?  Is the same problem
> present on SuSe when printing debug output?

I have separate patches to make startpar (seemingly, for me) work nicely with
Debian rc.d design. It does not suffer from duplicate execution of scripts
as far as I can tell.

Below is patch based on yours for startpar 0.52.

Thanks, Kel.
---
--- a/startpar.c
+++ b/startpar.c
@@ -31,6 +31,7 @@
 #include <sys/ioctl.h>
 #include <sys/sysinfo.h>
 #include <sys/stat.h>
+#include <sys/vfs.h>
 #include <time.h>
 #include <fcntl.h>
 #include <errno.h>
@@ -271,6 +272,62 @@ static inline int checkpar(const int par
   return checksystem(par, start, false);
 }
 
+/*
+ * Based on __posix_openpt() from glibc.  Reimplemented here to work
+ * around the problem with getpt() failing for the entire process life
+ * time if /dev/pts/ is missing the first time it is called but
+ * mounted while the process is running.  BSD style pts is not
+ * supported, but might be copied from glibc too if there is need.
+ */
+#define DEVFS_SUPER_MAGIC       0x1373
+#define DEVPTS_SUPER_MAGIC      0x1cd1
+
+static int startpar_getpt(void) {
+  int fd = open("/dev/ptmx", O_RDWR|O_NOCTTY);
+
+  if (fd != -1)
+    {
+      struct statfs fsbuf;
+
+      /* Check that the /dev/pts filesystem is mounted
+        or if /dev is a devfs filesystem (this implies /dev/pts).  */
+      if ((statfs ("/dev/pts", &fsbuf) == 0
+             && fsbuf.f_type == DEVPTS_SUPER_MAGIC)
+         || (statfs ("/dev", &fsbuf) == 0
+             && fsbuf.f_type == DEVFS_SUPER_MAGIC))
+        {
+          /* Everything is ok, switch to the getpt() in libc.  */
+          return fd;
+        }
+
+      /* If /dev/pts is not mounted then the UNIX98 pseudo terminals
+        are not usable.  */
+      close (fd);
+    }
+
+  return -1;
+}
+
+static int checkdevpts(void)
+{
+  int ptsfd = startpar_getpt();
+
+  if (ptsfd == -1)
+    {
+      return 0;
+    }
+  else if (ptsname(ptsfd) == 0 || grantpt(ptsfd) || unlockpt(ptsfd))
+    {
+      close(ptsfd);
+      return 0;
+    }
+  else
+    {
+      close(ptsfd);
+      return 1;
+    }
+}
+
 void run(struct prg *p)
 {
   char *m = 0;
@@ -775,6 +832,7 @@ int main(int argc, char **argv)
       pid_t pid = 0;
       int r = 0, s;
       long diff;
+      int devpts = 0;
 
       gettimeofday(&now, 0);
       FD_ZERO(&rset);
@@ -796,6 +854,8 @@ int main(int argc, char **argv)
       for (s = 0; s < par; s++)			/* never leave this with break!! */
 	{
 	account:				/* for the new process below */
+	  if (!devpts)
+	    devpts = checkdevpts();
 	  p = prgs + s;
 	  if (p == interactive_task)
 	    continue;				/* don't count this here */
@@ -815,7 +875,7 @@ int main(int argc, char **argv)
 		    {
 		      if ((nodevec[num] = pickup_task()) == NULL)
 			continue;
-		      if (nodevec[num]->interactive)
+		      if (nodevec[num]->interactive || !devpts)
 			interactive_task = p;
 		      p->name = nodevec[num]->name;
 		    }
---





More information about the Pkg-sysvinit-devel mailing list