/*static char *SCCSID = "@(#)main.c	6.5 91/11/06";*/
/***	MAIN.C - Entry point for format.
 *
 *	Format
 *	Michael Walma
 *	Copyright March 1988, Microsoft Corp.
 *	March 28 1988
 *
 *	Modification History:
 * code   def/fea  YYMMMDD release who  <description>
 * ---------------------------------------------------------------------------
 * @d01 = 73790    93jul29         glm  <MOVE fmt_verify_label call before
 *                                       fmt_open_lock_disk call. Fixes problem
 *                                       on HPFS386.IFS.  GLMORRIS@AUSVM1>
 *                             nizinski <change loop in fmt_verify_label
 *                                       to go from i to sizeof(infobuf.szVolLabel
 *                                       to match test in memicmp>
 *        74485    93oct27     nizinski <if fmt_verify_label passes back
 *                                       a rc of NOTHANKS_CODE, then the
 *                                       user decided not to format by
 *                                       typing 'N'. Be sure to exit with
 *                                       rc=0 so SYS1276 message is avoided.
 *                                       Also changed fmt_verify_label to
 *                                       suppress SYS1276 message when
 *                                       user enters wrong volume label.
 */

#include <setjmp.h>
#define INCL_DOSFILEMGR
#define INCL_DOSPROCESS
#include "ldefs.h"
#include "ltypes.h"
#include "globals.h"
#include <pr_fmt.h>

extern jmp_buf fmt_error;

void _loadds call_dismount (void);

void _loadds call_dismount (void)	/* necessary because DosExitList won't */
{					/* take a _loadds function, but we need */
  dismount ();				/* ds loaded to access our data. */
}

/***	fmt_exit_handler - termination function for FORMAT
 *
 *	This function is called when FORMAT terminates prematurely.
 *	It dismounts the force-mount that is in effect on the drive.
 *
 *	fmt_exit_handler (code)
 *
 *	ENTRY		code - reason for termination
 *
 *	EXIT		No return value
 *
 *	CALLS		DosExitList
 *			dismount
 *
 *	WARNINGS	None
 *
 *	EFFECTS		Dismounts drive
 */
void far pascal fmt_exit_handler (USHORT code)
{
  call_dismount ();

  DosExitList (EXLST_EXIT, NULL);

  code;
}


/***	format - entry point for FORMAT
 *
 *	This is the top-level routine for the FORMAT utility.  It calls
 *	lower-level routines to parse the command line, access the disk,
 *	format the disk, and install a new file system.
 *
 *	format (argc, argv, envp)
 *
 *	ENTRY		argc - count of command line arguments
 *			argv - list of pointers to command line arguments
 *			envp - list of pointers to environment strings
 *
 *	EXIT		Returns 0 or uses fmt_exit_error in case of error.
 *
 *	CALLS:		close_disk
 *			fmt_exit_error
 *			fmt_format_disk
 *			fmt_init_file_system
 *			fmt_open_lock_disk
 *			fmt_parse_command
 *			fmt_write_file_system
 *			setjmp
 *
 *	WARNINGS	None
 *
 *	EFFECTS		Allocates and deallocates memory
 *			Formats disk
 *			Installs file system
 */
