Subject: Re: kern/5504: signal handler does not get called again after execve
To: TheMan <andrew@untraceable.net>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: netbsd-bugs
Date: 05/28/1998 07:51:17
> >Release:        1.2

You're unlikely to get anything but "upgrade!", unless this proves to
be present in -current.

> >How-To-Repeat:
> 	write a program that re-execs itself after receiving a SIGHUP.
> 	send it a SIGHUP.  then send the new process a SIGHUP.  notice
> 	that it doesn't work.

This "how" is woefully incomplete.  I'd want to see full code to the
test program - for example, if you re-exec() directly in the SIGHUP
handler, the exec will happen with SIGHUP blocked, and the usual
unblocking mechanism upon exiting a signal handler will not get a
chance to run because the signal handler does not exit.  But if you
just set a volatile sig_atomic_t variable and exec from the main line,
something weirder is going on.

> >Fix:
> 	i looked at sendmail code (since it does this correctly) and
> 	noticed that it mucks about with sigprocmask(2).  shouldn't an
> 	exec clear such things?

No, an exec does *not* unblock a signal that's currently blocked.  See
execve(2)

     Signals set to be ignored in the calling process are set to be ignored in
     the new process. Signals which are set to be caught in the calling pro­
     cess image are set to default action in the new process image.  Blocked
     signals remain blocked regardless of changes to the signal action.  The
     signal stack is reset to be undefined (see sigaction(2) for more informa­
     tion).

and sigaction(2)

     Execve(2) reinstates the default action for all signals which were caught
     and resets all signals to be caught on the user stack.  Ignored signals
     remain ignored; the signal mask remains the same; signals that restart
     pending system calls continue to do so.

Here's a test program.  It works fine (for me - NetBSD/sparc 1.3E).
But if I uncomment the exec_self() call inside sighup(), it exhibits
symptoms such as you describe - the first SIGHUP works, but further
SIGHUPs are ignored.

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

extern const char *__progname;

static int argc;
static char **argv;

static volatile sig_atomic_t gothup;

static void exec_self(void)
{
 printf("got SIGHUP\n");
 fflush(0);
 execv(argv[0],argv);
 fprintf(stderr,"%s: can't exec myself: %s\n",__progname,strerror(errno));
 exit(1);
}

static void sighup(int sig __attribute__((__unused__)))
{
 gothup = 1;
/* exec_self(); */
}

int main(int, char **);
int main(int ac, char **av)
{
 struct sigaction sa;

 printf("starting up, pid = %d\n",getpid());
 fflush(0);
 argc = ac;
 argv = av;
 gothup = 0;
 sa.sa_handler = sighup;
 sigemptyset(&sa.sa_mask);
 sa.sa_flags = 0;
 sigaction(SIGHUP,&sa,0);
 while (1)
  { if (gothup) exec_self();
    sleep(1);
    printf(".");
    fflush(0);
  }
}

					der Mouse

			       mouse@rodents.montreal.qc.ca
		     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B