[Pkg-sysvinit-devel] Bug#484883: [sysvinit]: startpar 0.52 + Debian compat.

Kel Modderman kel at otaku42.de
Sun Jan 4 14:51:50 UTC 2009


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 (;;) */
---





More information about the Pkg-sysvinit-devel mailing list