USHORT far pascal _loadds format (argc, argv, envp)
  USHORT argc;
  UCHAR **argv;
  UCHAR **envp;
{
  USHORT rc;

  if (setjmp (fmt_error))		/* exit_error returns to here */
  {
    if (fmt_not_bad_param_flag)    /* 74485 if not a param error, return 0 */
       return (0);                 /* 74485 to avoid SYS1276 message */
    else
       return (ERROR_CODE);	     /* return exit code to frontend */
                                   /* caused SYS1276 msg to be displayed */
  }

#ifdef TIMESTAMPS
  printf ("%sBuilt %s %s\n\n", fmt_version_str, __DATE__, __TIME__);
#endif

/*
 * Find out whether the standard output handle has been redirected
 * to a file.  This information is later used to control whether
 * the percent-formatted display is used.
 */

  check_stdout_redir ();

/*
 * Parse the command line for a drive letter and options.
 */

  if (!fmt_parse_command (argc, argv))
    fmt_exit_error (ARG_ERROR);

#ifdef FILE_VER
  printf ("Enter number of sectors in volume (hex): ");
  scanf ("%lx", &fmt_volsize);
  zeros = malloc (SECSIZE);
  memset (zeros, '\0', SECSIZE);
#endif

#ifndef FILE_VER              /* @d01m - new location */
/*
 * Safeguard against accidental formatting.  We do this by asking the user
 * for the current volume label on the drive.  If what he types doesn't
 * match what's on the drive, we just exit.  Even if he types the correct
 * label, we still print a warning message and wait for a confirming 'Y' or
 * 'N' before starting to format.
 * Note that if the volume label entered by the user does not match
 * the current volume label, the fmt_verify_label routine calls
 * fmt_exit_error and never returns here.
 */

  if (rc=fmt_verify_label ())		/* PTM 3410 */
  {
    if (rc=NOTHANKS_CODE)        /* 74485 - user decided not to format */
       rc = 0;                   /* 74485 - zero to avoid SYS1276.     */
    return (rc);
  }
#endif                           /* @d01m - new location */

/*
 * Get a handle to the requested disk and lock out other users.
 */

  if (!fmt_open_lock_disk ())
    fmt_exit_error (OPEN_ERROR);

                                        /* @d01- original location */

  DosExitList (EXLST_ADD, fmt_exit_handler);

/*
 * Format the disk track by track, checking for bad tracks.
 */

  if ( (rc = fmt_format_disk ()) != NO_ERROR ) {

    if( rc == ERROR_TOO_MANY_OPEN_FILES )
	fmt_exit_error (TOO_MANY_MOUNTS_ERROR);
    else
	fmt_exit_error (FORMAT_ERROR);

  }

  pinboot.signature = SIGNATURE_VAL;

/*
 * Build memory images of new file system structures.
 */

  fmt_init_file_system ();

/*
 * Write the file system to disk.  Also closes the disk handle.
 */

  if (!fmt_write_file_system ())
    fmt_exit_error (INSTALL_ERROR);

  DosExitList (EXLST_REMOVE, fmt_exit_handler);



  if (fmt_update_config_flag) {

     /*	 Diddle config.sys to autocheck the new volume
      */
     if (!fixcfg ()) {
       fmt_cant_find_config ();
     }
  }

  return (SUCCESS_CODE);
  envp;					/* we need this refernence to */
					/* eliminate warning. We need */
					/* to put it on the stack because */
					/* the calling routine takes it off. */
}

/***	fmt_verify_label - ask user to verify current volume label
 *
 *	This function is called to prevent accidental formatting.  It
 *	asks the user to type the current volume label for the drive,
 *	and checks that against what is really on the drive.  If they
 *	don't match, the format is not allowed.
 *
 *	If the user types the correct volume label (or if the drive has
 *	no volume label on it) then the user is given a warning message
 *	and must type 'Y' to proceed with the format.  If he types 'N',
 *	FORMAT exits.
 *
 *	This function also reads the partition boot record into a scratch
 *	area.  The current volume label is not queried if the partition
 *	boot record does not have a signature (indicating that the
 *	partition has never been formatted).
 *
 *	This function is a fix for PTM 3410.
 *
 *	fmt_verify_label ()
 *
 *	ENTRY		No parameters
 *			disk_name contains name of drive, uppercase
 *
 *	EXIT		Returns 0 if OK to format, otherwise exit code
 *
 *	CALLS		DosQFSInfo
 *			computmsg
 *
 *	WARNINGS	None
 *
 *	EFFECTS		Asks file system for volume label
 *			Reads input from user
 */
