~ubuntu-branches/ubuntu/karmic/sysvinit/karmic-updates

« back to all changes in this revision

Viewing changes to debian/startpar/startpar.c

  • Committer: Bazaar Package Importer
  • Author(s): Scott James Remnant
  • Date: 2009-09-07 19:56:53 UTC
  • mfrom: (1.1.4 upstream) (2.1.7 sid)
  • Revision ID: james.westby@ubuntu.com-20090907195653-2i6t0j91wfbf1f0d
Tags: 2.87dsf-4ubuntu1
* Merge from debian unstable, remaining changes:
  - Support Cell processor:
    + debian/initscripts/postinst: Create spu system group and /spu mount
      point if we are running on a Cell processor.
    + debian/initscripts/etc/init.d/mountkernfs.sh: Mount spufs if Cell
      processor is detected.
    + debian/initscripts/lib/init/mount-functions.sh: Modprobe spufs
      if not available.
    + debian/control: Add initscripts dependency 'passwd' for groupadd.
    (Forwarded to Debian #483399)
  - Use tmpfs mounts for /var/lock and /var/run:
    + debian/initscripts/share/default.rcS: Enable RAMRUN and RAMLOCK by
      default.
    + debian/initscripts.postinst: Enable RAMRUN and RAMLOCK in
      /etc/default/rcS on upgrades. This needs to be kept until the next
      LTS.
    + debian/initscripts/etc/init.d/mountkernfs.sh: Propagate files from the
      initramfs to our new /var/run, so that we can populate
      /var/run/sendsigs.omit from initramfs.
  - Boot ordering differences:
    + mountkernfs.sh: 02 -> 01
    + mountdevsubfs.sh: 04 -> 11
    + bootlogd: disabled by default
    + checkroot.sh: 10 -> 20
    + mtab.sh: 12 -> 22
  - debian/patches/91_sulogin_lockedpw.dpatch: Disable "root account is
    locked" warning, since this is the default in Ubuntu. Document this in
    sulogin.8.
  - debian/control: Drop Essential: yes from packages since we use Upstart.
  - debian/control: Conflict/Replace sysvconfig which has also previously
    provided service(8).
  - debian/control, debian/rules: Previous name for sysvinit-utils was
    'sysvutils' in Ubuntu, so Conflict/Replace/Provide it. Also create a
    dummy sysvutils package, since Hardy has reverse versioned dependencies
    to it. This needs to be kept until after the next LTS.
  - debian/control: Depend on lsb-base (>= 3.2-14) for status_of_proc()
    function.
  - debian/initscripts/etc/init.d/checkfs.sh: Don't depend on hwclockfirst
    which Ubuntu does not have.
  - debian/initscripts/etc/init.d/mountkernfs.sh: Always mount devpts, and
    do not touch /dev/ptmx (which is already managed by udev).
  - debian/initscripts/etc/init.d/mountkernfs.sh: mount fusectl if it is
    available
  - debian/initscripts/etc/init.d/mountkernfs.sh: mount securityfs if it is
    available. This allows for easier AppArmor confinement of applications
    early in the boot process. LP: #399954
  - debian/initscripts/etc/init.d/mountkernfs.sh: mount debugfs if it is
    available.
  - debian/initscripts/etc/init.d/ondemand: Sleep for 60 seconds, then
    set CPU Frequency Scaling governor to "ondemand".   LP: #341573.
  - debian/initscripts/etc/init.d/umountfs: Don't unmount filesystems
    that precede root or use force for some mountpoints.
  - debian/initscripts/etc/network/if-up.d/mountnfs: Rename ifstate
    file to /var/run/network/ifstate
  - ./debian/initscripts/lib/init/usplash-fsck-functions.sh: Use blkid,
    vol_id is gone.
  - debian/initscripts.{pre,postinst}: waitnfs.sh -> mountnfs.sh renaming
    transition. This needs to be kept until after the next LTS.

LP: #32455, #94120, #160197, #382097 (amongst others).

* debian/sysv-rc/sbin/update-rc.d: Dropped support for "multiuser"
  command-line option.
* debian/rules: Compat symlink from /usr/bin/service to /usr/sbin/service
* debian/initscripts.postinst: Transition from bootlogs.sh to bootlogs

* debian/sysv-rc.postinst: Don't try and use insserv by default, though
  everything's in place for you to try if you like.  It can be activated
  with:
      USEINSSERV=yes dpkg-reconfigure sysv-rc

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
#include <sys/select.h>
30
30
#include <sys/time.h>
31
31
#include <sys/ioctl.h>
 
32
#include <sys/socket.h>
 
33
#include <sys/un.h>
32
34
#include <sys/sysinfo.h>
33
35
#include <sys/stat.h>
34
36
#include <time.h>
40
42
#include "makeboot.h"
41
43
#include "proc.h"
42
44
 
 
45
#define timerdiff(n,l) (__extension__ ({ (((n).tv_sec-(l).tv_sec)*1000)+(((n).tv_usec-(l).tv_usec)/1000); }))
 
46
 
43
47
typedef enum _boolean {false, true} boolean;
44
48
extern char *optarg;
45
49
extern int optind;
48
52
static char *myname;
49
53
static struct termios tio;
50
54
static struct winsize wz;
51
 
static int wzok;
 
55
static struct {
 
56
  char env_row[128];
 
57
  char env_col[128];
 
58
} sz;
 
59
static sig_atomic_t wzok;
52
60
static char *arg;
 
61
static boolean isstart;
53
62
static struct sigaction sa;
54
63
static struct timeval glastio;
55
64
static struct timeval now;
57
66
static char *run_mode = NULL;
58
67
static struct makenode **nodevec;
59
68
 
 
69
static enum { Unknown, Preload, NoPreload } ispreload = Unknown;
 
70
 
60
71
#define PBUF_SIZE       8192
61
72
struct prg {
62
 
  char *name;
 
73
  const char *name;
 
74
  const char *arg0;
63
75
  int num;
64
76
  int fd;
65
77
  pid_t pid;
72
84
static struct prg *prgs;
73
85
static int inpar, par;
74
86
static int pidpipe[2];
75
 
static int iorate = 800;
 
87
static double iorate = 800.0;
 
88
 
 
89
void sighandler_nopreload(int x)
 
90
{
 
91
    (void)x;
 
92
    ispreload = NoPreload;
 
93
}
 
94
 
 
95
 
 
96
void sighandler_preload(int x)
 
97
{
 
98
    (void)x;
 
99
    ispreload = Preload;
 
100
}
76
101
 
77
102
void *xcalloc(size_t nmemb, size_t size)
78
103
{
124
149
  int status;
125
150
  if (!splashpid)
126
151
    return;
127
 
  waitpid(splashpid, &status, 0);
 
152
  do {
 
153
    waitpid(splashpid, &status, 0);
 
154
  } while (errno == EINTR);
128
155
  splashpid = 0;
129
156
}
130
157
 
141
168
  close(pidpipe[1]);
142
169
}
143
170
 
144
 
void callsplash(int n, char *path, char *action)
 
171
void callsplash(int n, const char *path, char *action)
145
172
{
146
 
  char *p;
 
173
  const char *p;
147
174
  char sbuf[32];
148
175
  char tbuf[256];
149
176
  pid_t pid;
181
208
      splashpid = pid;
182
209
      return;
183
210
    }
184
 
  close(1);
185
 
  dup(2);
 
211
  while (dup2(2, 1) < 0 && (errno == EINTR))
 
212
    ;
186
213
  closeall();
187
214
  execl("/sbin/splash", "splash", "-p", sbuf, "-t", tbuf, splashcfg, (char *)0);
188
215
  _exit(1);
204
231
      p->len -= r;
205
232
      b += r;
206
233
    }
