/* DASDINIT64.C (C) Copyright Roger Bowler, 1999-2012                */
/*              Hercules DASD Utilities: DASD image builder          */
/*                                                                   */
/*   Released under "The Q Public License Version 1"                 */
/*   (http://www.hercules-390.org/herclic.html) as modifications to  */
/*   Hercules.                                                       */

/*-------------------------------------------------------------------*/
/* This program creates a disk image file and initializes it as      */
/* a blank FBA or CKD DASD volume.                                   */
/*                                                                   */
/* The program is invoked from the shell prompt using the command:   */
/*                                                                   */
/*   dasdinit64 [-options] filename devtype[-model] [volser] [size]  */
/*                                                                   */
/* options    options:                                               */
/*              -a      include alternate cylinders                  */
/*                      (ignored if size specified manually)         */
/*              -z      build compressed device using zlib           */
/*              -bz2    build compressed device using bzip2          */
/*              -0      build compressed device with no compression  */
/*              -r      "raw" init (bypass VOL1 & IPL track fmt)     */
/*              -b      build disabled wait PSW as BC-mode PSW (if   */
/*                      not specified, default is EC-mode PSW)       */
/*              -m      build disabled wait PSW enabled for          */
/*                      machine checks (default is disabled for      */
/*                      machine checks)                              */
/*              -linux  format dasd using linux null track format    */
/*                                                                   */
/*              Note:  To get a disabled wait PSW that matches       */
/*                     what this program originally created,         */
/*                     you must specify the "-b" and "-m"            */
/*                     options.  The revised defaults, if            */
/*                     those switches are not specified, is an       */
/*                     EC-mode PSW disabled for machine checks.      */
/*                                                                   */
/* filename     is the name of the disk image file to be created     */
/*              (this program will not overwrite an existing file)   */
/*                                                                   */
/* devtype      is the emulated device type.                         */
/*              CKD: 2305, 2311, 2314, 3330, 3350, 3375, 3380,       */
/*                   3390, 9345                                      */
/*              FBA: 0671, 3310, 3370, 9313, 9332, 9335, 9336        */
/*                                                                   */
/* model        is the device model number and implies the device    */
/*              size. If specified, then size shouldn't be specified.*/
/*                                                                   */
/* volser       is the volume serial number (1-6 characters)         */
/*              (only if '-r' option not used)                       */
/*                                                                   */
/* size         is the size of the device (in cylinders for CKD      */
/*              devices, or in 512-byte sectors for FBA devices).    */
/*              Shouldn't be specified if model is specified.        */
/*                                                                   */
/*-------------------------------------------------------------------*/

#include "hstdinc.h"
#include "hercules.h"
#include "dasdblks.h"
#include "ccwarn.h"

#define UTILITY_NAME    "dasdinit64"
#define UTILITY_DESC    "64-bit DASD image file creation program"

static void argexit( int code, char* m, const char* pgm );