USHORT fmt_verify_label ()
{
  register USHORT i;
  USHORT rc;
  struct label_buf infobuf;
  UCHAR *p=disk_name;

  USHORT usSearch = 1;			  /* BIGDISK */
  FILEFINDBUF findbuf;			  /* BIGDISK */
  HDIR hdir = HDIR_SYSTEM;		  /* BIGDISK */
  static CHAR achFind [] = "c:\\*.*";	  /* BIGDISK */

  achFind[0] = disk_name [0];								  /* BIGDISK */
//if (DosFindFirst (achFind, &hdir,                               //@d01d                 /* BIGDISK */
  if ((rc=DosFindFirst (achFind, &hdir,                           //@d01a                 /* BIGDISK */
		    FILE_NORMAL | FILE_READONLY | FILE_HIDDEN |				  /* BIGDISK */
		    FILE_SYSTEM | FILE_DIRECTORY | FILE_ARCHIVED,			  /* BIGDISK */
          &findbuf, sizeof (findbuf), &usSearch, 0L)) != ERROR_NOT_DOS_DISK) { //@d01a  /* BIGDISK */
//        &findbuf, sizeof (findbuf), &usSearch, 0L) != ERROR_NOT_DOS_DISK) {  //@d01d  /* BIGDISK */

    if (!rc) DosFindClose (hdir);   // close so drive lock succeeds //@d01a

    rc = DosQFSInfo ((USHORT)(disk_name [0] - 'A' + 1), /* 1-based drive no. */
		     0x0002,				/* info level */
		     (UCHAR far *)&infobuf,		/* place to store label */
		     sizeof (struct label_buf));	/* size of buffer */

    if (rc==ERROR_DRIVE_LOCKED) fmt_exit_error (OPEN_ERROR);      //@d01a

    if (!rc && infobuf.cbVolLabel
#ifdef PMFRONTEND
	&& (!fmt_pmfrontend)				    //PCR PM FRONT END
#endif
       )
    {		/* have a non-empty label */
      for (i=infobuf.cbVolLabel; i < sizeof (infobuf.szVolLabel); i++) //@d01c
	infobuf.szVolLabel [i] = '\0';		/* replace spaces with zeroes */
      FMT_COMPUTMSG( SYSTEM_MSG, &p, 1, FMT_CUR_LABEL_STR, msgfilename, STDOUT_CODE,
		 STRING_RESPONSE, scratchbuf, 1024);

      if (memicmp (scratchbuf, infobuf.szVolLabel, sizeof (infobuf.szVolLabel)))
      {
        fmt_not_bad_param_flag = TRUE;       /* 74485 not a bad param */
	     fmt_exit_error (WRONG_LABEL_ERROR);	/* user typed wrong label */
      }
    }
  }
    else {			     /* BIGDISK */
      pinboot.signature = 0;
    }				     /* BIGDISK */

  memset (pinboot.Extended_Boot.Boot_Vol_label, '\0', sizeof (pinboot.Extended_Boot.Boot_Vol_label));

  FMT_COMPUTMSG( SYSTEM_MSG, &p, 1, FMT_REALLY_FORMAT_STR, msgfilename, STDOUT_CODE,
	     YES_NO_RESPONSE, scratchbuf, 1);
  return (scratchbuf [0] == YES_ANS ? 0 : NOTHANKS_CODE);
}

/***	fmt_cant_find_config - handle the case where format
 *			       cannot find config.sys
 *
 *	fmt_cant_find_config ()
 *
 *	ENTRY		No parameters
 *
 *	EXIT		None
 *
 *	CALLS		computmsg
 *
 *	WARNINGS	None
 *
 *	EFFECTS		Prints message warning user
 */

void fmt_cant_find_config ()
{
    FMT_COMPUTMSG( SYSTEM_MSG, NULL, 0, FMT_CANT_FIND_CONFIG_STR, msgfilename, STDOUT_CODE,
	       NO_RESPONSE, NULL, 0);
}
