/*
 *----------------------------------------------------------------------
 *           "THE BEER-WARE LICENSE" (Revision 42):
 * <jeang3nie@HitchHiker-Linux.org> wrote this file. As long as you
 * retain this notice you can do whatever you want with this stuff. If
 * we meet some day, and you think this stuff is worth it, you can buy
 * me a beer in return.
 * ---------------------------------------------------------------------
 *            ______   _______  _          _________
 *           (  __  \ (  ___  )( (    /|( )\__   __/
 *           | (  \  )| (   ) ||  \  ( ||/    ) (
 *           | |   ) || |   | ||   \ | |      | |
 *           | |   | || |   | || (\ \) |      | |
 *           | |   ) || |   | || | \   |      | |
 *           | (__/  )| (___) || )  \  |      | |
 *           (______/ (_______)|/    )_)      )_(
 *
 *         _______  _______  _       _________ _______
 *        (  ____ )(  ___  )( \    /|\__   __/(  ____ \
 *        | (    )|| (   ) ||  \  ( |   ) (   | (    |/
 *        | (____)|| (___) ||   \ | |   | |   | |
 *        |  _____)|  ___  || (\ \) |   | |   | |
 *        | (      | (   ) || | \   |   | |   | |
 *        | )      | )   ( || )  \  |___) (___| (____|\
 *        |/       |/     \||/    \_)\_______/(_______/
 *
 */

#define _XOPEN_SOURCE

#include <ctype.h>
#include <err.h>
#include <inttypes.h>
#include <libgen.h>
#include <linux/limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include <bsd/unistd.h>

static const char *__progname;
uint8_t pflag = 0, vflag = 0;
mode_t mode, _mode, mask;

static void usage() {
  fprintf(stderr, "usage: %s [-hp] [-m mode] dir1 ... dir2 ...\n", __progname);
}

int isoctalmode(char *_mode) {
  int length = strlen(_mode);
  if (length > 5) {
    return 1;
  }
  int i;
  for (i = 0; i < length; i++) {
    if (isdigit(_mode[i]) == 0) {
      return 1;
    }
    int j = _mode[i] - '0';
    if (j > 7) {
      return 1;
    }
  }
  return 0;
}

int _mkdir(char *_path) {
  if (mkdir(_path, 0755) == -1) {
    perror("mkdir");
    exit(EXIT_FAILURE);
  }
  if (vflag)
    fprintf(stderr, "%s: created directory '%s'\n", __progname, _path);
  return 0;
}

/* checks to see if the argument exists, and if it is a directory,
 * before attempting to create it */
int _mkdir_ifnoexist(char *_path) {
  struct stat sb;
  if (stat(_path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
    /* just return 0 if directory exists */
    return 0;
  } else {
    /* create all intermediate dirs 0755 */
    if (_mkdir(_path) == 0)
      return 0;
    else
      return 1;
  }
}

/* parses the path we gave with '-p' and calls _mkdir_ifnoexist */
int _mkdir_p(char *_path) {
  char slash[PATH_MAX] = "/";
  char *d = strtok(_path, "/");
  /* if our path starts with '/', we have to prepend it here, as strtok
   * removes it from 'd'; else just copy the data */
  if (strncmp(_path, "/", 1) == 0) {
    strcat(slash, d);
  } else {
    strcpy(slash, d);
  }
  _mkdir_ifnoexist(slash);
  while (1 < 2) {
    d = strtok(NULL, "/");
    if (d == NULL) { // final destination reached
      /* mkdir doesn't handle sticky bits, so call chmod on our final
       * destination in case the user wanted a certain mode set */
      if (chmod(slash, mode) == -1) {
        perror("chmod");
        exit(EXIT_FAILURE);
      }
      break;
    }
    strcat(slash, "/");
    strcat(slash, d);
    _mkdir_ifnoexist(slash);
  }
  return 0;
}

int main(int argc, char *argv[]) {
  unsigned int index;
  int c;
  char *marg = NULL;
  char *end;
  void *set = NULL;
  umask(mask = umask(0));
  _mode = 0777 & ~mask;
  __progname = basename(argv[0]);

  while ((c = getopt(argc, argv, "hpvm:")) != -1)
    switch (c) {
    case 'h':
      usage();
      exit(EXIT_SUCCESS);
    case 'm':
      marg = optarg;
      break;
    case 'p':
      pflag = 1;
      break;
    case 'v':
      vflag = 1;
      break;
    case '?':
      if (isprint(optopt)) {
        usage();
        exit(EXIT_FAILURE);
      }
    default:
      usage();
    }

  /* no arguments supplied */
  if (argv[optind] == NULL) {
    fprintf(stderr, "Mandatory argument(s) missing\n");
    exit(EXIT_FAILURE);
  }

  /* check for a valid octal mode */
  if (marg) {
    if (isoctalmode(marg) == 0) {
      mode = strtol(marg, &end, 8);
    } else if ((set = setmode(marg)) != NULL) {
      mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO);
      free(set);
    } else {
      errx(1, "invalid file mode: %s", marg);
    }
  } else {
    mode = _mode;
  }

  for (index = optind; index < argc; index++) {
    if (pflag) {
      _mkdir_p(argv[index]);
    } else {
      _mkdir(argv[index]);
      /* mkdir doesn't do sticky bits even if asked to, so call chmod
       * to make sure we set the exact permissions asked for */
      if (chmod(argv[index], mode) == -1) {
        perror("chmod");
        exit(EXIT_FAILURE);
      }
    }
  }
  return 0;
}
