~ubuntu-branches/debian/experimental/sysvinit/experimental

« back to all changes in this revision

Viewing changes to .pc/76_stdin_notty.patch/startpar/startpar.c

  • Committer: Package Import Robot
  • Author(s): Roger Leigh, Roger Leigh, Steve Langasek
  • Date: 2012-04-21 12:11:45 UTC
  • mfrom: (9.1.33 sid)
  • Revision ID: package-import@ubuntu.com-20120421121145-tcyy57v1j6gx946d
Tags: 2.88dsf-23
[ Roger Leigh ]
* Acknowledge NMU for translation updates.  Thanks to Christian
  Perrier.
* debian/control:
  - Upgrade to Standards-Version 3.9.3.
  - Build-Depend on debhelper v9.
  - Correct Vcs-Git URL.
* debian/rules:
  - Use DEB_HOST_ARCH_OS = hurd rather than
    DEB_HOST_ARCH = hurd-i386.   Thanks to Pino Toscano.
* debian/patches:
  - 11_lfs_cflags.patch: Add patch for enabling large file support,
    needed on GNU/Hurd, but useful for all platforms.
  - 73_lfs_cflags.patch: Add patch for enabling large file support
    in startpar.
* initscripts:
  - Moved RAM* settings from /etc/default/rcS to /etc/default/tmpfs.
    This ensures that the settings are equivalent for upgrades and
    new installations, but will require manual configuration of the
    settings for upgrades (no migration from /etc/default/rcS to
    /etc/default/tmpfs will take place, due to tmpfs being a
    conffile).  tmpf(5) manual page added to document all aspects
    of tmpfs configuration, including the existing documentation in
    rcS(5).
  - Drop the use of .ramfs dotfiles in /run and /run/lock.  These
    were a legacy of /lib/init/rw and were not actually used by
    anything.  Closes: #403863.
  - Drop /etc/init.d/mountoverflowtmp.  This has been merged into
    the general tmpfs on /tmp handling functions.  This means the
    generic RAMTMP configuration is used for the overflowtmp.
    Closes: #567539.
  - It is now possible to configure a tmpfs mount size limit as a
    percentage of the total VM size (%VM) as well as a percentage
    of the RAM size (%).  This is computed by tmpfs.sh and the
    tmpfs mounts are remounted with the updated size limit after
    swap becomes available.
  - An fstab entry for /tmp overrides RAMTMP.  Document tmpfs
    override and tmpfs defaults in tmpfs(5), also undeprecating the
    tmpfs settings.  Closes: #585540, #665995.
  - An fstab entry for /run/lock or /run/shm overrides RAMLOCK and
    RAMSHM.
  - bootclean cleans /tmp, /run and /run/lock before any filesystems
    are mounted as well as after local and network mounts.  This
    permits cleaning of directories which would otherwise be hidden
    by mountpoints later in the boot process.
    Closes: #55707, #558000, #666871.  Additionally clean up
    /lib/init/rw in case any files were hidden by the (now removed)
    tmpfs mount at this location.  Closes: #652625.
  - Removed last trace of the long-removed EDITMOTD from the
    postinst.  Closes: #438895.
  - Removed documentation of #346342 in rcS(5).  This is no longer
    an issue now tzdata keeps a copy of the data on the rootfs.
    Closes: #385172.
  - Correct description of TMPTIME in rcS(5).  Thanks to Alan J.
    Greenberger.  Closes: #562500.
  - urandom: Applied a series of patches from John Denker to
    improve the integrity of random number generation.  Many thanks.
    Closes: #596479, #596480, #596481, #596482, #596483.
* sysv-rc:
  - Remove old upgrade logic from maintainer scripts not required
    for wheezy.
  - Migrate users of obsolete static boot ordering to dynamic boot
    ordering.
  - Remove use of /etc/init.d/.legacy-bootordering.  Closes: #668312.
  - Improve help text of debconf message when it is not possible to
    automatically enable dynamic boot ordering.  Provide explicit
    instructions for how to purge obsolete init scripts.
    Closes: #550425.
  - etc/init.d/rc: Ensure linprocfs is mounted on kFreeBSD.  Thanks
    to Robert Millan.  Closes: #659480.
  - Drop undocumented CONCURRENCY setting from /etc/init.d/rc.
    Closes: #518249, #540448, #539261.  Note that this still contains
    internal fallbacks to support non-insserv booting, which may be
    removed at a later date.
  - invoke-rc.d:
    + Minor manual page corrections.  Thanks to Anthony Fiumara.
      Closes: #664816.
    + Remove mention of the "dpkg Programmers' Manual" and replace
      with references to Debian Policy.  Closes: #543793.
  - update-rc.d:
    + Correctly warn about non-LSB standard runlevels.  Thanks to
      Chris Hiestand for this patch.  Closes: #614895.
    + Remove obsolete documentation of
      /var/lib/sysv-rc/legacy-bootsequence.  Thanks to Thomas Hood.
      Closes: #623051.
* sysvinit:
  - Minor corrections for halt(8) manual page.  Thanks to
    Christoph Anton Mitterer.  Closes: #587923.
  - Installation with debootstrap --variant=fakechroot now works, due
    to only migrating the old control channel when it is still
    present.  Thanks to Michael Gilbert.  Closes: #596284.
* sysvinit-utils:
  - Recommend bootlogd.  Closes: #659490.  This means that booklogd
    will be installed by default, but will be removable.
    Closes: #232569.
  - Correct documentation of the startpar -i option.  Closes: #545438.
  - Correct startpar(8) SEE ALSO section.  Closes: #634146.
  - Correct wording in service(8).  Thanks to Joey Hess and Regid
    Ichira.  Closes: #545401, #667745.

[ Steve Langasek ]
* debian/service/service: fix upstart compatibility to not try to use the
  upstart commands when init isn't upstart.  Closes: #636054.
