/*
 * Copyright (c) 2007, OpenFWTK Development Group
 * All rights reserved. See LICENSE.
 */

/* constchk.c */

/* Copyright 1997 by Eberhard Mattes <mattes@azu.informatik.uni-stuttgart.de>
   Donated to the public domain.  No warranty.
*/

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>

static void sig_install (int);

/* This program checks whether the compiler puts `const' variables and
   string constants into read-only memory (.text) or not.  Yes, I'm
   paranoid. */

static const char * const pgms[] =
{
  "/usr/bin/dig",
  "/usr/bin/finger",
  "/bin/ping",
  "/usr/bin/traceroute"
};

static char non_const;
static jmp_buf cont;

static void sig_handler (int signo)
{
  sig_install (SIGSEGV);
  sig_install (SIGBUS);
  longjmp (cont, signo);
}

static void sig_install (int signo)
{
  struct sigaction sa;

  sa.sa_handler = sig_handler;
  sa.sa_flags = SA_NODEFER;
  sigemptyset (&sa.sa_mask);
  if (sigaction (signo, &sa, NULL) != 0)
    {
      perror ("sigaction");
      exit (2);
    }
}

static void foo (char c)
{
  static volatile char bar;
  bar = c;
}

static void check (char *p, int is_const)
{
  if (setjmp (cont) != 0)
    {
      puts ("I cannot even READ the object!");
      exit (2);
    }
  foo (*p);

  if (setjmp (cont) != 0)
    {
      if (!is_const)
	{
	  puts ("I cannot even write non-const objects!");
	  exit (2);
	}
      return;
    }
  *p = 0;
  if (is_const)
    {
      puts ("Bad news: Your compiler doesn't put const objects into read-only memory.");
      puts ("Try to compile with GCC.");
      return;
    }
}

int main (void)
{
  puts ("Checking if the compiler puts const objects into read-only memory.");
  fflush (stdout);
  sig_install (SIGSEGV);
  sig_install (SIGBUS);
  check (&non_const, 0);	/* I'm paranoid */
  check ((char *)pgms, 1);
  check (&non_const, 0);	/* I'm paranoid */
  check ((char *)pgms[0], 1);
  if (*(pgms[0]) == 0)
      exit (1);
  puts ("Well, things are not _that_ bad, let's continue.");
  return 0;
}