207
 
  glastio.tv_sec  = now.tv_sec;
208
 
  glastio.tv_usec = now.tv_usec;
 
234
  glastio = now;
209
235
}
210
236
 
211
 
static int checksystem(const int par, const char *mode, const boolean limit)
 
237
static int checksystem(const int par, const boolean start, const boolean limit)
212
238
{
213
239
  const      int pg_size       = sysconf(_SC_PAGESIZE);
214
240
  const long int minphys_bytes = (sysconf(_SC_LONG_BIT) > 32L) ? (2<<22) : (2<<21);
223
249
  if (pg_size < 0)
224
250
    return par;
225
251
 
226
 
  if (mode && strcmp(mode, "stop") == 0)
 
252
  if (!start)
227
253
    minphys_pg = avphys_pg;
228
254
  else
229
255
    minphys_pg = minphys_bytes / pg_size;
240
266
  if (read_proc(&prcs_run, &prcs_blked))
241
267
    return par;
242
268
 
243
 
  newpar = (par*numcpu) - prcs_run + 1; /* +1 for startpar its self */
244
 
  newpar -= (prcs_blked * iorate);      /* I/O load reduction */
 
269
  /* if we have preload running, we expect I/O not to be a problem */
 
270
  if (ispreload != NoPreload)
 
271
    prcs_blked = 0;
 
272
 
 
273
  newpar  = (par*numcpu) - prcs_run + 1;        /* +1 for startpar its self */
 
274
  newpar -= (int)(((double)prcs_blked)*iorate); /* I/O load reduction */
245
275
 
246
276
#if DEBUG
247
 
  fprintf(stderr, "checksystem par=%d newpar=%d (prcs_run=%u) %ld\n", par, newpar, prcs_run, time(0));
 
277
  fprintf(stderr, "checksystem par=%d newpar=%d (prcs_run=%lu) %ld\n", par, newpar, prcs_run, time(0));
248
278
  dump_status();
249
279
#endif
250
280
  if (newpar <= 0)
253
283
    return newpar;
254
284
}
255
285
 
