/* Unaligned access control for Linux */
/* public domain */
/* written by Anton Ertl */

/* available from <http://www.complang.tuwien.ac.at/anton/uace.c> */
/* The only usage doc available as of this writing is here */

/* The Linux kernel does not support SSIN_UACPARNT or SSIN_UACSYS, so
   we cannot implement uac; instead we implement uace, which sets the
   uac stuff and then execs a command */

/* example usages:

1) I won't fix mysqladmin, so I don't want to see the "unaligned trap"
   messages in the logs:

   uace noprint mysqladmin

2) I am developing Forth code, and want to get a SIGBUS (and the
   corresponding backtrace) when I do an unaligned access:

   uace sigbus noprint gforth

3) I want all further processes started from this shell session not to
   log "unaligned trap" messages:

   exec uace noprint $SHELL

4) Reenable logging "unaligned trap"s after 3):

   exec uace $SHELL

Note that all children of the uaced process are affected, too.

*/

#include <sys/sysinfo.h>
#include <asm/sysinfo.h>
#include <errno.h>
#define __LIBRARY__
#include <asm/unistd.h>
#include <stdio.h>
#include <unistd.h>
/*
#include <machine/hal_sysinfo.h>
#include <sys/proc.h>
*/

_syscall6(int,osf_setsysinfo,
	    unsigned long,op,int *,buffer, unsigned long, nbytes,
	    int *,start, char *,arg, unsigned long, flag)

int main(int argc, char *argv[])
{
  int i;
  int buf[2];

  if (argc == 1) {
  usage:
    fprintf(stderr, "Usage: uac [noprint] [nofix] [sigbus] [--] command [arg] ...\n");
    exit(1);
  }
  buf[0]=SSIN_UACPROC;
  buf[1]=0;
  for (i=1; i<argc; i++) {
    if (strcmp(argv[i],"noprint")==0)
      buf[1] |= UAC_NOPRINT;
    else if (strcmp(argv[i],"nofix")==0)
      buf[1] |= UAC_NOFIX;
    else if (strcmp(argv[i],"sigbus")==0)
      buf[1] |= UAC_SIGBUS;
    else {
      if (strcmp(argv[i],"--")==0)
        i++;
      break;
    }
  }
  if (i>=argc)
    goto usage;
  if (osf_setsysinfo(SSI_NVPAIRS, buf, 1, 0, 0, 0) == -1) {
    perror("setsysinfo");
    exit(1);
  }
  execvp(argv[i],argv+i);
  return 0;
}
