/*
 * Copyright 2003 Ned Ludd <solar@gentoo.org>
 * Distributed under the terms of the GNU General Public License v2
 * $Header: $
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
// #include <dlfcn.h>

#ifdef __linux__
#include <elf.h>
#include <asm/elf.h>
#else
#include <sys/elf_common.h>
#endif


#ifndef ELF_CLASS
#error "UNABLE TO DETECT ELF_CLASS"
#endif

#if (ELF_CLASS == ELFCLASS32)
#define Elf_Ehdr        Elf32_Ehdr
#define Elf_Phdr        Elf32_Phdr
#define Elf_Shdr	Elf32_Shdr
#define Elf_Dyn		Elf32_Dyn
#endif

#if (ELF_CLASS == ELFCLASS64)
#define Elf_Ehdr        Elf64_Ehdr
#define Elf_Phdr        Elf64_Phdr
#define Elf_Shdr	Elf64_Shdr
#define Elf_Dyn		Elf64_Dyn
#endif

struct Elf_File {
   Elf_Ehdr *ehdr;
   Elf_Phdr *phdr;
   Elf_Shdr *shdr;
   Elf_Dyn *dyn;
   char *data;
   int len;
};

typedef struct Elf_File elfobj;

#define IS_ETEXEC(elf) ( \
	(elf->ehdr->e_type == ET_EXEC) && \
		(elf->ehdr->e_ident[EI_CLASS] == ELFCLASS32 || \
			elf->ehdr->e_ident[EI_CLASS] == ELFCLASS64) \
	)

/* Read an elf file into memory and map headers */
elfobj *readelf(char *filename)
{
   struct stat st;
   elfobj *elf;
   int fd;

   if (stat(filename, &st) == -1)
      return NULL;

   if ((fd = open(filename, O_RDONLY)) == -1)
      return NULL;

   if (st.st_size <= 0)
      return NULL;

   elf = NULL;
   elf = (void *) malloc(sizeof(elfobj));
   if (elf == NULL)
      return NULL;
   elf->len = st.st_size;
   elf->data =
       (char *) mmap(0, elf->len, PROT_READ | PROT_WRITE,
		     MAP_PRIVATE | MAP_DENYWRITE, fd, 0);

   if (elf->data == (char *) MAP_FAILED) {
      free(elf);
      return NULL;
   }

   elf->ehdr = (void *) elf->data;
   elf->phdr = (void *) (elf->data + elf->ehdr->e_phoff);
   elf->shdr = (void *) (elf->data + elf->ehdr->e_shoff);

   /* elf->fd = fd; */
   /* do we want to keep the fd open? */
   close(fd);
   return elf;
}

/* check the elf header */
int check_elf_header(Elf_Ehdr const *const ehdr)
{
   if (!ehdr || strncmp((void *) ehdr, ELFMAG, SELFMAG) != 0 ||
       (ehdr->e_ident[EI_CLASS] != ELFCLASS32
	&& ehdr->e_ident[EI_CLASS] != ELFCLASS64)
       || ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
      return 1;
   }
   return 0;
}

int main(int argc, char **argv)
{
   int i = 0;
   elfobj *elf = NULL;
   int exit_val = 0;

   if (argc < 2)
      return exit_val;

   while (*argv++) {
      if ((elf = readelf(*argv)) != NULL) {
	 if (!check_elf_header(elf->ehdr)) {
	    if (IS_ETEXEC(elf)) {
	       // sstrip here
	       // execve();
	       printf("%s\n", *argv);
	    } else {
	       // gnu strip with argv
	       // execve();
	    }
	 }
	 munmap(elf->data, elf->len);
	 free(elf);
      }
   }
   return exit_val;
}
