tags 484883 + patch
retitle 484883 update and patch startpar for Debian
thanks

Package: sysvinit
Version: 2.86.ds1-61

After discussion with Petter on IRC, we decided that startpar will remain
in sysvinit source package for time being. Therefore, I bring this bug report
back to a wishlist item to update startpar and make it work in Makefile mode
on Debian.

Attaching cumulative patch which contains the following logical changes:
* update to startpar 0.52 from 0.50
* apply patch from SuSE to make use of posix_fadvise(2)
* apply patch to make startpar work on Debian, including Makefile mode
* apply patch from #457896 to make sure scripts executed before /dev/pts is
  available are treated as interactive

Thanks, Kel.
---
--- a/debian/startpar/Makefile
+++ b/debian/startpar/Makefile
@@ -1,4 +1,5 @@
-VERSION = 0.50
+VERSION = 0.52
+ISSUSE = -DNOTSUSE
 
 INSTALL                = install -m 755
 INSTALL_DATA   = install -m 644
@@ -7,11 +8,18 @@ sbindir               = /sbin
 mandir         = /usr/share/man
 man8dir                = $(mandir)/man8
 
-OBJS           = startpar.o makeboot.o proc.o
+SRCS           = startpar.c makeboot.c proc.c
+HDRS           = makeboot.h proc.h
+REST           = COPYING Makefile startpar.8
+OBJS           = $(SRCS:.c=.o)
 
 CC = gcc
 OPTFLAGS = -O2 -g -Wall -W
-CFLAGS = $(OPTFLAGS) -D_GNU_SOURCE
+CFLAGS = $(OPTFLAGS) -D_GNU_SOURCE $(ISSUSE)
+
+ifeq ($(MAKECMDGOALS),makeboot)
+CFLAGS += -DTEST
+endif
 
 .c.o:
        $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -c $<
@@ -19,10 +27,20 @@ CFLAGS = $(OPTFLAGS) -D_GNU_SOURCE
 startpar: $(OBJS)
        $(CC) $(CFLAGS) -DVERSION=\"$(VERSION)\" -o $@ $(OBJS)
 
+makeboot: makeboot.c
+
 install: startpar
        $(INSTALL) -d $(DESTDIR)$(sbindir) $(DESTDIR)$(man8dir)
        $(INSTALL) startpar $(DESTDIR)$(sbindir)/.
        $(INSTALL_DATA) startpar.8 $(DESTDIR)$(man8dir)/.
 
 clean:
-       rm -f startpar $(OBJS)
+       rm -f startpar makeboot $(OBJS)
+
+dest: clean
+       mkdir -p startpar-$(VERSION)
+       for file in $(SRCS) $(HDRS) $(REST) ; do \
+           cp -p $$file startpar-$(VERSION)/; \
+       done
+       tar -cps -jf startpar-$(VERSION).tar.bz2 startpar-$(VERSION)/*
+       rm -rf startpar-$(VERSION)/
--- a/debian/startpar/makeboot.c
+++ b/debian/startpar/makeboot.c
@@ -13,6 +13,12 @@
 #include <errno.h>
 #include <limits.h>
 #include "makeboot.h"
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+static int o_flags = O_RDONLY;
+#endif
 
 
 int tree_entries = 0;
@@ -158,11 +164,28 @@ void parse_makefile(const char *path)
        char *s, *strp, *p;
        struct makenode *node;
 
-       if ((fp = fopen(path, "r")) == NULL) {
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+       int fd;
+
+       if (getuid() == (uid_t)0)
+               o_flags |= O_NOATIME;
+       if ((fd = open(path, o_flags)) < 0) {
                fprintf(stderr, "Can't open %s: %s\n", path, strerror(errno));
                exit(1);
        }
-       
+       (void)posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
+       (void)posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+       (void)posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
+
+       if ((fp = fdopen(fd, "r")) == NULL)
+#else
+       if ((fp = fopen(path, "r")) == NULL)
+#endif
+       {
+               fprintf(stderr, "Can't open %s: %s\n", path, strerror(errno));
+               exit(1);
+       }
+
        while (fgets(buf, sizeof(buf), fp)) {
                for (s = buf; *s && isspace(*s); s++)
                        ;
@@ -198,6 +221,11 @@ void parse_makefile(const char *path)
                        }
                }
        }
+
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+       (void)posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
+#endif
+
        fclose(fp);
 
        for (node = tree_list; node; node = node->next) {
@@ -233,16 +261,32 @@ static void filter_files(const char *dir
        struct makenode *t, *next;
 
        filter_prefix = prefix;
-       snprintf(path, sizeof(path), RCDBASEDIR "/%s.d", dir);
+#ifdef SUSE    /* SuSE */
+       snprintf(path, sizeof(path), "/etc/init.d/%s.d", dir);
+#else          /* Debian */
+       snprintf(path, sizeof(path), "/etc/%s.d", dir);
+#endif
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+       if ((i = open(path, o_flags|O_DIRECTORY|O_LARGEFILE)) >= 0) {
+               (void)posix_fadvise(i, 0, 0, POSIX_FADV_SEQUENTIAL);
+               (void)posix_fadvise(i, 0, 0, POSIX_FADV_NOREUSE);
+       }
+#endif
        ndirs = scandir(path, &dirlist, dirfilter, alphasort);
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+       if (i >= 0)
+               (void)posix_fadvise(i, 0, 0, POSIX_FADV_DONTNEED);
+#endif
        /* mark all matching nodes */
