- else if (WIFSIGNALED (status))
- {
- if (!killed || WTERMSIG (status) != SIGTERM)
- fprintf (stderr,
- "%s: %schild pid %d (%s) terminated with signal %d!\n",
- progname, (verbose_p ? "## " : ""),
- pid, current_hack_name (), WTERMSIG (status));
- else if (verbose_p)
- printf ("%s: child pid %d (%s) terminated with SIGTERM.\n",
- progname, pid, current_hack_name ());
- }
- else if (suspending)
- {
- suspended_p = True;
- suspending = False; /* complain if it happens twice */
- }
- else if (WIFSTOPPED (status))
+ }
+}
+
+
+static struct screenhack_job *
+find_job (pid_t pid)
+{
+ struct screenhack_job *job;
+ for (job = jobs; job; job = job->next)
+ if (job->pid == pid)
+ return job;
+ return 0;
+}
+
+static void await_dying_children (saver_info *si);
+#ifndef VMS
+static void describe_dead_child (saver_info *, pid_t, int wait_status);
+#endif
+
+
+/* Semaphore to temporarily turn the SIGCHLD handler into a no-op.
+ Don't alter this directly -- use block_sigchld() / unblock_sigchld().
+ */
+static int block_sigchld_handler = 0;
+
+
+void
+block_sigchld (void)
+{
+#ifdef HAVE_SIGACTION
+ sigset_t child_set;
+ sigemptyset (&child_set);
+ sigaddset (&child_set, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &child_set, 0);
+#endif /* HAVE_SIGACTION */
+
+ block_sigchld_handler++;
+}
+
+void
+unblock_sigchld (void)
+{
+#ifdef HAVE_SIGACTION
+ sigset_t child_set;
+ sigemptyset(&child_set);
+ sigaddset(&child_set, SIGCHLD);
+ sigprocmask(SIG_UNBLOCK, &child_set, 0);
+#endif /* HAVE_SIGACTION */
+
+ block_sigchld_handler--;
+}
+
+static int
+kill_job (saver_info *si, pid_t pid, int signal)
+{
+ saver_preferences *p = &si->prefs;
+ struct screenhack_job *job;
+ int status = -1;
+
+ clean_job_list();
+
+ if (block_sigchld_handler)
+ /* This function should not be called from the signal handler. */
+ abort();
+
+ block_sigchld(); /* we control the horizontal... */
+
+ job = find_job (pid);
+ if (!job ||
+ !job->pid ||
+ job->status == job_killed)
+ {
+ if (p->verbose_p)
+ fprintf (stderr, "%s: no child %ld to signal!\n",
+ blurb(), (long) pid);
+ goto DONE;
+ }
+
+ switch (signal) {
+ case SIGTERM: job->status = job_killed; break;
+#ifdef SIGSTOP
+ /* #### there must be a way to do this on VMS... */
+ case SIGSTOP: job->status = job_stopped; break;
+ case SIGCONT: job->status = job_running; break;
+#endif /* SIGSTOP */
+ default: abort();
+ }
+
+#ifdef SIGSTOP
+ if (p->verbose_p)
+ fprintf (stderr, "%s: %s pid %lu.\n", blurb(),
+ (signal == SIGTERM ? "killing" :
+ signal == SIGSTOP ? "suspending" :
+ signal == SIGCONT ? "resuming" : "signalling"),
+ (unsigned long) job->pid);
+#else /* !SIGSTOP */
+ if (p->verbose_p)
+ fprintf (stderr, "%s: %s pid %lu.\n", blurb(), "killing",
+ (unsigned long) job->pid);
+#endif /* !SIGSTOP */
+
+ status = kill (job->pid, signal);
+
+ if (p->verbose_p && status < 0)
+ {
+ if (errno == ESRCH)
+ fprintf (stderr, "%s: child process %lu (%s) was already dead.\n",
+ blurb(), job->pid, job->name);
+ else