/*
    mknod : A slimmed down mknod binary for klibc
    Copyright (C) 2006, Aaron Griffin <aaronmgriffin@gmail.com>
    Based on work by David MacKenzie <djm@ai.mit.edu>

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/stat.h>

#define PROGRAM_NAME "mknod"

int main(int argc, char **argv)
{
    int optc;
    mode_t node_type, newmode=0;
    unsigned long i_maj, i_min;
    const char *s_mode = NULL;
    char *fail = NULL;

    while((optc = getopt(argc, argv, "m:")) != -1)
    {
        switch(optc)
        {
        case 'm':
            s_mode = optarg;
            break;
        default:
            fprintf (stderr,"Usage: " PROGRAM_NAME " [-m MODE#] NAME {b,c,u,p} [MAJOR# MINOR#]\n");
            return 1;
        }
    }

    if(s_mode)
    {
        newmode = strtoul(s_mode, &fail, 8);
        if(*fail)
        {
            fprintf(stderr,PROGRAM_NAME ": invalid mode %s\n", s_mode);
            return 1;
        }
    }

    if (argc - optind != 2 && argc - optind != 4)
    {
        if (argc - optind < 2)
            fprintf (stderr, PROGRAM_NAME ": %s\n", "too few arguments");
        else if (argc - optind > 4)
            fprintf (stderr, PROGRAM_NAME ": %s\n", "too many arguments");
        else
            fprintf (stderr, PROGRAM_NAME ": %s\n", "wrong number of arguments");
        return 1;
    }

    switch (argv[optind + 1][0])
    {
    case 'b':			/* `block' or `buffered' */
        node_type = S_IFBLK;
        break;
    case 'c':			/* `character' */
    case 'u':			/* `unbuffered' */
        node_type = S_IFCHR;
        break;
    case 'p':
        node_type = S_IFIFO;
        break;
    default:
        fprintf(stderr,"invalid device type %s\n", argv[optind + 1]);
        return 1;
    }

    i_maj = strtoul(argv[optind + 2], &fail, 10);
    if(*fail)
    {
        fprintf(stderr,PROGRAM_NAME ": invalid major number %s\n", argv[optind + 2]);
        return 1;
    }
    i_min = strtoul(argv[optind + 3], &fail, 10);
    if(*fail)
    {
        fprintf(stderr,PROGRAM_NAME ": invalid minor number %s\n", argv[optind + 3]);
        return 1;
    }

    if (mknod(argv[optind], newmode | node_type, makedev(i_maj,i_min)) != 0)
    {
        fprintf(stderr, PROGRAM_NAME ": %s - %s\n" , strerror(errno), argv[optind]);
        return 1;
    }
    if (s_mode && chmod(argv[optind], newmode))
        fprintf(stderr,"cannot set permissions of %s\n", argv[optind]);

    return 0;
}