-       for (i = 0; i < ndirs; i++) {
-               t = lookup_target(dirlist[i]->d_name + 3);
-               if (t)
-                       t->status = 1;
-               free(dirlist[i]);
+       if (ndirs >= 0) {
+               for (i = 0; i < ndirs; i++) {
+                       t = lookup_target(dirlist[i]->d_name + 3);
+                       if (t)
+                               t->status = 1;
+                       free(dirlist[i]);
+               }
+               free(dirlist);
        }
-       free(dirlist);
        /* deselect non-matching nodes */
        for (t = tree_list; t; t = next) {
                next = t->next;
@@ -287,8 +331,10 @@ void check_run_files(const char *action,
 {
        char buf[4] = "rc0";
        if (! strcmp(action, "boot")) {
-               buf[2] = 'S';
-               filter_files(buf, 'S', 0);
+#ifdef SUSE    /* SuSE */
+               filter_files("boot", 'S', 0);
+       } else if (! strcmp(action, "halt")) {
+               filter_files("boot", 'K', 0);
        } else if (! strcmp(action, "start")) {
                buf[2] = *prev;
                filter_files(buf, 'K', 1);
@@ -299,6 +345,19 @@ void check_run_files(const char *action,
                filter_files(buf, 'K', 0);
                buf[2] = *run;
                filter_files(buf, 'S', 1);
+#else          /* Debian */
+               filter_files("rcS", 'S', 0);
+       } else if (! strcmp(action, "start")) {
+               buf[2] = *prev;
+               filter_files(buf, 'S', 1);
+               buf[2] = *run;
+               filter_files(buf, 'S', 0);
+       } else {
+               buf[2] = *prev;
+               filter_files(buf, 'K', 1);
+               buf[2] = *run;
+               filter_files(buf, 'K', 0);
+#endif
        }
 }
 
@@ -340,6 +399,21 @@ struct makenode *pickup_task(void)
                        best = node;
                }
        }
+       if (best) {
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+               char path[128];
+               int fd;
+               snprintf(path, sizeof(path), "/etc/init.d/%s", best->name);
+               if ((fd = open(path, o_flags|O_DIRECT)) >= 0) {
+                       (void)posix_fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
+                       (void)posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
+                       (void)posix_fadvise(fd, 0, 0, POSIX_FADV_NOREUSE);
+                       close(fd);
+               }
+#endif
+               blogger("service %s", best->name);
+               best->status = T_RUNNING;
+       }
        return best;
 }
 
@@ -354,6 +428,17 @@ void finish_task(struct makenode *node)
                return;
        for (n = node->select; n; n = n->next)
                n->node->num_deps--;
+#if defined _XOPEN_SOURCE && (_XOPEN_SOURCE - 0) >= 600
+       {
+               char path[128];
+               int fd;
+               snprintf(path, sizeof(path), "/etc/init.d/%s", node->name);
+               if ((fd = open(path, o_flags|O_DIRECT)) >= 0) {
+                       (void)posix_fadvise(fd, 0, 0, POSIX_FADV_DONTNEED);
+                       close(fd);
+               }
+       }
+#endif
        node->status = T_FINISHED;
        blogger("service %s done", node->name);
 }