256
 
static inline int checklimit(const int par, const char *mode)
257
 
{
258
 
  return checksystem(par, mode, true);
259
 
}
260
 
 
261
 
static inline int checkpar(const int par, const char *mode)
262
 
{
263
 
  return checksystem(par, mode, false);
264
 
}
 
286
static inline int checklimit(const int par, const boolean start)
 
287
{
 
288
  return checksystem(par, start, true);
 
289
}
 
290
 
 
291
static inline int checkpar(const int par, const boolean start)
 
292
{
 
293
  return checksystem(par, start, false);
 
294
}
 
295
 
 
296
#define SOCK_PATH "/dev/shm/preload_sock"
265
297
 
266
298
void run(struct prg *p)
267
299
{
268
300
  char *m = 0;
 
301
  pid_t parent = getpid();
269
302
 
270
303
  p->len = 0;
271
304
  p->pid = (pid_t)0;
301
334
  (void)signal(SIGQUIT, SIG_DFL);
302
335
  (void)signal(SIGSEGV, SIG_DFL);
303
336
  (void)signal(SIGTERM, SIG_DFL);
 
337
  (void)signal(SIGCHLD, SIG_DFL);
304
338
 
305
339
  if (setpgid(0, 0))
306
340
    perror("setpgid");
307
341
 
308
342
  if (m && p->fd)
309
343
    {
310
 
      close(1);
 
344
      while (close(1) < 0 && (errno == EINTR))
 
345
        ;
311
346
      if (open(m, O_RDWR) != 1)
312
347
        {
313
348
          perror(m);
314
349
          _exit(1);
315
350
        }
316
 
      close(2);
317
 
      dup(1);
 
351
      while (dup2(1, 2) < 0 && (errno == EINTR))
 
352
        ;
318
353
      tio.c_oflag &= ~OPOST;
319
354
      if (tcsetattr(1, TCSANOW, &tio))
320
355
        perror("tcsetattr");
321
 
      if (wzok && ioctl(0, TIOCSWINSZ, &wz))
322
 
        perror("TIOCSWINSZ");
 
356
      if (wzok)
 
357
        ioctl(1, TIOCSWINSZ, &wz);
 
358
      putenv(sz.env_row);
 
359
      putenv(sz.env_col);
323
360
    }
324
361
  else
325
362
    {
326
 
      close(1);
327
 
      dup(2);
 
363
      while (dup2(2, 1) < 0 && (errno == EINTR))
 
364
        ;
328
365
    }
329
366
 
330
367
  closeall();
331
368
 
332
 
  if (run_mode) {
333
 
    char path[128];
334
 
    snprintf(path, sizeof(path), INITDDIR "/%s", p->name);
335
 
    execlp(path, path, arg, (char *)0);
336
 
  } else if (arg)
337
 
    execlp(p->name, p->name, arg, (char *)0);
 
369
  if (!strcmp(arg, "start")) 
 
370
    { 
 
371
      int s, t, len;
 
372
      pid_t child;
 
373
      struct sockaddr_un remote;
 
374
      char str[100];
 
375
 
 
376
      s = socket(AF_UNIX, SOCK_STREAM, 0);
 
377
      if (s != -1) 
 
378
        {
 
379
          memset(&remote, 0, sizeof(struct sockaddr_un));
 
380
          remote.sun_family = AF_UNIX;
 
381
          strcpy(remote.sun_path, SOCK_PATH);
 
382
          len = strlen(remote.sun_path) + sizeof(remote.sun_family);
 
383
 
 
384
          t = connect(s, (struct sockaddr *)&remote, len);
 
385
          if (t != -1) 
 
386
            {
 
387
              if (ispreload != Preload)
 
388
                kill(parent, SIGUSR1);
 
389
              send(s, p->name, strlen(p->name), 0);
 
390
              recv(s, str, 100, 0);
 
391
            } 
 
392
          else if ( ispreload == Unknown) 
 
393
            {
 
394
              /*
 
395
               * if we connected to preload once, we know it ran.
 
396
               * In case we can't connect to it later, it means it did
 
397
               * its job and we can guess I/O is no longer a problem. 
 
398
               */
 
399
              kill(parent, SIGUSR2);
 
400
            }
 
401
          close(s);
 
402
          /*
 
403
           * if we use preload, we fork again to make bootcharts easier to read.
 
404
           * The reason is that the name of the init script will otherwise be used
 
405
           * when in reality the above code waited for preload. If we fork away
 
406
           * before the exec, the waiting code will be folded into startpar
 
407
           */
 
408
          child = fork();
 
409
          if (child) {
 
410
                int status;
 
411
                int ret = waitpid(child, &status, 0);
 
412
                if (ret == -1)
 
413
                        perror("waitpid");
 
414
                exit(WEXITSTATUS(status));
 
415
          }
 
416
        }
 
417
    }
 
418
 
 
419
  if (run_mode)
 
420
    {
 
421
      char path[128];
 
422
      snprintf(path, sizeof(path), "/etc/init.d/%s", p->name);
 
423
      execlp(path, p->arg0, arg, (char *)0);
 
424
    }
 
425
  else if (arg)
 
426
    execlp(p->name, p->arg0, arg, (char *)0);
338
427
  else
339
 
    execlp(p->name, p->name, (char *)0);
 
428
    execlp(p->name, p->arg0, (char *)0);
340
429
  perror(p->name);
341
430
  _exit(1);
342
431
}
343
432
 