* debian/rules: pass CFLAGS when building startpar.
* Fix startpar to not run init scripts that have matching upstart jobs,
  instead waiting for a signal from upstart.  Closes: #660824.
    to Robert Millan.  (Closes: #659480)
* sysvinit:
  - Don't restart or perform initctl migration if systemd is
    running.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (c) 2003 SuSE Linux AG
2
 
 *
3
 
 * This program is free software; you can redistribute it and/or modify
4
 
 * it under the terms of the GNU General Public License as published by
5
 
 * the Free Software Foundation; either version 2, or (at your option)
6
 
 * any later version.
7
 
 *  
8
 
 * This program is distributed in the hope that it will be useful,
9
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 
 * GNU General Public License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU General Public License
14
 
 * along with this program (see the file COPYING); if not, write to the
15
 
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
16
 
 * MA 02110-1301, USA.
17
 
 *
18
 
 ****************************************************************
19
 
 */
20
 
 
21
 
#ifndef _GNU_SOURCE
22
 
#define _GNU_SOURCE 1
23
 
#endif
24
 
 
25
 
#include <stdio.h>
26
 
#include <termios.h>
27
 
#include <sys/types.h>
28
 
#include <sys/wait.h>
29
 
#include <sys/select.h>
30
 
#include <sys/time.h>
31
 
#include <sys/ioctl.h>
32
 
#include <sys/socket.h>
33
 
#include <sys/un.h>
34
 
#include <sys/sysinfo.h>
35
 
#include <sys/stat.h>
36
 
#ifndef SUSE
37
 
#include <sys/vfs.h>
38
 
#endif
39
 
#include <time.h>
40
 
#include <fcntl.h>
41
 
#include <errno.h>
42
 
#include <string.h>
43
 
#include <stdlib.h>
44
 
#include <unistd.h>
45
 
#include "makeboot.h"
46
 
#include "proc.h"
47
 
 
48
 
#define timerdiff(n,l) (__extension__ ({ (((n).tv_sec-(l).tv_sec)*1000)+(((n).tv_usec-(l).tv_usec)/1000); }))
49
 
 
50
 
typedef enum _boolean {false, true} boolean;
51
 
extern char *optarg;
52
 
extern int optind;
53
 
 
54
 
static long int numcpu = -1;
55
 
static char *myname;
56
 
static struct termios tio;
57
 
static struct winsize wz;
58
 
static struct {
59
 
  char env_row[128];
60
 
  char env_col[128];
61
 
} sz;
62
 
static sig_atomic_t wzok;
63
 
static char *arg;
64
 
static boolean isstart;
65
 
static struct sigaction sa;
66
 
static struct timeval glastio;
67
 
static struct timeval now;
68
 
static struct timeval lastlim;
69
 
static char *run_mode = NULL;
70
 
static struct makenode **nodevec;
71
 
 
72
 
static enum { Unknown, Preload, NoPreload } ispreload = Unknown;
73
 
 
74
 
#define PBUF_SIZE       8192
75
 
struct prg {
76
 
  const char *name;
77
 
  const char *arg0;
78
 
  int num;
79
 
  int fd;
80
 
  pid_t pid;
81
 
  struct timeval lastio;
82
 
  size_t len;
83
 
  int splashadd;
84
 
  char buf[PBUF_SIZE];
85
 
};
86
 
 
87
 
static struct prg *prgs;
88
 
static int inpar, par;
89
 
static int pidpipe[2];
90
 
static double iorate = 800.0;
91
 
 
92
 
void sighandler_nopreload(int x)
93
 
{
94
 
    (void)x;
95
 
    ispreload = NoPreload;
96
 
}
97
 
 
98
 
 
99
 
void sighandler_preload(int x)
100
 
{
101
 
    (void)x;
102
 
    ispreload = Preload;
103
 
}
104
 
 
105
 
void *xcalloc(size_t nmemb, size_t size)
106
 
{
107
 
  void *r;
108
 
  if ((r = (void *)calloc(nmemb, size)) == 0)
109
 
    {
110
 
      fprintf(stderr, "calloc: out of memory\n");
111
 
      exit(1);
112
 
    }
113
 
  return r;
114
 
}
115
 
 
116
 
static int splashpos = -1;
117
 
static char *splashcfg;
118
 
 
119
 
int calcsplash(int x, int n, char *opt)
120
 
{
121
 
  char *p;
122
 
  int i;
123
 
  int r, d;
124
 
 
125
 
  if (opt == 0)
126
 
    return -1;
127
 
  for (i = 0; i <= x; i++)
128
 
    {
129
 
      if ((p = strchr(opt, ':')) == 0)
130
 
        break;
131
 
      if (i == x)
132
 
        return atoi(opt);
133
 
      opt = p + 1;
134
 
    }
135
 
  r = atoi(opt);
136
 
  n -= i;
137
 
  for (;; i++, n--)
138
 
    {
139
 
      if (n < 1)
140
 
        n = 1;
141
 
      d = r / n;
142
 
      if (i == x)
143
 
        return d;
144
 
      r -= d;
145
 
    }
146
 
}
147
 
 
148
 
pid_t splashpid;
149
 
 
150
 
void waitsplash()
151
 
{
152
 
  int status;
153
 
  if (!splashpid)
154
 
    return;
155
 
  do {
156
 
    waitpid(splashpid, &status, 0);
157
 
  } while (errno == EINTR);
158
 
  splashpid = 0;
159
 
}
160
 
 
161
 
void closeall(void)
162
 
{
163
 
  int s;
164
 
 
165
 
  if (!prgs)
166
 
    return;
167
 
  for (s = 0; s < par; s++)
168
 
    if (prgs[s].fd)
169
 
      close(prgs[s].fd);
170
 
  close(pidpipe[0]);
171
 
  close(pidpipe[1]);
172
 
}
173
 
 
174
 
void callsplash(int n, const char *path, char *action)
175
 
{
176
 
  const char *p;
177
 
  char sbuf[32];
178
 
  char tbuf[256];
179
 
  pid_t pid;
180
 
  struct stat stb;
181
 
 
182
 
  if (n < 0 || splashpos < 0)
183
 
    return;
184
 
  if (splashpos + n > 65535)
185
 
    n = 65535 - splashpos;
186
 
  splashpos += n;
187
 
  if (stat("/proc/splash", &stb))
188
 
     return;
189
 
  p = strrchr(path, '/');
190
 
  if (p)
191
 
    path = p + 1;
192
 
  for (p = path; *p; p++)
193
 
    if ((*p == 'S' || *p == 'K') && p[1] >= '0' && p[1] <= '9' && p[2] >= '0' && p[2] <= '9' && p[3])
194
 
      break;
195
 
  if (*p)
196
 
    p += 3;
197
 
  else
198
 
    p = path;
199
 
  if (!action)
200
 
    action = "";
201
 
  if (strlen(p) + strlen(action) + 2 > sizeof(tbuf))
202
 
    return;
203
 
  sprintf(tbuf, "%s%s%s", p, *action ? " " : "", action);
204
 
  sprintf(sbuf, "%d:%d", splashpos - n, n);
205
 
  waitsplash();
206
 
  pid = fork();
207
 
  if (pid == (pid_t)-1)
208
 
    return;
209
 
  if (pid)
210
 
    {
211
 
      splashpid = pid;
212
 
      return;
213
 
    }
214
 
  while (dup2(2, 1) < 0 && (errno == EINTR))
215
 
    ;
216
 
  closeall();
217
 
  execl("/sbin/splash", "splash", "-p", sbuf, "-t", tbuf, splashcfg, (char *)0);
218
 
  _exit(1);
219
 
}
220
 
 
221
 
void writebuf(struct prg *p)
222
 
{
223
 
  char *b = p->buf;
224
 
  int r;
225
 
 
226
 
  while (p->len > 0)
227
 
    {
228
 
      r = write(2, b, p->len);
229
 
      if (r < 0)
230
 
        {
231
 
          perror("write");
232
 
          r = p->len;
233
 
        }
234
 
      p->len -= r;
235
 
      b += r;
236
 
    }
237
 
  glastio = now;
238
 
}
239
 
 
240
 
static int checksystem(const int par, const boolean start, const boolean limit)
241
 
{
242
 
  const      int pg_size       = sysconf(_SC_PAGESIZE);
243
 
  const long int minphys_bytes = (sysconf(_SC_LONG_BIT) > 32L) ? (2<<22) : (2<<21);
244
 
  const long int avphys_pg     = sysconf(_SC_AVPHYS_PAGES);
245
 
  long int minphys_pg;
246
 
  unsigned long int prcs_run, prcs_blked;
247
 
  int newpar;
248
 
  
249
 
  if (avphys_pg < 0)
250
 
    return 1;
251
 
 
252
 
  if (pg_size < 0)
253
 
    return par;
254
 
 
255
 
  if (!start)
256
 
    minphys_pg = avphys_pg;
257
 
  else
258
 
    minphys_pg = minphys_bytes / pg_size;
259
 
 
260
 
  if (avphys_pg < minphys_pg)
261
 
    return 1;
262
 
 
263
 
  if (numcpu < 1)
264
 
    return par;
265
 
  
266
 
  if (!limit)
267
 
    return (par*numcpu);
268
 
 
269
 
  if (read_proc(&prcs_run, &prcs_blked))
270
 
    return par;
271
 
 
272
 
  /* if we have preload running, we expect I/O not to be a problem */
273
 
  if (ispreload != NoPreload)
274
 
    prcs_blked = 0;
275
 
 
276
 
  newpar  = (par*numcpu) - prcs_run + 1;        /* +1 for startpar its self */
277
 
  newpar -= (int)(((double)prcs_blked)*iorate); /* I/O load reduction */
278
 
 
279
 
#if DEBUG
280
 
  fprintf(stderr, "checksystem par=%d newpar=%d (prcs_run=%lu) %ld\n", par, newpar, prcs_run, time(0));
281
 
  dump_status();
282
 
#endif
283
 
  if (newpar <= 0)
284
 
    return 1;
285
 
  else
286
 
    return newpar;
287
 
}
288
 
 
289
 
static inline int checklimit(const int par, const boolean start)
290
 
{
291
 
  return checksystem(par, start, true);
292
 
}
293
 
 
294
 
static inline int checkpar(const int par, const boolean start)
295
 
{
296
 
  return checksystem(par, start, false);
297
 
}
298
 
 
299
 
#define SOCK_PATH "/dev/shm/preload_sock"
300
 
 
301
 
#ifdef SUSE
302
 
static int checkdevpts(void)
303
 
{
304
 
  /* /dev/pts is always mounted */
305
 
  return 1;
306
 
}
307
 
#else
308
 
/*
309
 
 * Based on __posix_openpt() from glibc.  Reimplemented here to work
310
 
 * around the problem with getpt() failing for the entire process life
311
 
 * time if /dev/pts/ is missing the first time it is called but
312
 
 * mounted while the process is running.  BSD style pts is not
313
 
 * supported, but might be copied from glibc too if there is need.
314
 
 */
315
 
#define DEVFS_SUPER_MAGIC       0x1373
316
 
#define DEVPTS_SUPER_MAGIC      0x1cd1
317
 
 
318
 
static int startpar_getpt(void) {
319
 
  int fd = open("/dev/ptmx", O_RDWR|O_NOCTTY);
320
 
 
321
 
  if (fd != -1)
322
 
    {
323
 
      struct statfs fsbuf;
324
 
 
325
 
      /* Check that the /dev/pts filesystem is mounted
326
 
        or if /dev is a devfs filesystem (this implies /dev/pts).  */
327
 
      if ((statfs ("/dev/pts", &fsbuf) == 0
328
 
             && fsbuf.f_type == DEVPTS_SUPER_MAGIC)
329
 
         || (statfs ("/dev", &fsbuf) == 0
330
 
             && fsbuf.f_type == DEVFS_SUPER_MAGIC))
331
 
        {
332
 
          /* Everything is ok, switch to the getpt() in libc.  */
333
 
          return fd;
334
 
        }
335
 
 
336
 
      /* If /dev/pts is not mounted then the UNIX98 pseudo terminals
337
 
        are not usable.  */
338
 
      close (fd);
339
 
    }
340
 
 
341
 
  return -1;
342
 
}
343
 
 
344
 
static int checkdevpts(void)
345
 
{
346
 
  int ptsfd = startpar_getpt();
347
 
 
348
 
  if (ptsfd == -1)
349
 
    {
350
 
      return 0;
351
 
    }
352
 
  else if (ptsname(ptsfd) == 0 || grantpt(ptsfd) || unlockpt(ptsfd))
353
 
    {
354
 
      close(ptsfd);
355
 
      return 0;
356
 
    }
357
 
  else
358
 
    {
359
 
      close(ptsfd);
360
 
      return 1;
361
 
    }
362
 
}
363
 
#endif
364
 
 
365
 
void run(struct prg *p)
366
 
{
367
 
  char *m = 0;
368
 
  pid_t parent = getpid();
369
 
 
370
 
  p->len = 0;
371
 
  p->pid = (pid_t)0;
372
 
  p->fd = getpt();
373
 
  if (p->fd <= 0)
374
 
    {
375
 
      p->fd = 0;
376
 
      perror("getpt");
377
 
      fprintf(stderr, "could not get pty for %s\n", p->name);
378
 
    }
379
 
  else if ((m = ptsname(p->fd)) == 0 || grantpt(p->fd) || unlockpt(p->fd))
380
 
    {
381
 
      fprintf(stderr, "could not init pty for %s\n", p->name);
382
 
      close(p->fd);
383
 
      p->fd = 0;
384
 
    }
385
 
  if ((p->pid = fork()) == (pid_t)-1)
386
 
    {
387
 
      perror("fork");
388
 
      fprintf(stderr, "could not fork %s\n", p->name);
389
 
      p->pid = 0;
390
 
      if (p->fd)
391
 
        {
392
 
          close(p->fd);
393
 
          p->fd = 0;
394
 
        }
395
 
      return;
396
 
    }
397
 
  if (p->pid != 0)
398
 
    return;
399
 
 
400
 
  (void)signal(SIGINT,  SIG_DFL);
401
 
  (void)signal(SIGQUIT, SIG_DFL);
402
 
  (void)signal(SIGSEGV, SIG_DFL);
403
 
  (void)signal(SIGTERM, SIG_DFL);
404
 
  (void)signal(SIGCHLD, SIG_DFL);
405
 
 
406
 
  if (setpgid(0, 0))
407
 
    perror("setpgid");
408
 
 
409
 
  if (m && p->fd)
410
 
    {
411
 
      while (close(1) < 0 && (errno == EINTR))
412
 
        ;
413
 
      if (open(m, O_RDWR) != 1)
414
 
        {
415
 
          perror(m);
416
 
          _exit(1);
417
 
        }
418
 
      while (dup2(1, 2) < 0 && (errno == EINTR))
419
 
        ;
420
 
      tio.c_oflag &= ~OPOST;
421
 
      if (tcsetattr(1, TCSANOW, &tio))
422
 
        perror("tcsetattr");
423
 
      if (wzok)
424
 
        ioctl(1, TIOCSWINSZ, &wz);
425
 
      putenv(sz.env_row);
426
 
      putenv(sz.env_col);
427
 
    }
428
 
  else
429
 
    {
430
 
      while (dup2(2, 1) < 0 && (errno == EINTR))
431
 
        ;
432
 
    }
433
 
 
434
 
  closeall();
435
 
 
436
 
  if (!strcmp(arg, "start")) 
437
 
    { 
438
 
      int s, t, len;
439
 
      pid_t child;
440
 
      struct sockaddr_un remote;
441
 
      char str[100];
442
 
 
443
 
      s = socket(AF_UNIX, SOCK_STREAM, 0);
444
 
      if (s != -1) 
445
 
        {
446
 
          memset(&remote, 0, sizeof(struct sockaddr_un));
447
 
          remote.sun_family = AF_UNIX;
448
 
          strcpy(remote.sun_path, SOCK_PATH);
449
 
          len = strlen(remote.sun_path) + sizeof(remote.sun_family);
450
 
 
451
 
          t = connect(s, (struct sockaddr *)&remote, len);
452
 
          if (t != -1) 
453
 
            {
454
 
              if (ispreload != Preload)
455
 
                kill(parent, SIGUSR1);
456
 
              send(s, p->name, strlen(p->name), 0);
457
 
              recv(s, str, 100, 0);
458
 
            } 
459
 
          else if ( ispreload == Unknown) 
460
 
            {
461
 
              /*
462
 
               * if we connected to preload once, we know it ran.
463
 
               * In case we can't connect to it later, it means it did
464
 
               * its job and we can guess I/O is no longer a problem. 
465
 
               */
466
 
              kill(parent, SIGUSR2);
467
 
            }
468
 
          close(s);
469
 
          /*
470
 
           * if we use preload, we fork again to make bootcharts easier to read.
471
 
           * The reason is that the name of the init script will otherwise be used
472
 
           * when in reality the above code waited for preload. If we fork away
473
 
           * before the exec, the waiting code will be folded into startpar
474
 
           */
475
 
          child = fork();
476
 
          if (child) {
477
 
                int status;
478
 
                int ret = waitpid(child, &status, 0);
479
 
                if (ret == -1)
480
 
                        perror("waitpid");
481
 
                exit(WEXITSTATUS(status));
482
 
          }
483
 
        }
484
 
    }
485
 
 
486
 
  if (run_mode)
487
 
    {
488
 
      char path[128];
489
 
      snprintf(path, sizeof(path), "/etc/init.d/%s", p->name);
490
 
      execlp(path, p->arg0, arg, (char *)0);
491
 
    }
492
 
  else if (arg)
493
 
    execlp(p->name, p->arg0, arg, (char *)0);
494
 
  else
495
 
    execlp(p->name, p->arg0, (char *)0);
496
 
  perror(p->name);
497
 
  _exit(1);
498
 
}
499
 
 
500
 
int run_single(const char *prg, const char *arg0, int spl)
501
 
{
502
 
  pid_t pid;
503
 
  int r;
504
 
 
505
 
  if ((pid = fork()) == (pid_t)-1)
506
 
    {
507
 
      perror("fork");
508
 
      fprintf(stderr, "could not fork %s\n", prg);
509
 
      return 1;
510
 
    }
511
 
 
512
 
  if (pid == 0)
513
 
    {
514
 
      (void)signal(SIGINT,  SIG_DFL);
515
 
      (void)signal(SIGQUIT, SIG_DFL);
516
 
      (void)signal(SIGSEGV, SIG_DFL);
517
 
      (void)signal(SIGTERM, SIG_DFL);
518
 
      (void)signal(SIGCHLD, SIG_DFL);
519
 
 
520
 
      while (dup2(2, 1) < 0 && (errno == EINTR))
521
 
        ;
522
 
      closeall();
523
 
      if (run_mode)
524
 
        {
525
 
          char path[128];
526
 
          snprintf(path, sizeof(path), "/etc/init.d/%s", prg);
527
 
          execlp(path, arg0 ? arg0 : path, arg, (char *)0);
528
 
        }
529
 
      else if (arg)
530
 
        execlp(prg, arg0 ? arg0 : prg, arg, (char *)0);
531
 
      else
532
 
        execlp(prg, arg0 ? arg0 : prg, (char *)0);
533
 
      perror(prg);
534
 
      _exit(1);
535
 
    }
536
 
 
537
 
   while ((waitpid(pid, &r, 0) == (pid_t)-1) && (errno == EINTR))
538
 
     ;
539
 
   callsplash(spl, prg, arg);
540
 
   return WIFEXITED(r) ? WEXITSTATUS(r) : (WIFSIGNALED(r) ? 1 : 255);
541
 
}
542
 
 
543
 
void do_forward(void)
544
 
{
545
 
  char buf[4096], *b;
546
 
  int r, rr;
547
 
  setsid();
548
 
  while ((r = read(0, buf, sizeof(buf))) > 0)
549
 
    {
550
 
      b = buf;
551
 
      while (r > 0)
552
 
        {
553
 
          rr = write(1, b, r);
554
 
          if (rr == -1)
555
 
            {
556
 
              perror("write");
557
 
              rr = r;
558
 
            }
559
 
          r -= rr;
560
 
        }
561
 
    }
562
 
  _exit(0);
563
 
}
564
 
 
565
 
static char *gtimo_buf;
566
 
static size_t gtimo_bufsize;
567
 
static size_t gtimo_buflen;
568
 
 
569
 
void storebuf(struct prg *p)
570
 
{
571
 
  if ((gtimo_buflen + p->len) > gtimo_bufsize)
572
 
    {
573
 
      writebuf(p);                              /* In case of overflow or memory shortage */
574
 
      return;
575
 
    }
576
 
 
577
 
  (void)memcpy(gtimo_buf + gtimo_buflen, p->buf, p->len);
578
 
  gtimo_buflen += p->len;
579
 
  p->len = 0;
580
 
  glastio = now;
581
 
}
582
 
 
583
 
void flushbuf(void)
584
 
{
585
 
  size_t len = gtimo_buflen;
586
 
  char * buf = gtimo_buf;
587
 
 
588
 
  if (!buf)
589
 
        return;                                 /* In case of memory shortage */
590
 
 
591
 
  while (len > 0)
592
 
    {
593
 
      int r = write(2, buf, len);
594
 
      if (r < 0)
595
 
        {
596
 
          perror("write");
597
 
          r = len;
598
 
        }
599
 
      len -= r;
600
 
      buf += r;
601
 
    }
602
 
  gtimo_buflen = 0;
603
 
  *gtimo_buf = 0;
604
 
}
605
 
 
606
 
#define GTIMO_OFFL      0
607
 
#define GTIMO_USED      1
608
 
 
609
 
void detach(struct prg *p, const int store)
610
 
{
611
 
  int r;
612
 
  int flags = fcntl(p->fd, F_GETFL);
613
 
 
614
 
  if (flags > 0)
615
 
    flags |= FNONBLOCK;
616
 
  else
617
 
    flags = FNONBLOCK;
618
 
 
619
 
  fcntl(p->fd, F_SETFL, flags);
620
 
  while ((r = read(p->fd, p->buf, sizeof(p->buf))) > 0)
621
 
    {
622
 
      p->len = r;
623
 
      if (store)
624
 
        storebuf(p);
625
 
      else
626
 
        writebuf(p);
627
 
    }
628
 
  flags &= ~FNONBLOCK;
629
 
  fcntl(p->fd, F_SETFL, flags);
630
 
  if (r == -1 && errno == EWOULDBLOCK)
631
 
    {
632
 
      if ((r = fork()) == 0)
633
 
        {
634
 
          while (dup2(p->fd, 0) < 0 && (errno == EINTR))
635
 
            ;
636
 
          while (dup2(2, 1) < 0 && (errno == EINTR))
637
 
            ;
638
 
          closeall();
639
 
          execlp(myname, myname, "-f", "--", p->name, NULL);
640
 
          do_forward();
641
 
        }
642
 
      if (r == -1)
643
 
        perror("fork");
644
 
    }
645
 
  close(p->fd);
646
 
  p->fd = 0;
647
 
}
648
 
 
649
 
static void sigchld(int sig __attribute__ ((unused)))
650
 
{
651
 
  char c = 0;
652
 
  write(pidpipe[1], &c, 1);
653
 
}
654
 
 
655
 
static void sigwinch(int sig __attribute__ ((unused)))
656
 
{
657
 
  if (ioctl(0, TIOCGWINSZ, &wz) < 0)
658
 
    {
659
 
      wzok = 0;
660
 
      return;
661
 
    }
662
 
  if (wz.ws_row == 0) wz.ws_row = 24;
663
 
  if (wz.ws_col == 0) wz.ws_col = 80;
664
 
  snprintf(sz.env_row, sizeof(sz.env_row), "LINES=%d",   wz.ws_row);
665
 
  snprintf(sz.env_col, sizeof(sz.env_col), "COLUMNS=%d", wz.ws_col);
666
 
}
667
 
 
668
 
void usage(int status)
669
 
{
670
 
  fprintf(stderr, "usage: startpar [options] [-a arg] prgs\n");
671
 
  fprintf(stderr, "           run given programs parallel\n");
672
 
  fprintf(stderr, "       startpar [options] [-P prev] [-R run] [-S <start>:<num>] -M mode\n");
673
 
  fprintf(stderr, "           run parallel with Makefile\n");
674
 
  fprintf(stderr, "       startpar -v\n");
675
 
  fprintf(stderr, "           show version number\n");
676
 
  fprintf(stderr, "general options:\n");
677
 
  fprintf(stderr, "       -p parallel tasks\n");
678
 
  fprintf(stderr, "       -t I/O timeout\n");
679
 
  fprintf(stderr, "       -T global I/O timeout\n");
680
 
  exit(status);
681
 
}
682
 
 
683
 
int main(int argc, char **argv)
684
 
{
685
 
  int gtimo = -1;
686
 
  int timo = -1;
687
 
  int isgtimo;
688
 
  int forw = 0;
689
 
  int c, i, num;
690
 
  int limit;
691
 
  int *resvec;
692
 
  fd_set rset;
693
 
  struct timeval tv;
694
 
  struct prg *p;
695
 
  char pipebuf[16];
696
 
  struct prg *gtimo_running = 0;
697
 
  struct prg *interactive_task = NULL;
698
 
  char *prev_level = getenv("PREVLEVEL");
699
 
  char *run_level = getenv("RUNLEVEL");
700
 
  char *splashopt = 0;
701
 
 
702
 
  (void)signal(SIGUSR1, sighandler_preload);
703
 
  (void)signal(SIGUSR2, sighandler_nopreload);
704
 
 
705
 
  (void)signal(SIGCHLD, SIG_DFL);
706
 
  numcpu = sysconf(_SC_NPROCESSORS_ONLN);
707
 
  myname = argv[0];
708
 
 
709
 
  while ((c = getopt(argc, argv, "fhp:t:T:a:M:P:R:S:vi:")) != EOF)
710
 
    {
711
 
      switch(c)
712
 
        {
713
 
        case 'p':
714
 
          par = atoi(optarg);
715
 
          break;
716
 
        case 't':
717
 
          timo = atoi(optarg);
718
 
          break;
719
 
        case 'T':
720
 
          gtimo = atoi(optarg);
721
 
          break;
722
 
        case 'f':
723
 
          forw = 1;
724
 
          break;
725
 
        case 'a':
726
 
          arg = optarg;
727
 
          break;
728
 
        case 'M':
729
 
          run_mode = optarg;
730
 
          break;
731
 
        case 'P':
732
 
          prev_level = optarg;
733
 
          break;
734
 
        case 'R':
735
 
          run_level = optarg;
736
 
          break;
737
 
        case 'S':
738
 
          splashopt = optarg;
739
 
          break;
740
 
        case 'v':
741
 
          printf("startpar version %s\n", VERSION);
742
 
          exit(0);
743
 
        case 'h':
744
 
          usage(0);
745
 
          break;
746
 
        case 'i':
747
 
          iorate = atof(optarg);
748
 
          if (iorate < 0.0)
749
 
            iorate = 800.0;
750
 
          break;
751
 
        default:
752
 
          usage(1);
753
 
          break;
754
 
        }
755
 
    }
756
 
  if (forw)
757
 
    do_forward();
758
 
  argc -= optind;
759
 
  argv += optind;
760
 
 
761
 
  if (splashopt)
762
 
    {
763
 
      char *so = strchr(splashopt, ':');
764
 
      if (!so)
765
 
        splashopt = 0;
766
 
      else
767
 
        {
768
 
          splashpos = atoi(splashopt);
769
 
          splashopt = so + 1;
770
 
        }
771
 
      splashcfg = getenv("SPLASHCFG");
772
 
      if (!splashcfg)
773
 
        {
774
 
          splashpos = -1;
775
 
          splashopt = 0;
776
 
        }
777
 
    }
778
 
  if (run_mode)
779
 
    {
780
 
      char makefile[64];
781
 
      if (!strcmp(run_mode, "boot"))
782
 
        arg = "start";
783
 
      else if (!strcmp(run_mode, "halt"))
784
 
        arg = "stop";
785
 
      else if (!strcmp(run_mode, "start") || !strcmp(run_mode, "stop"))
786
 
        {
787
 
          arg = run_mode;
788
 
          if (!prev_level || !run_level)
789
 
            {
790
 
              fprintf(stderr, "You must specify previous and next runlevels\n");
791
 
              exit(1);
792
 
            }
793
 
        }
794
 
      else
795
 
        {
796
 
          fprintf(stderr, "invalid run mode %s\n", run_mode);
797
 
          exit(1);
798
 
        }
799
 
      snprintf(makefile, sizeof(makefile), "/etc/init.d/.depend.%s", run_mode);
800
 
      parse_makefile(makefile);
801
 
      check_run_files(run_mode, prev_level, run_level);
802
 
 
803
 
      argc = tree_entries;                      /* number of handled scripts */
804
 
      isstart = !strcmp(arg, "start");
805
 
 
806
 
      if (argc == 0)
807
 
        exit(0);
808
 
 
809
 
      if (par == 0)
810
 
        par = 4;
811
 
      if (par > argc)                           /* not more than the number of all scripts */
812
 
        par = argc;
813
 
 
814
 
      inpar = par;                              /* the original argument of parallel procs per cpu */
815
 
 
816
 
      par = checkpar(inpar, isstart);           /* the number of parallel procs on all cpu's */
817
 
 
818
 
      if (par > argc)                           /* not more than the number of all scripts */
819
 
        par = argc;
820
 
 
821
 
      nodevec = xcalloc(argc, sizeof(*nodevec));
822
 
    }
823
 
  else
824
 
    {
825
 
      if (par < 0)
826
 
        usage(1);
827
 
 
828
 
      if (arg)
829
 
        isstart = !strcmp(arg, "start");
830
 
 
831
 
      if (argc == 0)
832
 
        exit(0);
833
 
 
834
 
      if (par == 0)
835
 
        par = argc;
836
 
      if (par > argc)                           /* not more than the number of all scripts */
837
 
        par = argc;
838
 
 
839
 
      inpar = par;                              /* the original argument of parallel procs per cpu */
840
 
 
841
 
      par = checkpar(inpar, isstart);           /* the number of parallel procs on all cpu's */
842
 
 
843
 
      if (par > argc)                           /* not more than the number of all scripts */
844
 
        par = argc;
845
 
    }
846
 
 
847
 
  num = 0;
848
 
  resvec = (int *)xcalloc(argc, sizeof(int));
849
 
  for (i = 0; i < argc; i++)
850
 
    resvec[i] = 255;
851
 
 
852
 
  if (argc == 1)
853
 
    {
854
 
      if (run_mode)
855
 
        {
856
 
          if ((*nodevec = pickup_task()))
857
 
          {
858
 
            *resvec = run_single((*nodevec)->name, (*nodevec)->arg0, calcsplash(0, 1, splashopt));
859
 
            finish_task(*nodevec);
860
 
          }
861
 
      } else
862
 
        *resvec = run_single(*argv, *argv, calcsplash(0, 1, splashopt));
863
 
      goto finished;
864
 
    }
865
 
 
866
 
  prgs = (struct prg *)xcalloc(par, sizeof *prgs);
867
 
  gtimo_bufsize = par * PBUF_SIZE;
868
 
  gtimo_buf = (char *) calloc(gtimo_bufsize, sizeof(char));
869
 
  if (!gtimo_buf)
870
 
    gtimo_bufsize = 0;                          /* Accept error due memory shortage */
871
 
 
872
 
  sa.sa_handler = sigwinch;
873
 
  sa.sa_flags = SA_RESTART|SA_NODEFER;
874
 
  (void)sigemptyset(&sa.sa_mask);
875
 
  if (sigaction(SIGWINCH, &sa, 0))
876
 
    {
877
 
      perror("sigwinch sigaction");
878
 
      exit(1);
879
 
    }
880
 
 
881
 
  if (tcgetattr(0, &tio))
882
 
    {
883
 
      perror("tcgetattr");
884
 
      exit(1);
885
 
    }
886
 
  if (ioctl(0, TIOCGWINSZ, &wz) == 0)
887
 
    wzok = 1;
888
 
  if (wz.ws_row == 0) wz.ws_row = 24;
889
 
  if (wz.ws_col == 0) wz.ws_col = 80;
890
 
 
891
 
  strcat(&sz.env_row[0], "LINES=");
892
 
  strcat(&sz.env_col[0], "COLUMNS=");
893
 
  snprintf(sz.env_row, sizeof(sz.env_row), "LINES=%d",   wz.ws_row);
894
 
  snprintf(sz.env_col, sizeof(sz.env_col), "COLUMNS=%d", wz.ws_col);
895
 
 
896
 
  if (pipe(pidpipe))
897
 
    {
898
 
      perror("pipe");
899
 
      exit(1);
900
 
    }
901
 
  fcntl(pidpipe[0], F_SETFL, FNONBLOCK);
902
 
  fcntl(pidpipe[1], F_SETFL, FNONBLOCK);
903
 
  sa.sa_handler = sigchld;
904
 
  sa.sa_flags = SA_RESTART;
905
 
  (void)sigemptyset(&sa.sa_mask);
906
 
  if (sigaction(SIGCHLD, &sa, 0))
907
 
    {
908
 
      perror("sigchld sigaction");
909
 
      exit(1);
910
 
    }
911
 
 
912
 
  gettimeofday(&glastio, 0);
913
 
  limit = checklimit(inpar, isstart);
914
 
  lastlim = glastio;
915
 
  for (;;)
916
 
    {
917
 
      int active = 0;
918
 
      int maxfd = -1;
919
 
      int last = -1;
920
 
      pid_t pid = 0;
921
 
      int r = 0, s;
922
 
      long diff;
923
 
      int devpts = 0;
924
 
 
925
 
      gettimeofday(&now, 0);
926
 
      FD_ZERO(&rset);
927
 
      tv = now;
928
 
 
929
 
      if ((diff = timerdiff(now, lastlim)) >= 300 || diff < 0)
930
 
        {
931
 
#if DEBUG
932
 
          fprintf(stderr, "%d: doing checklimit after %ldms %ld\n", getpid(), diff, time(0));
933
 
#endif
934
 
          if ((limit = checklimit(inpar, isstart)) > argc)
935
 
            limit = argc;                       /* not more than the number of all scripts */
936
 
          lastlim = now;
937
 
          diff = 0;
938
 
        } 
939
 
#if DEBUG
940
 
      fprintf(stderr, "par=%d, inpar=%d, limit=%d (diff=%ld)\n", par, inpar, limit, diff);
941
 
#endif
942
 
      for (s = 0; s < par; s++)                 /* never leave this with break!! */
943
 
        {
944
 
        account:                                /* for the new process below */
945
 
          if (!devpts)
946
 
            devpts = checkdevpts();
947
 
          p = prgs + s;
948
 
          if (p == interactive_task)
949
 
            continue;                           /* don't count this here */
950
 
          if (p->fd || p->pid)
951
 
            active++;                           /* count all running procs */
952
 
          if (p->fd == 0)
953
 
            {
954
 
              if (interactive_task)
955
 
                continue;                       /* dont't start new processes */
956
 
              if (num >= argc)
957
 
                continue;                       /* nothing to do */
958
 
              if (p->pid == 0)
959
 
                {
960
 
                  if (active >= limit)
961
 
                    continue;                   /* load balancing */
962
 
                  if (run_mode)
963
 
                    {
964
 
                      if ((nodevec[num] = pickup_task()) == NULL)
965
 
                        continue;
966
 
                      if (nodevec[num]->interactive)
967
 
                        interactive_task = p;
968
 
                      p->name = nodevec[num]->name;
969
 
                      p->arg0 = nodevec[num]->arg0 ? nodevec[num]->arg0 : nodevec[num]->name;
970
 
                    }
971
 
                  else {
972
 
                    p->name = *argv++;
973
 
                    p->arg0 = p->name;
974
 
                  }
975
 
                  p->splashadd = calcsplash(num, argc, splashopt);
976
 
                  p->num = num++;
977
 
                  if (interactive_task)
978
 
                    continue;                   /* don't start this here */
979
 
                  if (!devpts)
980
 
                    {
981
 
                      interactive_task = p;     /* no /dev/pts, treat as interactive */
982
 
                      continue;
983
 
                    }
984
 
                  run(p);
985
 
                  if (p->pid == 0)
986
 
                    {
987
 
                      resvec[p->num] = 1;
988
 
                      if (run_mode)
989
 
                        finish_task(nodevec[p->num]);
990
 
                    }
991
 
                  gettimeofday(&now, 0);
992
 
                  tv = now;
993
 
                  goto account;                 /* take the new process into account */
994
 
                }
995
 
              continue;
996
 
            }
997
 
          FD_SET(p->fd, &rset);
998
 
          if (p->fd > maxfd)
999
 
            maxfd = p->fd;
1000
 
          if (p->len == 0)
1001
 
            continue;
1002
 
          if ((last < 0) || timercmp(&tv,&p->lastio,>))
1003
 
            {
1004
 
              last = s;
1005
 
              tv = p->lastio;
1006
 
            }
1007
 
        } /* for (s = 0; s < par; s++) */
1008
 
 
1009
 
      if (interactive_task)
1010
 
        {
1011
 
          if (active == 0)
1012
 
            {
1013
 
              p = interactive_task;
1014
 
              resvec[p->num] = run_single(p->name, p->arg0, p->splashadd);
1015
 
              if (run_mode)
1016
 
                finish_task(nodevec[p->num]);
1017
 
              p->pid = 0;
1018
 
              p->fd = 0;
1019
 
              interactive_task = NULL;
1020
 
              continue;
1021
 
            }
1022
 
        }
1023
 
 
1024
 
      if (active == 0)
1025
 
        {
1026
 
          if (num < argc)
1027
 
            fprintf(stderr, "ERROR: not all processed (%d of %d)\n", num, argc);
1028
 
#if DEBUG
1029
 
          if ((pid = waitpid(-1, &r, (maxfd < 0 ? 0 : WNOHANG)|WUNTRACED)) > 0)
1030
 
            fprintf(stderr, "ERROR: not all processes are checked\n");
1031
 
#endif
1032
 
          break;
1033
 
        }
1034
 
#if DEBUG
1035
 
      fprintf(stderr, "active = %d\n", active);
1036
 
#endif
1037
 
      if (active == 1 && last >= 0)
1038
 
        {
1039
 
          p = prgs + last;
1040
 
          if ((pid = waitpid(p->pid, &r, (maxfd < 0 ? 0 : WNOHANG)|WUNTRACED)) == 0)
1041
 
            {
1042
 
              writebuf(p);
1043
 
              continue;
1044
 
            }
1045
 
        }
1046
 
 
1047
 
      FD_SET(pidpipe[0], &rset);
1048
 
      /* drain the pidpipe */
1049
 
      while ((c = read(pidpipe[0], pipebuf, sizeof pipebuf)) > 0)
1050
 
        ;
1051
 
 
1052
 
      if (pid == 0)
1053
 
        pid = waitpid(-1, &r, (maxfd < 0 ? 0 : WNOHANG)|WUNTRACED);
1054
 
 
1055
 
      if (pid > 0)
1056
 
        {
1057
 
          if (pid == splashpid)
1058
 
            splashpid = (pid_t)0;
1059
 
          for (s = 0; s < par; s++)
1060
 
            {
1061
 
              p = prgs + s;
1062
 
              if (p->pid == pid)
1063
 
                {
1064
 
                  if (WIFSTOPPED(r))
1065
 
                    {
1066
 
                      if (WSTOPSIG(r) == SIGTTIN)
1067
 
                        {
1068
 
                          pid_t pg = getpgid(pid);
1069
 
                          if (pg > 0)
1070
 
                            killpg(pg, SIGCONT);
1071
 
                        }
1072
 
                      continue;
1073
 
                    }
1074
 
                  callsplash(p->splashadd, p->name, arg);
1075
 
                  resvec[p->num] = WIFEXITED(r) ? WEXITSTATUS(r) : (WIFSIGNALED(r) ? 1 : 255);
1076
 
                  if (run_mode)
1077
 
                    finish_task(nodevec[p->num]);
1078
 
                  p->pid = 0;
1079
 
                  if (gtimo_running == p)
1080
 
                    {
1081
 
                      writebuf(p);
1082
 
                      if (p->fd)
1083
 
                        detach(p, GTIMO_OFFL);
1084
 
                      flushbuf();
1085
 
                      gtimo_running = 0;
1086
 
                    }
1087
 
                  else if (gtimo_running)
1088
 
                    {
1089
 
                      storebuf(p);
1090
 
                      if (p->fd)
1091
 
                        detach(p, GTIMO_USED);
1092
 
                    }
1093
 
                  else
1094
 
                    {
1095
 
                      writebuf(p);
1096
 
                      if (p->fd)
1097
 
                        detach(p, GTIMO_OFFL);
1098
 
                    }
1099
 
                  break;
1100
 
                }
1101
 
            } /* for (s = 0; s < par; s++) */
1102
 
          continue;
1103
 
        }
1104
 
 
1105
 
      if (maxfd < 0)
1106
 
        continue;                               /* start new processes? */
1107
 
 
1108
 
      if (timo >= 0)
1109
 
        tv.tv_sec += timo;
1110
 
 
1111
 
      isgtimo = 0;
1112
 
      if (gtimo >= 0 && !gtimo_running && last >= 0 && prgs[last].pid)
1113
 
        {
1114
 
          struct timeval gl = glastio;
1115
 
          gl.tv_sec += gtimo;
1116
 
          if ((timo < 0) || timercmp(&tv,&gl,>))
1117
 
            {
1118
 
              tv = glastio;
1119
 
              tv.tv_sec += gtimo;
1120
 
              isgtimo = 1;
1121
 
            }
1122
 
        }
1123
 
 
1124
 
      r = 0;
1125
 
      if (timo >= 0 || isgtimo)
1126
 
        {
1127
 
          int setfd = (pidpipe[0] > maxfd) ? pidpipe[0] : maxfd;
1128
 
          struct timeval wait;
1129
 
 
1130
 
          timersub(&tv, &now, &wait);
1131
 
          if (wait.tv_usec < 0)
1132
 
            {
1133
 
              wait.tv_usec += 1000000;
1134
 
              wait.tv_sec--;
1135
 
            }
1136
 
          if (wait.tv_sec >= 0)
1137
 
            {
1138
 
              int check = limit < par && num < argc;
1139
 
 
1140
 
              if (check)                        /* shorten timeout for new limit and procs  ... */
1141
 
                {
1142
 
                  wait.tv_sec = 0;
1143
 
                  wait.tv_usec = (300 - diff) * 1000;
1144
 
                }
1145
 
#if DEBUG
1146
 
              fprintf(stderr, "going into select1 %d %ld %ld\n", last, wait.tv_sec, wait.tv_usec);
1147
 
#endif
1148
 
              r = select(setfd + 1, &rset, 0, 0, (last >= 0 || check) ? &wait : 0);
1149
 
 
1150
 
              if (check && (r == 0))            /* ... but do not throw out messages to early!!! */
1151
 
                continue;
1152
 
            }
1153
 
          else
1154
 
            {
1155
 
              wait.tv_sec  = 0;                 /* Avoid looping around (does this ever happen?) */
1156
 
              wait.tv_usec = 20*1000;
1157
 
              r = select(setfd + 1, &rset, 0, 0, last >= 0 ? &wait : 0);
1158
 
            }
1159
 
        }
1160
 
      else
1161
 
        {
1162
 
          int setfd = (pidpipe[0] > maxfd) ? pidpipe[0] : maxfd;
1163
 
          r = select(setfd + 1, &rset, 0, 0, 0);
1164
 
        }
1165
 
 
1166
 
      if (r == -1)
1167
 
        {
1168
 
          if (errno == EINTR)
1169
 
            continue;
1170
 
          perror("select");
1171
 
          exit(1);
1172
 
        }
1173
 
      if (r == 0)
1174
 
        {
1175
 
          if (last < 0)         /* just in case... */
1176
 
            continue;
1177
 
          p = prgs + last;
1178
 
          writebuf(p);
1179
 
          if (isgtimo && p->pid)
1180
 
            gtimo_running = p;
1181
 
        }
1182
 
      else
1183
 
        {
1184
 
          for (s = 0; s < par; s++)
1185
 
            {
1186
 
              p = prgs + s;
1187
 
              if (p->fd == 0)
1188
 
                continue;
1189
 
              if (!FD_ISSET(p->fd, &rset))
1190
 
                continue;
1191
 
              r = read(p->fd, p->buf + p->len, sizeof(p->buf) - p->len);
1192
 
              if (r <= 0)
1193
 
                {
1194
 
                  if (!gtimo_running || p == gtimo_running)
1195
 
                    writebuf(p);
1196
 
                  close(p->fd);
1197
 
                  p->fd = 0;
1198
 
                  break;
1199
 
                }
1200
 
              p->len += r;
1201
 
              if (p->len == sizeof(p->buf))
1202
 
                {
1203
 
                  for (i = p->len - 1; i >= 0; i--)
1204
 
                    {
1205
 
                      if (p->buf[i] == '\n')
1206
 
                        break;
1207
 
                    }
1208
 
                  if (++i <= 0)
1209
 
                    i = p->len;
1210
 
                  p->len = i;
1211
 
                  writebuf(p);
1212
 
                  p->len = i;   /* writebuf clears p->len */
1213
 
                  if (p->len < sizeof(p->buf))
1214
 
                    memmove(p->buf, p->buf + p->len, sizeof(p->buf) - p->len);
1215
 
                  p->len = sizeof(p->buf) - p->len;
1216
 
                }
1217
 
              p->lastio = now;
1218
 
            } /* for (s = 0; s < par; s++) */
1219
 
        }
1220
 
    } /* for (;;) */
1221
 
 
1222
 
 finished:
1223
 
  waitsplash();
1224
 
  if (run_mode)
1225
 
    print_run_result(resvec, nodevec, run_mode);
1226
 
  else
1227
 
    {
1228
 
      for (i = 0; i < argc; i++)
1229
 
        {
1230
 
#if DEBUG
1231
 
          if (resvec[i] == 255)
1232
 
            {
1233
 
              fprintf(stderr, "ERROR: forgotten process??\n");
1234
 
              exit (1);
1235
 
            }
1236
 
#endif
1237
 
#if VERBOSE
1238
 
          printf(i ? " %d" : "%d", resvec[i]);
1239
 
#endif /* VERBOSE */
1240
 
        }
1241
 
#if VERBOSE
1242
 
      printf("\n");
1243
 
#endif /* VERBOSE */
1244
 
    }
1245
 
  return 0;
1246
 
}