#define _GNU_SOURCE

#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>

#include <linux/crypto.h>

#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

static int
set_debug (int fd, int arg)
{
  int retval = ioctl (fd, CRYPTOLOOP_SET_DEBUG, &arg);
  
  if (retval)
    perror ("ioctl(CRYPTOLOOP_SET_DEBUG)");

  return retval;
}

static int
set_blksize (int fd, int arg)
{
  int retval = ioctl (fd, CRYPTOLOOP_SET_BLKSIZE, &arg);
  
  if (retval)
    perror ("ioctl(CRYPTOLOOP_SET_BLKSIZE)");

  return retval;
}

int main(int argc, char *argv[])
{

  int arg_set_debug = -1;
  int arg_set_blksize = -1;

  while (1) {
    const static struct option long_options[] = {
      {"set-debug", 1, 0, 'd'},
      {"set-blksize", 1, 0, 'b'},
      {"help", 0, 0, 'h'},
      {0, 0, 0, 0}
    };

    const int c = getopt_long (argc, argv, "d:b:h", long_options, NULL);

    if (c == -1)
      break;

    switch (c) {
    default:
      printf ("option %c", c);
      if (optarg)
	printf (" with arg %s", optarg);
      printf ("\n");
      break;

    case 'd':
      arg_set_debug = atoi (optarg);
      break;

    case 'b':
      arg_set_blksize = atoi (optarg);
      break;

    case '?':
      printf ("error while parsing command line - try --help\n");
      exit (EXIT_FAILURE);
      break;
    case 'h':
      puts ("Usage: cryptoloop_cfg [options] loop_device\n"
	    " --set-debug <num>, -d <num>\n"
	    " --set-blksize <num>, -b <num>\n"
	    "");
      exit (EXIT_SUCCESS);
      break;
    }
  }

  if (optind == argc)
    {
      printf ("error: no loop device given\n");
      exit (EXIT_FAILURE);
    }
  else if (optind + 1 < argc)
    {
      printf ("error: too many non-option arguments given\n");
      exit (EXIT_FAILURE);
    }

  {
    const char *dev_fname = argv[optind];
    int fd;

    printf ("using device %s\n", dev_fname);

    if ((fd = open (dev_fname, O_RDONLY)) < 0)
      {
	perror ("open()");
	exit (EXIT_FAILURE);
      }

    if (arg_set_blksize != -1)
      set_blksize (fd, arg_set_blksize);

    if (arg_set_debug != -1)
      set_debug (fd, arg_set_debug);
    
    close (fd);
  }

  return EXIT_SUCCESS;
}

/*
 Local Variables:
 compile-command: "gcc -Wall -O2 -ansi cryptoloop_cfg.c -o cryptoloop_cfg"
 End:
*/