344
 
int run_single(char *prg, int spl)
 
433
int run_single(const char *prg, const char *arg0, int spl)
345
434
{
346
435
  pid_t pid;
347
436
  int r;
359
448
      (void)signal(SIGQUIT, SIG_DFL);
360
449
      (void)signal(SIGSEGV, SIG_DFL);
361
450
      (void)signal(SIGTERM, SIG_DFL);
 
451
      (void)signal(SIGCHLD, SIG_DFL);
362
452
 
363
 
      close(1);
364
 
      dup(2);
 
453
      while (dup2(2, 1) < 0 && (errno == EINTR))
 
454
        ;
365
455
      closeall();
366
456
      if (run_mode)
367
457
        {
368
458
          char path[128];
369
 
          snprintf(path, sizeof(path), INITDDIR "/%s", prg);
370
 
          execlp(path, path, arg, (char *)0);
 
459
          snprintf(path, sizeof(path), "/etc/init.d/%s", prg);
 
460
          execlp(path, arg0 ? arg0 : path, arg, (char *)0);
371
461
        }
372
462
      else if (arg)
373
 
        execlp(prg, prg, arg, (char *)0);
 
463
        execlp(prg, arg0 ? arg0 : prg, arg, (char *)0);
374
464
      else
375
 
        execlp(prg, prg, (char *)0);
 
465
        execlp(prg, arg0 ? arg0 : prg, (char *)0);
376
466
      perror(prg);
377
467
      _exit(1);
378
468
    }
379
469
 
380
 
   while (waitpid(pid, &r, 0) == (pid_t)-1)
 
470
   while ((waitpid(pid, &r, 0) == (pid_t)-1) && (errno == EINTR))
381
471
     ;
382
472
   callsplash(spl, prg, arg);
383
473
   return WIFEXITED(r) ? WEXITSTATUS(r) : (WIFSIGNALED(r) ? 1 : 255);
420
510
  (void)memcpy(gtimo_buf + gtimo_buflen, p->buf, p->len);
421
511
  gtimo_buflen += p->len;
422
512
  p->len = 0;
423
 
  glastio.tv_sec  = now.tv_sec;
424
 
  glastio.tv_usec = now.tv_usec;
 
513
  glastio = now;
425
514
}
426
515
 