/*-------------------------------------------------------------------*/
/* DASDINIT64 program main entry point                               */
/*-------------------------------------------------------------------*/
int main ( int argc, char *argv[] )
{
char   *pgm;                            /* less any extension (.ext) */
int     altcylflag = 0;                 /* Alternate cylinders flag  */
int     rawflag = 0;                    /* Raw format flag           */
int     volsize_argnum = 4;             /* argc value of size option */
int     flagECmode = 1;                 /* IPL PSW mode flag         */
int     flagMachinecheck   = 0;         /* IPL PSW machine check flag*/
U32     size = 0;                       /* Volume size               */
U32     altsize = 0;                    /* Alternate cylinders       */
U32     heads = 0;                      /* Number of tracks/cylinder */
U32     maxdlen = 0;                    /* Maximum R1 data length    */
U32     sectsize = 0;                   /* Sector size               */
U16     devtype = 0;                    /* Device type               */
BYTE    comp = 0xff;                    /* Compression algoritm      */
BYTE    type = 0;                       /* C=CKD, F=FBA              */
char    fname[1024];                    /* File name                 */
char    volser[6+1];                    /* Volume serial number      */
BYTE    c;                              /* Character work area       */
CKDDEV *ckd;                            /* -> CKD device table entry */
FBADEV *fba;                            /* -> FBA device table entry */
int     lfs = 0;                        /* 1 = Build large file      */
int     nullfmt = CKD_NULLTRK_FMT1;     /* Null track format type    */
int     rc;                             /* Return code               */

    INITIALIZE_UTILITY( UTILITY_NAME, UTILITY_DESC, &pgm );

    /* Display help if needed or requested */
    if (argc <= 1 || (argc == 2 && !strcmp(argv[1], "-v")))
        argexit( -1, NULL, pgm );

    /* Process optional arguments */
    for ( ; argc > 1 && argv[1][0] == '-'; argv++, argc--)
    {
        if (strcmp("0", &argv[1][1]) == 0)
            comp = CCKD_COMPRESS_NONE;
#if defined( HAVE_ZLIB )
        else if (strcmp("z", &argv[1][1]) == 0)
            comp = CCKD_COMPRESS_ZLIB;
#endif
#if defined( CCKD_BZIP2 )
        else if (strcmp("bz2", &argv[1][1]) == 0)
            comp = CCKD_COMPRESS_BZIP2;
#endif
        else if (strcmp("a", &argv[1][1]) == 0)
            altcylflag = 1;
        else if (strcmp("r", &argv[1][1]) == 0)
            rawflag = 1;
        else if (strcmp("lfs", &argv[1][1]) == 0 && sizeof(off_t) > 4)
            lfs = 1;
        else if (strcmp("linux", &argv[1][1]) == 0)
            nullfmt = CKD_NULLTRK_FMT2;
        else if (strcmp("b", &argv[1][1]) == 0)
            flagECmode = 0;
        else if (strcmp("m", &argv[1][1]) == 0)
            flagMachinecheck = 1;
        else argexit( 0, argv[1], pgm );
    }

    /* Check remaining number of arguments */
    if (argc < (rawflag ? 3 : 4) || argc > (rawflag ? 4 : 5))
        argexit( 5, NULL, pgm );

    /* The first argument is the file name */
    if (argv[1] == NULL || strlen(argv[1]) == 0
        || strlen(argv[1]) > sizeof(fname)-1)
        argexit( 1, argv[1], pgm );

    STRLCPY( fname, argv[1] );

    /* The second argument is the device type.
       Model number may also be specified */
    if (argv[2] == NULL)
        argexit( 2, argv[2], pgm );
    ckd = dasd_lookup (DASD_CKDDEV, argv[2], 0, 0);
    if (ckd != NULL)
    {
        type = 'C';
        devtype = ckd->devt;
        size = ckd->cyls;
        altsize = ckd->altcyls;
        heads = ckd->heads;
        maxdlen = ckd->r1;
    }
    else
    {
        fba = dasd_lookup (DASD_FBADEV, argv[2], 0, 0);
        if (fba != NULL)
        {
            type = 'F';
            devtype = fba->devt;
            size = fba->blks;
            altsize = 0;
            sectsize = fba->size;
        }
    }

    if (!type)
        /* Specified model not found */
        argexit( 2, argv[2], pgm );

    /* If -r option specified, then there is not volume serial
       argument and volume size argument is actually argument
       number 3 and not argument number 4 as otherwise */
    if (rawflag)
        volsize_argnum = 3;
    else
    {
        volsize_argnum = 4;

        /* The third argument is the volume serial number */
        if (argv[3] == NULL || strlen(argv[3]) == 0
            || strlen(argv[3]) > sizeof(volser)-1)
            argexit( 3, argv[3], pgm );

        STRLCPY( volser, argv[3] );
        string_to_upper (volser);
    }

    /* The fourth argument (or third for -r) is the volume size */
    if (argc > volsize_argnum)
    {
        S32 signed_size = 0;    /* SIGNED Volume size */

        if (argc > (volsize_argnum+1))
            argexit( 5, NULL, pgm );

        if (0
            || !argv      [volsize_argnum]
            || strlen(argv[volsize_argnum]) == 0
            || sscanf(argv[volsize_argnum], "%d%c", &signed_size, &c) != 1
            || (type == 'C' && (signed_size < 1 || signed_size > 65536))
            || (type == 'F' && signed_size < 64)
        )
            argexit( 4, argv[volsize_argnum], pgm );

        size = (U32) signed_size;
        altcylflag = 0;
    }

    /* `-linux' only supported for 3390 device type */
    if (nullfmt == CKD_NULLTRK_FMT2 && devtype != 0x3390)
        argexit( 6, NULL, pgm );

    if (altcylflag)
        size += altsize;

    /* Create the device */
    if (type == 'C')
        rc = create_ckd64( fname, devtype, heads, maxdlen, size, volser,
                           comp, (BYTE) lfs, (BYTE) 0, (BYTE) nullfmt,
                           (BYTE) rawflag, (BYTE) flagECmode,
                           (BYTE) flagMachinecheck );
    else
        rc = create_fba64( fname, devtype, sectsize, size, volser, comp,
                           lfs, 0, rawflag );

    /* Display completion message */
    if (rc == 0)
    {
        // "DASD operation completed"
        WRMSG( HHC02423, "I" );
    } else {
        // "DASD operation failed"
        FWRMSG( stderr, HHC02449, "E" );
    }

    return rc;

} /* end function main */

/*-------------------------------------------------------------------*/
/* Subroutine to display command syntax and exit                     */
/*-------------------------------------------------------------------*/
static void argexit( int code, char* m, const char* pgm )
{
    // HHC02445: "Invalid, unsupported or missing %s: %s"

    switch (code) {
    case 0:
        FWRMSG( stderr, HHC02445, "E", "option",      m ? m : "(null)" );
        break;
    case 1:
        FWRMSG( stderr, HHC02445, "E", "filename",    m ? m : "(null)" );
        break;
    case 2:
        FWRMSG( stderr, HHC02445, "E", "device type", m ? m : "(null)" );
        break;
    case 3:
        FWRMSG( stderr, HHC02445, "E", "volser",      m ? m : "(null)" );
        break;
    case 4:
        FWRMSG( stderr, HHC02445, "E", "size",        m ? m : "(null)" );
        break;
    case 5:
        FWRMSG( stderr, HHC02446, "E" );
        break;
    case 6:
        FWRMSG( stderr, HHC02447, "E" );
        break;
    default:
        {
            // HHC02448 "Usage: dasdinit64 ...."

#if defined( HAVE_ZLIB )
            char *bufz = "HHC02448I   -z        build compressed dasd image file using zlib\n";
#else
            char *bufz = "";
#endif

#if defined( CCKD_BZIP2 )
            char *bufbz = "HHC02448I   -bz2      build compressed dasd image file using bzip2\n";
#else
            char *bufbz = "";
#endif

            char* buflfs = "";

            if (sizeof(off_t) > 4)
                buflfs = "HHC02448I   -lfs      build a large (uncompressed) dasd file (if supported)\n";

            WRMSG( HHC02448, "I", pgm, bufz, bufbz, buflfs );
        }
        break;
    }

    exit(code);

} /* end function argexit */
