Subject: Re: kern/5504: signal handler does not get called again after execve
To: None <mouse@Rodents.Montreal.QC.CA>
From: John Kohl <jtk@kolvir.arlington.ma.us>
List: netbsd-bugs
Date: 05/28/1998 08:55:04
This seems related to a bug I ran into on SunOS, which is present in
NetBSD as well.  Solaris and Digital UNIX do not have this bug.

Signal delivery masks (the sigmasks installed while a signal is handled)
should be cleared at exec() time, but they are not.  Here is a pair of
sample programs that illuminate the problem.  sethandler installs a
handler for a signal, and then execs showsigmask to display all the
signals and their disposition.

>From my internal records on this bug at work:

 When a new image is exec()ed on UNIX, the system cleans out all
 the previous signal handlers.  On OSF/1 and Solaris, it also cleans out
 the signal delivery masks (it's held in sigvec.sv_mask).  On SunOS, it
 removes the previous handler but leaves sv_mask set.  Now, most programs
 don't give a hoot--if they install a new signal handler, they ignore the 
 existing sv_mask and set their own.  ksh, however, examines the existing
 sv_mask and (apparently) ORs it into the sv_mask it sets.

sethandler.c:

#include <unistd.h>
#include <stdio.h>
#include <signal.h>

void handler()
{
    printf("handled\n");
    return;
}


main()
{
	int i;
	sigset_t sm;
	struct sigaction sv, sv2;
	sigset_t MASK;
	sigemptyset(&MASK);
	sigaddset(&MASK, SIGINT);
	sigaddset(&MASK, SIGTERM);
	sigaddset(&MASK, SIGHUP);

	sv.sa_handler = handler;
	sv.sa_mask = MASK;
	sv.sa_flags = 0;
	if (sigaction(2, &sv, 0) == -1)
		perror("sigaction");
	printf("set signal 2 mask to %x\n", sv.sa_mask);
	if (sigaction(2, 0, &sv2) == 0)
		printf("signal %d handler=%lx, mask=%lx, flags=%lx\n",
		       2, sv2.sa_handler, 
		       sv2.sa_mask,
		       sv2.sa_flags);
	else
		perror("sigaction");
	sleep(3);
	system("./showsigmask");
	exit(1);
}

showsigmask.c:

#include <unistd.h>
#include <stdio.h>
#include <signal.h>

void
handler()
{
    printf("handled\n");
    return;
}

int
main(int argc, char *argv[])
{
	int i;
	sigset_t sm;
	struct sigaction sv, sv2;
    
	/*    sigsetmask(1<<15);*/
	sigprocmask(0, NULL, &sm);

	printf("%s: sigmask is %lx\n", argv[0], sm);
	for (i = 1; i < 32; i++) {
		if (sigismember(&sm, i))
			printf("signal %d blocked\n", i);
		memset(&sv, 0, sizeof(sv));
		memset(&sv2, 0, sizeof(sv2));
		if (sigaction(i, &sv, &sv2) == 0)
			printf("signal %d handler=%lx, mask=%lx, flags=%lx\n",
			       i, sv2.sa_handler,
			       sv2.sa_mask,
			       sv2.sa_flags);
		else
			perror("sigaction");
		sigaction(i, &sv2, 0);		/* restore */
	}
	signal(2, SIG_DFL);
	if (sigaction(2, &sv, &sv2) == 0)
		printf("signal %d handler=%lx, mask=%lx, flags=%lx\n",
		       2, sv2.sa_handler,
		       sv2.sa_mask,
		       sv2.sa_flags);
	else
		perror("sigaction");
	signal(2, handler);
	if (sigaction(2, &sv, &sv2) == 0)
		printf("signal %d handler=%lx, mask=%lx, flags=%lx\n",
		       2, sv2.sa_handler,
		       sv2.sa_mask,
		       sv2.sa_flags);
	else
		perror("sigaction");
	exit(0);
}