427
516
void flushbuf(void)
475
564
    {
476
565
      if ((r = fork()) == 0)
477
566
        {
478
 
          close(0);
479
 
          dup(p->fd);
480
 
          close(1);
481
 
          dup(2);
 
567
          while (dup2(p->fd, 0) < 0 && (errno == EINTR))
 
568
            ;
 
569
          while (dup2(2, 1) < 0 && (errno == EINTR))
 
570
            ;
482
571
          closeall();
483
572
          execlp(myname, myname, "-f", "--", p->name, NULL);
484
573
          do_forward();
490
579
  p->fd = 0;
491
580
}
492
581
 
493
 
void sigchld(int sig __attribute__ ((unused)))
 
582
static void sigchld(int sig __attribute__ ((unused)))
494
583
{
495
584
  char c = 0;
496
585
  write(pidpipe[1], &c, 1);
497
586
}
498
587
 
 
588
static void sigwinch(int sig __attribute__ ((unused)))
 
589
{
 
590
  if (ioctl(0, TIOCGWINSZ, &wz) < 0)
 
591
    {
 
592
      wzok = 0;
 
593
      return;
 
594
    }
 
595
  if (wz.ws_row == 0) wz.ws_row = 24;
 
596
  if (wz.ws_col == 0) wz.ws_col = 80;
 
597
  snprintf(sz.env_row, sizeof(sz.env_row), "LINES=%d",   wz.ws_row);
 
598
  snprintf(sz.env_col, sizeof(sz.env_col), "COLUMNS=%d", wz.ws_col);
 
599
}
 
600
 
499
601
void usage(int status)
500
602
{
501
603
  fprintf(stderr, "usage: startpar [options] [-a arg] prgs\n");
513
615
 
514
616
int main(int argc, char **argv)
515
617
{
516
 
  volatile int broken;
 
618
  int gtimo = -1;
517
619
  int timo = -1;
518
 
  int gtimo = -1;
519
 
  int r, c, i, s, last, num;
 
620
  int isgtimo;
 
621
  int forw = 0;
 
622
  int c, i, num;
 
623
  int limit;
520
624
  int *resvec;
521
 
  int maxfd;
522
625
  fd_set rset;
523
626
  struct timeval tv;
524
627
  struct prg *p;
525
 
  pid_t pid;
526
 
  int forw = 0;
527
628
  char pipebuf[16];
528
 
  int isgtimo;
529
629
  struct prg *gtimo_running = 0;
530
630
  struct prg *interactive_task = NULL;
531
 
  int active, limit;
532
 
  char *prev_level = NULL, *run_level = NULL;
 
631
  char *prev_level = getenv("PREVLEVEL");
 
632
  char *run_level = getenv("RUNLEVEL");
533
633
  char *splashopt = 0;
534
634
 
 
635
  (void)signal(SIGUSR1, sighandler_preload);
 
636
  (void)signal(SIGUSR2, sighandler_nopreload);
 
637
 
 
638
  (void)signal(SIGCHLD, SIG_DFL);
535
639
  numcpu = sysconf(_SC_NPROCESSORS_ONLN);
536
640
  myname = argv[0];
537
641
 
573
677
          usage(0);
574
678
          break;
575
679
        case 'i':
576
 
          iorate = atoi(optarg);
577
 
          if (iorate <= 0)
578
 
            iorate = 800;
 
680
          iorate = atof(optarg);
 
681
          if (iorate < 0.0)
 
682
            iorate = 800.0;
579
683
          break;
580
684
        default:
581
685
          usage(1);
609
713
      char makefile[64];
610
714
      if (!strcmp(run_mode, "boot"))
611
715
        arg = "start";
 
716
      else if (!strcmp(run_mode, "halt"))
 
717
        arg = "stop";
612
718
      else if (!strcmp(run_mode, "start") || !strcmp(run_mode, "stop"))
613
719
        {
614
720
          arg = run_mode;
623
729
          fprintf(stderr, "invalid run mode %s\n", run_mode);
624
730
          exit(1);
625
731
        }
626
 
      snprintf(makefile, sizeof(makefile), INITDDIR "/.depend.%s", run_mode);
 
732
      snprintf(makefile, sizeof(makefile), "/etc/init.d/.depend.%s", run_mode);
627
733
      parse_makefile(makefile);
628
734
      check_run_files(run_mode, prev_level, run_level);
629
735
 
630
736
      argc = tree_entries;                      /* number of handled scripts */
 
737
      isstart = !strcmp(arg, "start");
631
738
 
632
739
      if (argc == 0)
633
740
        exit(0);
639
746
 
640
747
      inpar = par;                              /* the original argument of parallel procs per cpu */
641
748
 
642
 
      par = checkpar(inpar, run_mode);          /* the number of parallel procs on all cpu's */
 
749
      par = checkpar(inpar, isstart);           /* the number of parallel procs on all cpu's */
643
750
 
644
751
      if (par > argc)                           /* not more than the number of all scripts */
645
752
        par = argc;
651
758
      if (par < 0)
652
759
        usage(1);
653
760
 
 
761
      if (arg)
 
762
        isstart = !strcmp(arg, "start");
 
763
 
654
764
      if (argc == 0)
655
765
        exit(0);
656
766
 
661
771
 
662
772
      inpar = par;                              /* the original argument of parallel procs per cpu */
663
773
 
664
 
      par = checkpar(inpar, "stop");            /* the number of parallel procs on all cpu's */
 
774
      par = checkpar(inpar, isstart);           /* the number of parallel procs on all cpu's */
665
775
 
666
776
      if (par > argc)                           /* not more than the number of all scripts */
667
777
        par = argc;
674
784
 
675
785
  if (argc == 1)
676
786
    {
677
 
      if (run_mode) {
678
 
        *nodevec = pickup_task();
679
 
        if (*nodevec) {
680
 
          *resvec = run_single((*nodevec)->name, calcsplash(0, 1, splashopt));
681
 
          finish_task(*nodevec);
682
 
        }
 
787
      if (run_mode)
 
788
        {
 
789
          if ((*nodevec = pickup_task()))
 
790
          {
 
791
            *resvec = run_single((*nodevec)->name, (*nodevec)->arg0, calcsplash(0, 1, splashopt));
 
792
            finish_task(*nodevec);
 
793
          }
683
794
      } else
684
 
        *resvec = run_single(*argv, calcsplash(0, 1, splashopt));
 
795
        *resvec = run_single(*argv, *argv, calcsplash(0, 1, splashopt));
685
796
      goto finished;
686
797
    }
687
798
 
691
802
  if (!gtimo_buf)
692
803
    gtimo_bufsize = 0;                          /* Accept error due memory shortage */
693
804
 
 
805
  sa.sa_handler = sigwinch;
 
806
  sa.sa_flags = SA_RESTART|SA_NODEFER;
 
807
  (void)sigemptyset(&sa.sa_mask);
 
808
  if (sigaction(SIGWINCH, &sa, 0))
 
809
    {
 
810
      perror("sigwinch sigaction");
 
811
      exit(1);
 
812
    }
 
813
 
694
814
  if (tcgetattr(0, &tio))
695
815
    {
696
816
      perror("tcgetattr");
698
818
    }
699
819
  if (ioctl(0, TIOCGWINSZ, &wz) == 0)
700
820
    wzok = 1;
 
821
  if (wz.ws_row == 0) wz.ws_row = 24;
 
822
  if (wz.ws_col == 0) wz.ws_col = 80;
 
823
 
 
824
  strcat(&sz.env_row[0], "LINES=");
 
825
  strcat(&sz.env_col[0], "COLUMNS=");
 
826
  snprintf(sz.env_row, sizeof(sz.env_row), "LINES=%d",   wz.ws_row);
 
827
  snprintf(sz.env_col, sizeof(sz.env_col), "COLUMNS=%d", wz.ws_col);
701
828
 
702
829
  if (pipe(pidpipe))
703
830
    {
715
842
      exit(1);
716
843
    }
717
844
 
718
 
  broken = 0;                                   /* Detect broken hardware */
719
845
  gettimeofday(&glastio, 0);
720
 
  limit = checklimit(inpar, (run_mode) ? run_mode : "stop");
721
 
  lastlim.tv_sec  = glastio.tv_sec;
722
 
  lastlim.tv_usec = glastio.tv_usec;
 
846
  limit = checklimit(inpar, isstart);
 
847
  lastlim = glastio;
723
848
  for (;;)
724
849
    {
 
850
      int active = 0;
 
851
      int maxfd = -1;
 
852
      int last = -1;
 
853
      pid_t pid = 0;
 
854
      int r = 0, s;
725
855
      long diff;
726
856
 
727
857
      gettimeofday(&now, 0);
728
858
      FD_ZERO(&rset);
729
 
      tv.tv_sec  = now.tv_sec;
730
 
      tv.tv_usec = now.tv_usec;
731
 
      last = -1;
732
 
      maxfd = -1;
733
 
      active = 0;
734
 
      pid = 0;
 
859
      tv = now;
735
860
 
736
 
      diff = ((now.tv_sec  - lastlim.tv_sec) * 1000) +
737
 
             ((now.tv_usec - lastlim.tv_usec)/ 1000);
738
 
      if (diff >= 300 || diff < 0)
 
861
      if ((diff = timerdiff(now, lastlim)) >= 300 || diff < 0)
739
862
        {
740
863
#if DEBUG
741
864
          fprintf(stderr, "%d: doing checklimit after %ldms %ld\n", getpid(), diff, time(0));
742
865
#endif
743
 
          limit = checklimit(inpar, (run_mode) ? run_mode : "stop");
744
 
          if (limit > argc)
 
866
          if ((limit = checklimit(inpar, isstart)) > argc)
745
867
            limit = argc;                       /* not more than the number of all scripts */
746
 
          lastlim.tv_sec  = now.tv_sec;
747
 
          lastlim.tv_usec = now.tv_usec;
 
868
          lastlim = now;
748
869
          diff = 0;
749
870
        } 
750
871
#if DEBUG
751
 
      fprintf(stderr, "par = %d, inpar = %d, limit = %d (diff=%ld)\n", par, inpar, limit, diff);
 
872
      fprintf(stderr, "par=%d, inpar=%d, limit=%d (diff=%ld)\n", par, inpar, limit, diff);
752
873
#endif
753
 
      for (s = 0; s < par; s++)
 
874
      for (s = 0; s < par; s++)                 /* never leave this with break!! */
754
875
        {
 
876
        account:                                /* for the new process below */
755
877
          p = prgs + s;
756
878
          if (p == interactive_task)
757
 
            continue;                           /* don't handle this here */
 
879
            continue;                           /* don't count this here */
758
880
          if (p->fd || p->pid)
759
881
            active++;                           /* count all running procs */
760
882
          if (p->fd == 0)
761
883
            {
762
 
              if (p->pid == 0 && num < argc && !interactive_task)
 
884
              if (interactive_task)
 
885
                continue;                       /* dont't start new processes */
 
886
              if (num >= argc)
 
887
                continue;                       /* nothing to do */
 
888
              if (p->pid == 0)
763
889
                {
764
890
                  if (active >= limit)
765
 
                    break;                      /* load balancing */
 
891
                    continue;                   /* load balancing */
766
892
                  if (run_mode)
767
893
                    {
768
 
                      nodevec[num] = pickup_task();
769
 
                      if (! nodevec[num])
 
894
                      if ((nodevec[num] = pickup_task()) == NULL)
770
895
                        continue;
771
896
                      if (nodevec[num]->interactive)
772
897
                        interactive_task = p;
773
898
                      p->name = nodevec[num]->name;
 
899
                      p->arg0 = nodevec[num]->arg0 ? nodevec[num]->arg0 : nodevec[num]->name;
774
900
                    }
775
 
                  else
 
901
                  else {
776
902
                    p->name = *argv++;
 
903
                    p->arg0 = p->name;
 
904
                  }
777
905
                  p->splashadd = calcsplash(num, argc, splashopt);
778
906
                  p->num = num++;
779
907
                  if (interactive_task)
780
 
                    break;
 
908
                    continue;                   /* don't start this here */
781
909
                  run(p);
782
 
                  active++;                     /* remember this _new_ proc!!! */
783
910
                  if (p->pid == 0)
784
911
                    {
785
912
                      resvec[p->num] = 1;
786
913
                      if (run_mode)
787
914
                        finish_task(nodevec[p->num]);
788
 
                      active--;                 /* fork in run() failed, sigh! */
789
915
                    }
790
 
                  break;
 
916
                  gettimeofday(&now, 0);
 
917
                  tv = now;
 
918
                  goto account;                 /* take the new process into account */
791
919
                }
792
920
              continue;
793
921
            }
796
924
            maxfd = p->fd;
797
925
          if (p->len == 0)
798
926
            continue;
799
 
          if ((last < 0) || (tv.tv_sec > p->lastio.tv_sec) ||
800
 
              (tv.tv_sec == p->lastio.tv_sec && tv.tv_usec > p->lastio.tv_usec))
 
927
          if ((last < 0) || timercmp(&tv,&p->lastio,>))
801
928
            {
802
929
              last = s;
803
 
              tv.tv_sec = p->lastio.tv_sec;
804
 
              tv.tv_usec = p->lastio.tv_usec;
 
930
              tv = p->lastio;
805
931
            }
806
 
 
807
932
        } /* for (s = 0; s < par; s++) */
808
933
 
809
 
      broken++;                                 /* no endless loops due broken systems */
810
 
 
811
934
      if (interactive_task)
812
935
        {
813
936
          if (active == 0)
814
937
            {
815
938
              p = interactive_task;
816
 
              resvec[p->num] = run_single(p->name, p->splashadd);
 
939
              resvec[p->num] = run_single(p->name, p->arg0, p->splashadd);
817
940
              if (run_mode)
818
941
                finish_task(nodevec[p->num]);
819
942
              p->pid = 0;
820
943
              p->fd = 0;
821
944
              interactive_task = NULL;
822
 
              broken = 0;                       /* run_single() uses waitpid() */
823
945
              continue;
824
946
            }
825
947
        }
826
948
 
827
 
      if ((active < limit) && (num < argc) && (broken < argc))
828
 
        continue;                               /* try to start new processes */
829
 
 
830
949
      if (active == 0)
831
950
        {
832
951
          if (num < argc)
833
952
            fprintf(stderr, "ERROR: not all processed (%d of %d)\n", num, argc);
834
953
#if DEBUG
835
 
          if ((pid = waitpid(-1, &r, maxfd < 0 ? 0 : WNOHANG)) > 0)
 
954
          if ((pid = waitpid(-1, &r, (maxfd < 0 ? 0 : WNOHANG)|WUNTRACED)) > 0)
836
955
            fprintf(stderr, "ERROR: not all processes are checked\n");
837
956
#endif
838
957
          break;
839
958
        }
840
 
#if 0
 
959
#if DEBUG
841
960
      fprintf(stderr, "active = %d\n", active);
842
961
#endif
843
962
      if (active == 1 && last >= 0)
844
963
        {
845
964
          p = prgs + last;
846
 
          if ((pid = waitpid(p->pid, &r, maxfd < 0 ? 0 : WNOHANG)) == 0)
 
965
          if ((pid = waitpid(p->pid, &r, (maxfd < 0 ? 0 : WNOHANG)|WUNTRACED)) == 0)
847
966
            {
848
967
              writebuf(p);
849
968
              continue;
850
969
            }
851
 
          broken = 0;
852
970
        }
853
971
 
854
972
      FD_SET(pidpipe[0], &rset);
857
975
        ;
858
976
 
859
977
      if (pid == 0)
860
 
        {
861
 
          pid = waitpid(-1, &r, maxfd < 0 ? 0 : WNOHANG);
862
 
          broken = 0;
863
 
        }
 
978
        pid = waitpid(-1, &r, (maxfd < 0 ? 0 : WNOHANG)|WUNTRACED);
864
979
 
865
980
      if (pid > 0)
866
981
        {
871
986
              p = prgs + s;
872
987
              if (p->pid == pid)
873
988
                {
 
989
                  if (WIFSTOPPED(r))
 
990
                    {
 
991
                      if (WSTOPSIG(r) == SIGTTIN)
 
992
                        {
 
993
                          pid_t pg = getpgid(pid);
 
994
                          if (pg > 0)
 
995
                            killpg(pg, SIGCONT);
 
996
                        }
 
997
                      continue;
 
998
                    }
874
999
                  callsplash(p->splashadd, p->name, arg);
875
1000
                  resvec[p->num] = WIFEXITED(r) ? WEXITSTATUS(r) : (WIFSIGNALED(r) ? 1 : 255);
876
1001
                  if (run_mode)
911
1036
      isgtimo = 0;
912
1037
      if (gtimo >= 0 && !gtimo_running && last >= 0 && prgs[last].pid)
913
1038
        {
914
 
          const long glsec = glastio.tv_sec + gtimo;
915
 
          if ((timo < 0) || (tv.tv_sec > glsec) ||
916
 
              (tv.tv_sec == glsec && tv.tv_usec > glastio.tv_usec))
 
1039
          struct timeval gl = glastio;
 
1040
          gl.tv_sec += gtimo;
 
1041
          if ((timo < 0) || timercmp(&tv,&gl,>))
917
1042
            {
918
 
              tv.tv_sec  = glastio.tv_sec;
919
 
              tv.tv_usec = glastio.tv_usec;
 
1043
              tv = glastio;
920
1044
              tv.tv_sec += gtimo;
921
1045
              isgtimo = 1;
922
1046
            }
1015
1139
                    memmove(p->buf, p->buf + p->len, sizeof(p->buf) - p->len);
1016
1140
                  p->len = sizeof(p->buf) - p->len;
1017
1141
                }
1018
 
              p->lastio.tv_sec  = now.tv_sec;
1019
 
              p->lastio.tv_usec = now.tv_usec;
 
1142
              p->lastio = now;
1020
1143
            } /* for (s = 0; s < par; s++) */
1021
1144
        }
1022
1145
    } /* for (;;) */