#define _POSIX_C_SOURCE 200809L
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int
makedir(const char *name, mode_t mode, int parents)
{
    struct stat st;
    if (mkdir(name, mode) == 0) return 0;
    if (parents && errno == EEXIST) {
        if (stat(name, &st) < 0) { perror(name); return 1; }
        if (S_ISDIR(st.st_mode)) return 0;
        errno = ENOTDIR;
    }
    perror(name);
    return 1;
}

static int
mkdirp(char *name, mode_t mode, mode_t parent_mode)
{
    char *p;
    if (!*name) { errno = ENOENT; perror(name); return 1; }
    for (p = name + 1; *p; ++p) {
        int status;
        if (*p != '/' || p[-1] == '/') continue;
        *p = '\0';
        status = makedir(name, parent_mode, 1);
        *p = '/';
        if (status) return 1;
    }
    return makedir(name, mode, 1);
}

int
main(int argc, char **argv)
{
    mode_t mode = 0777;
    mode_t parent_mode = 0777;
    int option, parents = 0, explicit_mode = 0, status = 0;
    while ((option = getopt(argc, argv, "pm:")) != -1) {
        if (option == 'p') parents = 1;
        else if (option == 'm') {
            char *end;
            unsigned long n;
            errno = 0;
            n = strtoul(optarg, &end, 8);
            if (errno || !*optarg || *end || optarg[0] == '-' || n > 0777) goto usage;
            mode = (mode_t)n;
            explicit_mode = 1;
        } else goto usage;
    }
    if (optind == argc) goto usage;
    if (explicit_mode) parent_mode = (0777 & ~umask(0)) | 0300;
    for (; optind < argc; ++optind)
        status |= parents ? mkdirp(argv[optind], mode, parent_mode) : makedir(argv[optind], mode, 0);
    return status;
usage:
    fprintf(stderr, "usage: %s [-p] [-m mode] dir...\n", argv[0]);
    return 1;
}