@@ -413,3 +498,42 @@ void dump_status(void)
                        node->name, node->status, node->num_deps, 
node->interactive, node->importance);
 }
 #endif
+
+#ifdef TEST
+void *xcalloc(size_t nmemb, size_t size)
+{
+       void *r;
+       if ((r = (void *)calloc(nmemb, size)) == 0) {
+               fprintf(stderr, "calloc: out of memory\n");
+               exit(1);
+       }
+       return r;
+}
+
+int main(int argc, char **argv)
+{
+       struct makenode *nodevec;
+       char makefile[64];
+
+       if (argc != 4) {
+               fprintf(stderr, "usage: makeboot <action> [<prev> <run>]\n");
+               goto out;
+       }
+
+       nodevec = xcalloc(1, sizeof(*nodevec));
+
+       snprintf(makefile, sizeof(makefile), "depend.%s", argv[1]);
+       parse_makefile(makefile);
+
+       fprintf(stderr, "check_run_files(%s, %s, %s)\n", argv[1], argv[2],
+               argv[3]);
+       check_run_files(argv[1], argv[2], argv[3]);
+out:
+       while ((nodevec = pickup_task())) {
+               fprintf(stdout, "%s\n", nodevec->name);
+               finish_task(nodevec);
+       }
+
+       return 0;
+}
+#endif
--- a/debian/startpar/makeboot.h
+++ b/debian/startpar/makeboot.h
@@ -33,12 +33,3 @@ extern struct makenode *pickup_task(void
 extern void finish_task(struct makenode *n);
 extern void *xcalloc(size_t nmemb, size_t size);
 extern void print_run_result(int *resvec, struct makenode **nodevec, const 
char *action);
-
-/* SUSE and Debian */
-#define INITDDIR "/etc/init.d"
-
-#if 0 /* SUSE */
-#  define RCDBASEDIR "/etc/init.d"
-#else /* Debian */
-#  define RCDBASEDIR "/etc"
-#endif
--- a/debian/startpar/startpar.c
+++ b/debian/startpar/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>
@@ -40,6 +41,8 @@
 #include "makeboot.h"
 #include "proc.h"
 
+#define timerdiff(n,l) (__extension__ ({ 
(((n).tv_sec-(l).tv_sec)*1000)+(((n).tv_usec-(l).tv_usec)/1000); }))
+
 typedef enum _boolean {false, true} boolean;
 extern char *optarg;
 extern int optind;
@@ -48,8 +51,13 @@ static long int numcpu = -1;
 static char *myname;
 static struct termios tio;
 static struct winsize wz;
-static int wzok;
+static struct {
+  char env_row[128];
+  char env_col[128];
+} sz;
+static sig_atomic_t wzok;
 static char *arg;
+static boolean isstart;
 static struct sigaction sa;
 static struct timeval glastio;
 static struct timeval now;
@@ -72,7 +80,7 @@ struct prg {
 static struct prg *prgs;
 static int inpar, par;
 static int pidpipe[2];
-static int iorate = 800;
+static double iorate = 800.0;
 
 void *xcalloc(size_t nmemb, size_t size)
 {
@@ -124,7 +132,9 @@ void waitsplash()
   int status;
   if (!splashpid)
     return;
-  waitpid(splashpid, &status, 0);
+  do {
+    waitpid(splashpid, &status, 0);
+  } while (errno == EINTR);
   splashpid = 0;
 }
 
@@ -181,8 +191,8 @@ void callsplash(int n, char *path, char 
       splashpid = pid;
       return;
     }
-  close(1);
-  dup(2);
+  while (dup2(2, 1) < 0 && (errno == EINTR))
+    ;
   closeall();
   execl("/sbin/splash", "splash", "-p", sbuf, "-t", tbuf, splashcfg, (char 
*)0);
   _exit(1);
@@ -204,11 +214,10 @@ void writebuf(struct prg *p)
       p->len -= r;
       b += r;
     }
