SIGBUS handling

/* Example of SIGBUS handling. A read from mmap()ed memory is invalid because
 * a file was shrinked. SIGBUS is sent to the process, but we handle it and
 * jump to another place in the program so it doesn't crash.
 *
 * Run this program with or without the 'shrink' argument.
 */
#include <sys/types.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <setjmp.h>
 
/* Size of the file in pages. */
#define FILE_SIZE	4
 
/* Environment and blocked signal state for restoration in a signal handler. */
static sigjmp_buf sj_env;
 
static void sigbus_hdl (int sig, siginfo_t *siginfo, void *ptr)
{
 
	/* Jump (goto) to the saved program state where we don't use mmapped()
	 * memory. */
	siglongjmp (sj_env, 1);
}
 
int main (int argc, char *argv[])
{
	struct sigaction act;
	int fd = -1;
	char *mem = NULL;
	size_t file_size;
 
	memset (&act, 0, sizeof(act));
	act.sa_sigaction = sigbus_hdl;
	act.sa_flags = SA_SIGINFO;
 
	if (sigaction(SIGBUS, &act, 0)) {
		perror ("sigaction");
		return 1;
	}
 
	file_size = sysconf(_SC_PAGE_SIZE) * FILE_SIZE;
 
	fd = open ("file_for_mmap", O_RDWR | O_CREAT | O_TRUNC, 0644);
	if (fd < 0) {
		perror ("open");
		return 1;
	}
 
	/* Enlarge the file to file_size bytes. */
	if (ftruncate(fd, file_size) < 0) {
		perror ("ftruncate");
		return 1;
	}
 
	mem = mmap (NULL, file_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
	if (mem == MAP_FAILED) {
		perror ("mmap");
		return 1;
	}
 
	/* Remember this point as a state that we can return to using
	 * siglongjmp(). If this function returns a value other than 0
	 * it means that we are here because of siglongjmp().
	 */
	if (sigsetjmp(sj_env, 1)) {
		fprintf (stderr, "Failed to read from mapped file\n");
 
		if (mem) {
			if (munmap(mem, file_size) < 0) {
				perror ("munmap");
				return 1;
			}
		}
 
		if (fd >= 0)
			close (fd);
 
		return 1;
	}
 
	if (argc > 1 && !strcmp(argv[1], "shrink")) {
 
		/* Shrink the file to half of it's size. */
		if (ftruncate(fd, file_size / 2) < 0) {
			perror ("ftruncate");
			return 1;
		}
	}
 
	/* Read from mmapped() memory. */
	if (memchr(mem, 'd', file_size)) {
		puts ("found 'd'!");
	}
	else
		puts ("'d' not found");
 
	munmap (mem, FILE_SIZE);
	close (fd);
 
	return 0;
}