#include <sys/fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>

void setstack(long size, char *filename)
{
  int fd;
  int len, i;
  caddr_t addr;
  struct stat s;
  static int printed_header = 0;
  
  if (stat(filename, &s) == -1 || !S_ISREG(s.st_mode))
  {
    close(fd);
    return;
  }
  fd = open(filename, O_RDWR);
  if (fd == -1)
  {
    perror(filename);
    return;
  }
  len = lseek(fd, 0, SEEK_END);
  addr = mmap(NULL, len, PROT_WRITE | PROT_READ, MAP_SHARED, fd, 0);
  if (fd == -1)
  {
    perror(filename);
    close(fd);
    return;
  }
  for (i = 0; i < len - 12; i += 2)
    if (*(long *)(addr + i) == 'StCk' && *(long *)(addr + i + 8) == 'sTcK')
    {
      if (size >= 0)
      {
        lseek(fd, i + 4, SEEK_SET);
        write(fd, &size, 4);
      }
      else
      {
        if (!printed_header)
        {
          printed_header = 1;
          printf("stacksize  filename\n---------  --------\n");
        }
        printf("%9d  %s\n", *(long *)(addr + i + 4), filename);
      }
      munmap(addr, len);
      close(fd);
      return;
    }
  close(fd);
  if (size)
    printf("cannot set stack: %s\n", filename);
}

main(int argc, char **argv)
{
  long size;

  if (argc < 3)
  {
    fprintf(stderr, "set stacksize:  ixstack <stacksize> <files ...>
show stacksize: ixstack -l <files ...>\n");
    exit(1);
  }
  if (!strcmp(argv[1], "-l"))
    size = -1;
  else
  {
    int i;
    
    for (i = 0; argv[1][i]; i++)
      if (!isdigit(argv[1][i]))
      {
        fprintf(stderr, "stacksize %s is not a number\n", argv[1]);
        exit(1);
      }
    size = atol(argv[1]);
    if (size < 4000 && size)
    {
      fprintf(stderr, "stacksize must be at least 4000 bytes\n");
      exit(1);
    }
    if (size && (size & 3))
    {
      fprintf(stderr, "stacksize must be a multiple of 4\n");
      exit(1);
    }
  }
  argv += 2;
  while (*argv)
    setstack(size, *argv++);
}