-  glastio.tv_sec  = now.tv_sec;
-  glastio.tv_usec = now.tv_usec;
+  glastio = now;
 }
 
-static int checksystem(const int par, const char *mode, const boolean limit)
+static int checksystem(const int par, const boolean start, const boolean limit)
 {
   const      int pg_size       = sysconf(_SC_PAGESIZE);
   const long int minphys_bytes = (sysconf(_SC_LONG_BIT) > 32L) ? (2<<22) : 
(2<<21);
@@ -223,7 +232,7 @@ static int checksystem(const int par, co
   if (pg_size < 0)
     return par;
 
-  if (mode && strcmp(mode, "stop") == 0)
+  if (!start)
     minphys_pg = avphys_pg;
   else
     minphys_pg = minphys_bytes / pg_size;
@@ -240,8 +249,8 @@ static int checksystem(const int par, co
   if (read_proc(&prcs_run, &prcs_blked))
     return par;
 
-  newpar = (par*numcpu) - prcs_run + 1; /* +1 for startpar its self */
-  newpar -= (prcs_blked * iorate);     /* I/O load reduction */
+  newpar  = (par*numcpu) - prcs_run + 1;       /* +1 for startpar its self */
+  newpar -= (int)(((double)prcs_blked)*iorate);        /* I/O load reduction */
 
 #if DEBUG
   fprintf(stderr, "checksystem par=%d newpar=%d (prcs_run=%u) %ld\n", par, 
newpar, prcs_run, time(0));
@@ -253,14 +262,70 @@ static int checksystem(const int par, co
     return newpar;
 }
 
-static inline int checklimit(const int par, const char *mode)
+static inline int checklimit(const int par, const boolean start)
 {
-  return checksystem(par, mode, true);
+  return checksystem(par, start, true);
 }
 
-static inline int checkpar(const int par, const char *mode)
+static inline int checkpar(const int par, const boolean start)
 {
-  return checksystem(par, mode, false);
+  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)
@@ -301,39 +366,45 @@ void run(struct prg *p)
   (void)signal(SIGQUIT, SIG_DFL);
   (void)signal(SIGSEGV, SIG_DFL);
   (void)signal(SIGTERM, SIG_DFL);
+  (void)signal(SIGCHLD, SIG_DFL);
 
   if (setpgid(0, 0))
     perror("setpgid");
 
   if (m && p->fd)
     {
-      close(1);
+      while (close(1) < 0 && (errno == EINTR))
+       ;
       if (open(m, O_RDWR) != 1)
        {
          perror(m);
          _exit(1);
        }
-      close(2);
-      dup(1);
+      while (dup2(1, 2) < 0 && (errno == EINTR))
+       ;
       tio.c_oflag &= ~OPOST;
       if (tcsetattr(1, TCSANOW, &tio))
        perror("tcsetattr");
-      if (wzok && ioctl(0, TIOCSWINSZ, &wz))
-       perror("TIOCSWINSZ");
+      if (wzok)
+       ioctl(1, TIOCSWINSZ, &wz);
+      putenv(sz.env_row);
+      putenv(sz.env_col);
     }
   else
     {
-      close(1);
-      dup(2);
+      while (dup2(2, 1) < 0 && (errno == EINTR))
+       ;
     }
 
   closeall();
 
-  if (run_mode) {
-    char path[128];
-    snprintf(path, sizeof(path), INITDDIR "/%s", p->name);
-    execlp(path, path, arg, (char *)0);
-  } else if (arg)
+  if (run_mode)
+    {
+      char path[128];
+      snprintf(path, sizeof(path), "/etc/init.d/%s", p->name);
+      execlp(path, path, arg, (char *)0);
+    }
+  else if (arg)
     execlp(p->name, p->name, arg, (char *)0);
   else
     execlp(p->name, p->name, (char *)0);
@@ -359,14 +430,15 @@ int run_single(char *prg, int spl)
       (void)signal(SIGQUIT, SIG_DFL);
       (void)signal(SIGSEGV, SIG_DFL);
       (void)signal(SIGTERM, SIG_DFL);
+      (void)signal(SIGCHLD, SIG_DFL);
 
-      close(1);
-      dup(2);
+      while (dup2(2, 1) < 0 && (errno == EINTR))
+       ;
       closeall();
       if (run_mode)
        {
          char path[128];
-         snprintf(path, sizeof(path), INITDDIR "/%s", prg);
+         snprintf(path, sizeof(path), "/etc/init.d/%s", prg);
          execlp(path, path, arg, (char *)0);
        }
       else if (arg)
@@ -377,7 +449,7 @@ int run_single(char *prg, int spl)
       _exit(1);
     }
 
-   while (waitpid(pid, &r, 0) == (pid_t)-1)
+   while ((waitpid(pid, &r, 0) == (pid_t)-1) && (errno == EINTR))
      ;
    callsplash(spl, prg, arg);
    return WIFEXITED(r) ? WEXITSTATUS(r) : (WIFSIGNALED(r) ? 1 : 255);
@@ -420,8 +492,7 @@ void storebuf(struct prg *p)
   (void)memcpy(gtimo_buf + gtimo_buflen, p->buf, p->len);
   gtimo_buflen += p->len;
   p->len = 0;
-  glastio.tv_sec  = now.tv_sec;
-  glastio.tv_usec = now.tv_usec;
+  glastio = now;
 }
 
 void flushbuf(void)
@@ -475,10 +546,10 @@ void detach(struct prg *p, const int sto
     {
       if ((r = fork()) == 0)
        {
-         close(0);
-         dup(p->fd);
-         close(1);
-         dup(2);
+         while (dup2(p->fd, 0) < 0 && (errno == EINTR))
+           ;
+         while (dup2(2, 1) < 0 && (errno == EINTR))
+           ;
          closeall();
          execlp(myname, myname, "-f", "--", p->name, NULL);
          do_forward();
@@ -490,12 +561,25 @@ void detach(struct prg *p, const int sto
   p->fd = 0;
 }
 
-void sigchld(int sig __attribute__ ((unused)))
+static void sigchld(int sig __attribute__ ((unused)))
 {
   char c = 0;
   write(pidpipe[1], &c, 1);
 }
 
+static void sigwinch(int sig __attribute__ ((unused)))
+{
+  if (ioctl(0, TIOCGWINSZ, &wz) < 0)
+    {
+      wzok = 0;
+      return;
+    }
+  if (wz.ws_row == 0) wz.ws_row = 24;
+  if (wz.ws_col == 0) wz.ws_col = 80;
+  snprintf(sz.env_row, sizeof(sz.env_row), "LINES=%d",   wz.ws_row);
+  snprintf(sz.env_col, sizeof(sz.env_col), "COLUMNS=%d", wz.ws_col);
+}
+
 void usage(int status)
 {
   fprintf(stderr, "usage: startpar [options] [-a arg] prgs\n");
@@ -513,25 +597,24 @@ void usage(int status)
 
 int main(int argc, char **argv)
 {
-  volatile int broken;
-  int timo = -1;
   int gtimo = -1;
-  int r, c, i, s, last, num;
+  int timo = -1;
+  int isgtimo;
+  int forw = 0;
+  int c, i, num;
+  int limit;
   int *resvec;
-  int maxfd;
   fd_set rset;
   struct timeval tv;
   struct prg *p;
-  pid_t pid;
-  int forw = 0;
   char pipebuf[16];
-  int isgtimo;
   struct prg *gtimo_running = 0;
   struct prg *interactive_task = NULL;
-  int active, limit;
-  char *prev_level = NULL, *run_level = NULL;
+  char *prev_level = getenv("PREVLEVEL");
+  char *run_level = getenv("RUNLEVEL");
   char *splashopt = 0;
 
+  (void)signal(SIGCHLD, SIG_DFL);
   numcpu = sysconf(_SC_NPROCESSORS_ONLN);
   myname = argv[0];
 
@@ -573,9 +656,9 @@ int main(int argc, char **argv)
          usage(0);
          break;
        case 'i':
-         iorate = atoi(optarg);
-         if (iorate <= 0)
-           iorate = 800;
+         iorate = atof(optarg);
+         if (iorate < 0.0)
+           iorate = 800.0;
          break;
        default:
          usage(1);
@@ -609,6 +692,8 @@ int main(int argc, char **argv)
       char makefile[64];
       if (!strcmp(run_mode, "boot"))
        arg = "start";
+      else if (!strcmp(run_mode, "halt"))
+       arg = "stop";
       else if (!strcmp(run_mode, "start") || !strcmp(run_mode, "stop"))
        {
          arg = run_mode;
@@ -623,11 +708,12 @@ int main(int argc, char **argv)
          fprintf(stderr, "invalid run mode %s\n", run_mode);
          exit(1);
        }
-      snprintf(makefile, sizeof(makefile), INITDDIR "/.depend.%s", run_mode);
+      snprintf(makefile, sizeof(makefile), "/etc/init.d/.depend.%s", run_mode);
       parse_makefile(makefile);
       check_run_files(run_mode, prev_level, run_level);
 
       argc = tree_entries;                     /* number of handled scripts */
+      isstart = !strcmp(arg, "start");
 
       if (argc == 0)
        exit(0);
@@ -639,7 +725,7 @@ int main(int argc, char **argv)
 
       inpar = par;                             /* the original argument of 
parallel procs per cpu */
 
-      par = checkpar(inpar, run_mode);         /* the number of parallel procs 
on all cpu's */
+      par = checkpar(inpar, isstart);          /* the number of parallel procs 
on all cpu's */
 
       if (par > argc)                          /* not more than the number of 
all scripts */
        par = argc;
@@ -651,6 +737,9 @@ int main(int argc, char **argv)
       if (par < 0)
        usage(1);
 
+      if (arg)
+       isstart = !strcmp(arg, "start");
+
       if (argc == 0)
        exit(0);
 
@@ -661,7 +750,7 @@ int main(int argc, char **argv)
 
       inpar = par;                             /* the original argument of 
parallel procs per cpu */
 
-      par = checkpar(inpar, "stop");           /* the number of parallel procs 
on all cpu's */
+      par = checkpar(inpar, isstart);          /* the number of parallel procs 
on all cpu's */
 
       if (par > argc)                          /* not more than the number of 
all scripts */
        par = argc;
@@ -674,12 +763,13 @@ int main(int argc, char **argv)
 
   if (argc == 1)
     {
-      if (run_mode) {
-       *nodevec = pickup_task();
-       if (*nodevec) {
-         *resvec = run_single((*nodevec)->name, calcsplash(0, 1, splashopt));
-         finish_task(*nodevec);
-       }
+      if (run_mode)
+       {
+         if ((*nodevec = pickup_task()))
+         {
+           *resvec = run_single((*nodevec)->name, calcsplash(0, 1, splashopt));
+           finish_task(*nodevec);
+         }
       } else
        *resvec = run_single(*argv, calcsplash(0, 1, splashopt));
       goto finished;
@@ -691,6 +781,15 @@ int main(int argc, char **argv)
   if (!gtimo_buf)
     gtimo_bufsize = 0;                         /* Accept error due memory 
shortage */
 
+  sa.sa_handler = sigwinch;
+  sa.sa_flags = SA_RESTART|SA_NODEFER;
+  (void)sigemptyset(&sa.sa_mask);
+  if (sigaction(SIGWINCH, &sa, 0))
+    {
+      perror("sigwinch sigaction");
+      exit(1);
+    }
+
   if (tcgetattr(0, &tio))
     {
       perror("tcgetattr");
@@ -698,6 +797,13 @@ int main(int argc, char **argv)
     }
   if (ioctl(0, TIOCGWINSZ, &wz) == 0)
     wzok = 1;
+  if (wz.ws_row == 0) wz.ws_row = 24;
+  if (wz.ws_col == 0) wz.ws_col = 80;
+
+  strcat(&sz.env_row[0], "LINES=");
+  strcat(&sz.env_col[0], "COLUMNS=");
+  snprintf(sz.env_row, sizeof(sz.env_row), "LINES=%d",   wz.ws_row);
+  snprintf(sz.env_col, sizeof(sz.env_col), "COLUMNS=%d", wz.ws_col);
 
   if (pipe(pidpipe))
     {
@@ -715,60 +821,61 @@ int main(int argc, char **argv)
       exit(1);
     }
 
-  broken = 0;                                  /* Detect broken hardware */
   gettimeofday(&glastio, 0);
-  limit = checklimit(inpar, (run_mode) ? run_mode : "stop");
-  lastlim.tv_sec  = glastio.tv_sec;
-  lastlim.tv_usec = glastio.tv_usec;
+  limit = checklimit(inpar, isstart);
+  lastlim = glastio;
   for (;;)
     {
+      int active = 0;
+      int maxfd = -1;
+      int last = -1;
+      pid_t pid = 0;
+      int r = 0, s;
       long diff;
+      int devpts = 0;
 
       gettimeofday(&now, 0);
       FD_ZERO(&rset);
-      tv.tv_sec  = now.tv_sec;
-      tv.tv_usec = now.tv_usec;
-      last = -1;
-      maxfd = -1;
-      active = 0;
-      pid = 0;
-
-      diff = ((now.tv_sec  - lastlim.tv_sec) * 1000) +
-            ((now.tv_usec - lastlim.tv_usec)/ 1000);
-      if (diff >= 300 || diff < 0)
+      tv = now;
+
+      if ((diff = timerdiff(now, lastlim)) >= 300 || diff < 0)
        {
 #if DEBUG
          fprintf(stderr, "%d: doing checklimit after %ldms %ld\n", getpid(), 
diff, time(0));
 #endif
-         limit = checklimit(inpar, (run_mode) ? run_mode : "stop");
-         if (limit > argc)
+         if ((limit = checklimit(inpar, isstart)) > argc)
            limit = argc;                       /* not more than the number of 
all scripts */
-         lastlim.tv_sec  = now.tv_sec;
-         lastlim.tv_usec = now.tv_usec;
+         lastlim = now;
          diff = 0;
        } 
 #if DEBUG
-      fprintf(stderr, "par = %d, inpar = %d, limit = %d (diff=%ld)\n", par, 
inpar, limit, diff);
+      fprintf(stderr, "par=%d, inpar=%d, limit=%d (diff=%ld)\n", par, inpar, 
limit, diff);
 #endif
-      for (s = 0; s < par; s++)
+      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 handle this here */
+           continue;                           /* don't count this here */
          if (p->fd || p->pid)
            active++;                           /* count all running procs */
          if (p->fd == 0)
            {
-             if (p->pid == 0 && num < argc && !interactive_task)
+             if (interactive_task)
+               continue;                       /* dont't start new processes */
+             if (num >= argc)
+               continue;                       /* nothing to do */
+             if (p->pid == 0)
                {
                  if (active >= limit)
-                   break;                      /* load balancing */
+                   continue;                   /* load balancing */
                  if (run_mode)
                    {
-                     nodevec[num] = pickup_task();
-                     if (! nodevec[num])
+                     if ((nodevec[num] = pickup_task()) == NULL)
                        continue;
-                     if (nodevec[num]->interactive)
+                     if (nodevec[num]->interactive || !devpts)
                        interactive_task = p;
                      p->name = nodevec[num]->name;
                    }
@@ -777,17 +884,17 @@ int main(int argc, char **argv)
                  p->splashadd = calcsplash(num, argc, splashopt);
                  p->num = num++;
                  if (interactive_task)
-                   break;
+                   continue;                   /* don't start this here */
                  run(p);
-                 active++;                     /* remember this _new_ proc!!! 
*/
                  if (p->pid == 0)
                    {
                      resvec[p->num] = 1;
                      if (run_mode)
                        finish_task(nodevec[p->num]);
-                     active--;                 /* fork in run() failed, sigh! 
*/
                    }
-                 break;
+                 gettimeofday(&now, 0);
+                 tv = now;
+                 goto account;                 /* take the new process into 
account */
                }
              continue;
            }
@@ -796,18 +903,13 @@ int main(int argc, char **argv)
            maxfd = p->fd;
          if (p->len == 0)
            continue;
-          if ((last < 0) || (tv.tv_sec > p->lastio.tv_sec) ||
-             (tv.tv_sec == p->lastio.tv_sec && tv.tv_usec > p->lastio.tv_usec))
+          if ((last < 0) || timercmp(&tv,&p->lastio,>))
            {
              last = s;
-             tv.tv_sec = p->lastio.tv_sec;
-             tv.tv_usec = p->lastio.tv_usec;
+             tv = p->lastio;
            }
-
        } /* for (s = 0; s < par; s++) */
 
-      broken++;                                        /* no endless loops due 
broken systems */
-
       if (interactive_task)
        {
          if (active == 0)
@@ -819,36 +921,31 @@ int main(int argc, char **argv)
              p->pid = 0;
              p->fd = 0;
              interactive_task = NULL;
-             broken = 0;                       /* run_single() uses waitpid() 
*/
              continue;
            }
        }
 
-      if ((active < limit) && (num < argc) && (broken < argc))
-       continue;                               /* try to start new processes */
-
       if (active == 0)
        {
          if (num < argc)
            fprintf(stderr, "ERROR: not all processed (%d of %d)\n", num, argc);
 #if DEBUG
-         if ((pid = waitpid(-1, &r, maxfd < 0 ? 0 : WNOHANG)) > 0)
+         if ((pid = waitpid(-1, &r, (maxfd < 0 ? 0 : WNOHANG)|WUNTRACED)) > 0)
            fprintf(stderr, "ERROR: not all processes are checked\n");
 #endif
          break;
        }
-#if 0
+#if DEBUG
       fprintf(stderr, "active = %d\n", active);
 #endif
       if (active == 1 && last >= 0)
        {
          p = prgs + last;
-         if ((pid = waitpid(p->pid, &r, maxfd < 0 ? 0 : WNOHANG)) == 0)
+         if ((pid = waitpid(p->pid, &r, (maxfd < 0 ? 0 : WNOHANG)|WUNTRACED)) 
== 0)
            {
              writebuf(p);
              continue;
            }
-          broken = 0;
        }
 
       FD_SET(pidpipe[0], &rset);
@@ -857,10 +954,7 @@ int main(int argc, char **argv)
        ;
 
       if (pid == 0)
-       {
-         pid = waitpid(-1, &r, maxfd < 0 ? 0 : WNOHANG);
-         broken = 0;
-       }
+       pid = waitpid(-1, &r, (maxfd < 0 ? 0 : WNOHANG)|WUNTRACED);
 
       if (pid > 0)
        {
@@ -871,6 +965,16 @@ int main(int argc, char **argv)
              p = prgs + s;
              if (p->pid == pid)
                {
+                 if (WIFSTOPPED(r))
+                   {
+                     if (WSTOPSIG(r) == SIGTTIN)
+                       {
+                         pid_t pg = getpgid(pid);
+                         if (pg > 0)
+                           killpg(pg, SIGCONT);
+                       }
+                     continue;
+                   }
                  callsplash(p->splashadd, p->name, arg);
                  resvec[p->num] = WIFEXITED(r) ? WEXITSTATUS(r) : 
(WIFSIGNALED(r) ? 1 : 255);
                  if (run_mode)
@@ -911,12 +1015,11 @@ int main(int argc, char **argv)
       isgtimo = 0;
       if (gtimo >= 0 && !gtimo_running && last >= 0 && prgs[last].pid)
        {
-         const long glsec = glastio.tv_sec + gtimo;
-         if ((timo < 0) || (tv.tv_sec > glsec) ||
-             (tv.tv_sec == glsec && tv.tv_usec > glastio.tv_usec))
+         struct timeval gl = glastio;
+         gl.tv_sec += gtimo;
+         if ((timo < 0) || timercmp(&tv,&gl,>))
            {
-             tv.tv_sec  = glastio.tv_sec;
-             tv.tv_usec = glastio.tv_usec;
+             tv = glastio;
              tv.tv_sec += gtimo;
              isgtimo = 1;
            }
@@ -1015,8 +1118,7 @@ int main(int argc, char **argv)
                    memmove(p->buf, p->buf + p->len, sizeof(p->buf) - p->len);
                  p->len = sizeof(p->buf) - p->len;
                }
-             p->lastio.tv_sec  = now.tv_sec;
-             p->lastio.tv_usec = now.tv_usec;
+             p->lastio = now;
            } /* for (s = 0; s < par; s++) */
        }
     } /* for (;;) */
---



-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to