From: Christian Kastner
Date: Wed Dec 23 10:30:40 CET 2015
Subject: Improve waiting for spawned editor

Refine the process of waiting for the spawned editor. Also, block signals while
waiting.

Fix provided by Steve Greenland <stevegr@debian.org>.

Forwarded: no
Last-Update: 2015-12-22
Index: cron/crontab.c
===================================================================
--- cron.orig/crontab.c
+++ cron/crontab.c
@@ -31,6 +31,7 @@ static char rcsid[] = "$Id: crontab.c,v
 #include "cron.h"
 #include <errno.h>
 #include <fcntl.h>
+#include <signal.h>
 #include <sys/file.h>
 #include <sys/stat.h>
 #ifdef USE_UTIMES
@@ -408,6 +409,11 @@ edit_cmd() {
 	 * close and reopen the file around the edit.
 	 */
 
+	/* Turn off signals. */
+	(void)signal(SIGHUP, SIG_IGN);
+	(void)signal(SIGINT, SIG_IGN);
+	(void)signal(SIGQUIT, SIG_IGN);
+
 	switch (pid = fork()) {
 	case -1:
 		perror("fork");
@@ -438,33 +444,34 @@ edit_cmd() {
 	}
 
 	/* parent */
-	xpid = wait(&waiter);
-	if (xpid != pid) {
-		fprintf(stderr, "%s: wrong PID (%d != %d) from \"%s\"\n",
-			ProgramName, xpid, pid, editor);
-		goto fatal;
-	}
-	if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
-		fprintf(stderr, "%s: \"%s\" exited with status %d\n",
-			ProgramName, editor, WEXITSTATUS(waiter));
-		goto fatal;
-	}
-	if (WIFSIGNALED(waiter)) {
-		fprintf(stderr,
-			"%s: \"%s\" killed; signal %d (%score dumped)\n",
-			ProgramName, editor, WTERMSIG(waiter),
-			WCOREDUMP(waiter) ?"" :"no ");
-		goto fatal;
-	}
-	if (fstat(t, &statbuf) < 0) {
-		perror("fstat");
-		goto fatal;
-	}
-	if (mtime == statbuf.st_mtime) {
-		fprintf(stderr, "%s: no changes made to crontab\n",
-			ProgramName);
-		goto remove;
+	while (1) {
+		xpid = waitpid(pid, &waiter, WUNTRACED);
+		if (xpid == -1) {
+			fprintf(stderr, "%s: waitpid() failed waiting for PID %d from \"%s\": %s\n",
+				ProgramName, pid, editor, strerror(errno));
+		} else if (xpid != pid) {
+			fprintf(stderr, "%s: wrong PID (%d != %d) from \"%s\"\n",
+				ProgramName, xpid, pid, editor);
+			goto fatal;
+		} else if (WIFSTOPPED(waiter)) {
+		        /* raise(WSTOPSIG(waiter)); Not needed and breaks in job control shell*/
+		} else if (WIFEXITED(waiter) && WEXITSTATUS(waiter)) {
+			fprintf(stderr, "%s: \"%s\" exited with status %d\n",
+				ProgramName, editor, WEXITSTATUS(waiter));
+			goto fatal;
+		} else if (WIFSIGNALED(waiter)) {
+			fprintf(stderr,
+				"%s: \"%s\" killed; signal %d (%score dumped)\n",
+				ProgramName, editor, WTERMSIG(waiter),
+				WCOREDUMP(waiter) ?"" :"no ");
+			goto fatal;
+		} else
+			break;
 	}
+	(void)signal(SIGHUP, SIG_DFL);
+	(void)signal(SIGINT, SIG_DFL);
+	(void)signal(SIGQUIT, SIG_DFL);
+
 	fprintf(stderr, "%s: installing new crontab\n", ProgramName);
 	switch (replace_cmd()) {
 	case 0:
