|
|
//----------------------------------------------------------------------------
//
// Copyright (c) 1999 Microsoft Corporation
// All rights reserved.
//
// File Name:
// makeboot.c
//
// Description:
// This program copies the images of the 4 Windows NT setup disks to
// floppy disk so the user can boot their system with them.
//
// Assumptions:
// The sector size is 512 and the sectors per track is 18
//
// The floppy disk images are in the current dir and named CDBOOT1.IMG,
// CDBOOT2.IMG, CDBOOT3.IMG and CDBOOT4.IMG.
//
// The txtsetup.sif resides in ..\i386 or ..\alpha from where the
// program is being run.
//
//----------------------------------------------------------------------------
#include <bios.h>
#include <string.h>
#include <malloc.h>
#include <io.h>
#include <fcntl.h>
#include <process.h>
#include <errno.h>
#include <conio.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "makeboot.h"
//
// Constants
//
//
// To support disks other than 1.44 MB High-Density floppies, then these
// numbers will have to be changed or determined at run-time.
//
#define SECTORS_PER_TRACK 18
#define SECTOR_SIZE 512
#define TRACK_SIZE SECTORS_PER_TRACK * SECTOR_SIZE
#define NUMBER_OF_TRACKS 80
#define SECTORS_TO_COPY_AT_A_TIME 18
// we multiply by 2 because the disk is double-sided
#define NUMBER_OF_SECTORS_ON_DISK NUMBER_OF_TRACKS * SECTORS_PER_TRACK * 2
#define NT_NAME_OF_MAKEBOOT "makebt32.exe"
#define NT_IMAGE_1_NAME "CDBOOT1.IMG"
#define NT_IMAGE_2_NAME "CDBOOT2.IMG"
#define NT_IMAGE_3_NAME "CDBOOT3.IMG"
#define NT_IMAGE_4_NAME "CDBOOT4.IMG"
#define NT_IMAGE_5_NAME "CDBOOT5.IMG"
#define NT_IMAGE_6_NAME "CDBOOT6.IMG"
#define NT_IMAGE_7_NAME "CDBOOT7.IMG"
#define MAX_INILINE_LENGTH 1023
#define ENTER_KEY 13
#define ESC_KEY 27
#define NUMBER_OF_ASCII_WHEEL_SYMBOLS 4
const char rgAsciiWheel[NUMBER_OF_ASCII_WHEEL_SYMBOLS] = { '|', '/', '-', '\\' };
//
// Function prototypes
//
int WriteImageToFloppy( char *szFileName, int drive ); int DoesUserWantToTryCopyAgain( void ); void ReportBiosError( unsigned int iBiosErrorCode ); int DoImageFilesExist( void ); unsigned int IsFloppyDrive( int DriveLetter ); void PressAnyKeyToContinue( void ); unsigned int AbsoluteDiskWrite( unsigned int *iErrorCode, unsigned int iDrive, unsigned int iStartingSector, unsigned int iNumberOfSectorsToWrite, void far *Buffer_to_be_written );
unsigned DnGetCodepage(void);
//
// Variables that are allocated in strings.c that are used to determine what
// string table to use.
//
extern unsigned int CODEPAGE;
extern const char *EngStrings[];
extern const char *LocStrings[];
//
// This var holds a pointer to the array of strings to be used
//
const char **StringTable;
//----------------------------------------------------------------------------
//
// Function: main
//
// Purpose: Instructs user to insert floppy disks to be copied and performs
// the copy.
//
// Arguments: int argc - standard program argument, count of the command line args
// char *argv[] - standard program argument, the 2nd argument is the
// floppy drive to copy the images to.
// Returns: int - zero on success, non-zero on error
//
//----------------------------------------------------------------------------
int main( int argc, char *argv[] ) {
char *szOsName; char Drive; char DriveLetter; int bTryAgain;
//
// Set the string table to the appropriate language depending on
// the code page.
//
if( *LocStrings[0] == '\0' ) { StringTable = EngStrings; } else {
if( DnGetCodepage() != CODEPAGE ) { StringTable = EngStrings; } else { StringTable = LocStrings; }
}
szOsName = getenv( "OS" );
//
// See if we are on NT. If we are, call the NT version and exit.
// If we aren't then just continue executing this program.
//
if( szOsName && ( stricmp( szOsName, "Windows_NT" ) == 0 ) ) {
int iRetVal;
iRetVal = spawnl( P_WAIT, NT_NAME_OF_MAKEBOOT, NT_NAME_OF_MAKEBOOT, argv[1], NULL );
if( iRetVal == -1 ) { if( errno == ENOENT ) { printf( StringTable[ CANNOT_FIND_FILE ], NT_NAME_OF_MAKEBOOT );
exit( 1 ); } else if( errno == ENOMEM ) { printf( StringTable[ NOT_ENOUGH_MEMORY ] );
exit( 1 ); } else if( errno == ENOEXEC ) { printf( StringTable[ NOT_EXEC_FORMAT ], NT_NAME_OF_MAKEBOOT );
exit( 1 ); } else { printf( StringTable[ UNKNOWN_SPAWN_ERROR ], NT_NAME_OF_MAKEBOOT );
exit( 1 ); } }
// successful completion
exit( 0 );
}
printf( "\n%s\n", StringTable[ STARS ] ); printf( "%s\n", StringTable[ EXPLANATION_LINE_1 ] ); printf( StringTable[ EXPLANATION_LINE_2 ], StringTable[ NT_VERSION_NAME ] ); printf( "\n\n" );
printf( "%s\n", StringTable[ EXPLANATION_LINE_3 ] ); printf( "%s\n\n", StringTable[ EXPLANATION_LINE_4 ] );
//
// If they didn't specified the floppy drive on the command line then
// prompt them for it.
//
if( argc == 1 ) {
printf( StringTable[ SPECIFY_DRIVE ] );
DriveLetter = (char) getche();
printf( "\n\n" );
} else {
DriveLetter = argv[1][0];
}
//
// Make sure the character they entered is a possible drive letter
//
if( ! isalpha( DriveLetter ) ) {
printf( StringTable[ INVALID_DRIVE_LETTER ] );
exit( 1 );
}
//
// Make sure the drive specified is actually a floppy drive
//
if( ! IsFloppyDrive( DriveLetter ) ) {
printf( StringTable[ NOT_A_FLOPPY ], DriveLetter );
exit( 1 );
}
//
// map the drive letter a or A to 0, b or B to 1, etc.
//
Drive = (char) ( toupper( DriveLetter ) - (int)'A' );
//
// Make sure all the images files exist in the current directory
//
if( ! DoImageFilesExist() ) { exit( 1 ); }
printf( StringTable[ INSERT_FIRST_DISK_LINE_1 ], DriveLetter ); printf( "\n" );
printf( StringTable[ INSERT_FIRST_DISK_LINE_2 ], StringTable[ DISK_LABEL_1 ] ); printf( "\n\n" );
PressAnyKeyToContinue();
while( ! WriteImageToFloppy( NT_IMAGE_1_NAME, Drive ) ) {
bTryAgain = DoesUserWantToTryCopyAgain();
if( ! bTryAgain ) { exit( 1 ); }
}
printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_1 ], DriveLetter ); printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_2 ], StringTable[ DISK_LABEL_2 ] ); printf( "\n\n" );
PressAnyKeyToContinue();
while( ! WriteImageToFloppy( NT_IMAGE_2_NAME, Drive ) ) {
bTryAgain = DoesUserWantToTryCopyAgain();
if( ! bTryAgain ) { exit( 1 ); }
}
printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_1 ], DriveLetter ); printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_2 ], StringTable[ DISK_LABEL_3 ] ); printf( "\n\n" );
PressAnyKeyToContinue();
while( ! WriteImageToFloppy( NT_IMAGE_3_NAME, Drive ) ) {
bTryAgain = DoesUserWantToTryCopyAgain();
if( ! bTryAgain ) { exit( 1 ); }
}
printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_1 ], DriveLetter ); printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_2 ], StringTable[ DISK_LABEL_4 ] ); printf( "\n\n" );
PressAnyKeyToContinue();
while( ! WriteImageToFloppy( NT_IMAGE_4_NAME, Drive ) ) {
bTryAgain = DoesUserWantToTryCopyAgain();
if( ! bTryAgain ) { exit( 1 ); }
}
printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_1 ], DriveLetter ); printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_2 ], StringTable[ DISK_LABEL_5 ] ); printf( "\n\n" ); PressAnyKeyToContinue();
while( ! WriteImageToFloppy( NT_IMAGE_5_NAME, Drive ) ) {
bTryAgain = DoesUserWantToTryCopyAgain();
if( ! bTryAgain ) { exit( 1 ); }
}
printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_1 ], DriveLetter ); printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_2 ], StringTable[ DISK_LABEL_6 ] ); printf( "\n\n" ); PressAnyKeyToContinue();
while( ! WriteImageToFloppy( NT_IMAGE_6_NAME, Drive ) ) {
bTryAgain = DoesUserWantToTryCopyAgain();
if( ! bTryAgain ) { exit( 1 ); }
}
printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_1 ], DriveLetter ); printf( "\n" ); printf( StringTable[ INSERT_ANOTHER_DISK_LINE_2 ], StringTable[ DISK_LABEL_7 ] ); printf( "\n\n" ); PressAnyKeyToContinue();
while( ! WriteImageToFloppy( NT_IMAGE_7_NAME, Drive ) ) {
bTryAgain = DoesUserWantToTryCopyAgain();
if( ! bTryAgain ) { exit( 1 ); }
}
printf( "\n\n%s\n\n", StringTable[ COMPLETED_SUCCESSFULLY ] );
printf( "%s\n", StringTable[ STARS ] );
return( 0 );
}
//----------------------------------------------------------------------------
//
// Function: WriteImageToFloppy
//
// Purpose: Writes an image file to a floppy disk. Handles all error
// reporting to the user.
//
// Arguments: char *szFileName - filename to write to the floppy
// int drive - drive letter of the floppy to write to
//
// Returns: int - non-zero on success
// - zero on error
//
//----------------------------------------------------------------------------
int WriteImageToFloppy( char *szFileName, int drive ) {
char *pTrack; int hImageFile; unsigned int iSuccess; unsigned int iErrorCode; unsigned int iBytesRead; unsigned int iTotalSectorsWritten; unsigned int iPercentComplete; unsigned int iWheelPosition; char TrackBuffer[ TRACK_SIZE ]; _fmode = O_BINARY;
//
// Open the image file
//
hImageFile = open( szFileName, O_RDONLY );
if( hImageFile == -1 ) { perror( szFileName );
return( 0 ); }
iWheelPosition = 0; iTotalSectorsWritten = 0;
//
// Loop reading a track and then writing SECTORS_TO_COPY_AT_A_TIME sectors
// out at a time until we reach the end of the file
//
while( ( iBytesRead = read( hImageFile, TrackBuffer, TRACK_SIZE ) ) > 0 ) {
pTrack = TrackBuffer;
for( ; iBytesRead > 0; iTotalSectorsWritten += SECTORS_TO_COPY_AT_A_TIME ) {
iSuccess = AbsoluteDiskWrite( &iErrorCode, drive, iTotalSectorsWritten, SECTORS_TO_COPY_AT_A_TIME, (void far *) pTrack );
if( ! iSuccess ) { ReportBiosError( iErrorCode );
close( hImageFile );
return( 0 ); }
iBytesRead = iBytesRead - ( SECTOR_SIZE * SECTORS_TO_COPY_AT_A_TIME );
pTrack = pTrack + ( SECTOR_SIZE * SECTORS_TO_COPY_AT_A_TIME );
}
iPercentComplete = (int) ( ( (double) (iTotalSectorsWritten) / (double) (NUMBER_OF_SECTORS_ON_DISK) ) * 100.0 );
printf( "%c %3d%% %s\r", rgAsciiWheel[iWheelPosition], iPercentComplete, StringTable[ COMPLETE ] ); //
// Advance the ASCII wheel
//
iWheelPosition++;
if( iWheelPosition >= NUMBER_OF_ASCII_WHEEL_SYMBOLS ) { iWheelPosition = 0; }
}
//
// We are done copying the disk so force it to read 100% and get rid of
// the ascii wheel symbol.
//
printf( " 100%% %s \n", StringTable[ COMPLETE ] );
close( hImageFile );
return( 1 );
}
//----------------------------------------------------------------------------
//
// Function: DoesUserWantToTryCopyAgain
//
// Purpose: Ask the user if they want to retry to copy the image to floppy.
// Get the user input and return whether to copy again or not.
//
// Arguments: void
//
// Returns: int - non-zero if user wants to attempt to copy again
// - zero if user does not want to attempt to copy again
//
//----------------------------------------------------------------------------
int DoesUserWantToTryCopyAgain( void ) {
int ch;
//
// Clear the input stream by eating all the chars until there are none
// left. Print the message and then wait for a key press.
//
while( kbhit() ) { getch(); } do { printf( "%s\n", StringTable[ ATTEMPT_TO_CREATE_FLOPPY_AGAIN ] ); printf( "%s\n", StringTable[ PRESS_ENTER_OR_ESC ] );
ch = getch();
} while( ch != ENTER_KEY && ch != ESC_KEY );
if( ch == ENTER_KEY ) { return( 1 ); } else { return( 0 ); }
}
//----------------------------------------------------------------------------
//
// Function: PressAnyKeyToContinue
//
// Purpose: Print the "Press any key when ready" message and wait until the
// user presses a key.
//
// Arguments: void
//
// Returns: void
//
//----------------------------------------------------------------------------
void PressAnyKeyToContinue( void ) {
//
// Clear the input stream by eating all the chars until there are none
// left. Print the message and then wait for a key press.
//
while( kbhit() ) { getch(); }
printf( "%s\n", StringTable[ PRESS_ANY_KEY_TO_CONTINUE ] );
//
// Spin until the keyboard is pressed
//
while( ! kbhit() ) { ; }
}
//----------------------------------------------------------------------------
//
// Function: DoImageFilesExist
//
// Purpose: Determines if all the image files are in the current directory or
// not. If an image file is missing, an error message is printed
// to the user.
//
// Note: it detemines if a file exists by seeing if it can open it
// for reading.
//
// Arguments: void
//
// Returns: int -- non-zero on success, all images files exist in current dir
// zero on failure, 1 or more image files do not exist
//
//----------------------------------------------------------------------------
int DoImageFilesExist( void ) {
FILE *FileStream; int iSuccess = 1; // assume success
if( ( FileStream = fopen( NT_IMAGE_1_NAME, "r" ) ) == NULL ) { printf( StringTable[ CANNOT_FIND_FILE ], NT_IMAGE_1_NAME );
printf( "\n" );
iSuccess = 0; } else { fclose( FileStream ); }
if( ( FileStream = fopen( NT_IMAGE_2_NAME, "r" ) ) == NULL ) { printf( StringTable[ CANNOT_FIND_FILE ], NT_IMAGE_2_NAME );
printf( "\n" );
iSuccess = 0; } else { fclose( FileStream ); }
if( ( FileStream = fopen( NT_IMAGE_3_NAME, "r" ) ) == NULL ) { printf( StringTable[ CANNOT_FIND_FILE ], NT_IMAGE_3_NAME );
printf( "\n" );
iSuccess = 0; } else { fclose( FileStream ); }
if( ( FileStream = fopen( NT_IMAGE_4_NAME, "r" ) ) == NULL ) { printf( StringTable[ CANNOT_FIND_FILE ], NT_IMAGE_4_NAME );
printf( "\n" );
iSuccess = 0; } else { fclose( FileStream ); }
if( ( FileStream = fopen( NT_IMAGE_5_NAME, "r" ) ) == NULL ) { printf( StringTable[ CANNOT_FIND_FILE ], NT_IMAGE_5_NAME );
printf( "\n" );
iSuccess = 0; } else { fclose( FileStream ); }
if( ( FileStream = fopen( NT_IMAGE_6_NAME, "r" ) ) == NULL ) { printf( StringTable[ CANNOT_FIND_FILE ], NT_IMAGE_6_NAME );
printf( "\n" );
iSuccess = 0; } else { fclose( FileStream ); }
if( ( FileStream = fopen( NT_IMAGE_7_NAME, "r" ) ) == NULL ) { printf( StringTable[ CANNOT_FIND_FILE ], NT_IMAGE_7_NAME );
printf( "\n" );
iSuccess = 0; } else { fclose( FileStream ); } return( iSuccess );
}
//----------------------------------------------------------------------------
//
// Function: IsFloppyDrive
//
// Purpose: To determine if a particular drive is a floppy drive.
//
// Arguments: int DriveLetter - the drive letter to test whether it is a
// floppy or not
//
// Returns: unsigned int -- non-zero if the specified drive is a floppy drive
// zero if the specified drive is not a floppy drive
//
//----------------------------------------------------------------------------
unsigned int IsFloppyDrive( int DriveLetter ) {
unsigned int drive; unsigned int iIsFloppy; //
// Convert the drive letter to a number. 1 = A, 2 = B, 3 = C, ...
//
drive = ( toupper( DriveLetter ) - (int)'A' ) + 1;
//
// Assume it is not a floppy
//
iIsFloppy = 0;
_asm { push ds push es push bp
mov ah, 1Ch // going to call function 1Ch
mov dl, BYTE PTR [drive]
int 21h // call Int 21h function 1Ch
cmp BYTE PTR ds:[bx], 0F8h // test for fixed drive
je done
mov iIsFloppy, 1 // it is a floppy
done:
pop bp pop es pop ds }
return( iIsFloppy );
}
//----------------------------------------------------------------------------
//
// Function: ReportBiosError
//
// Purpose: To convert a BIOS error code to a error message and print it out
// for the user to see.
//
// Arguments: unsigned int iBiosErrorCode - the BIOS error code to be looked up
//
// Returns: void
//
//----------------------------------------------------------------------------
void ReportBiosError( unsigned int iBiosErrorCode ) { //
// Print out the error code for the lower byte
//
switch( iBiosErrorCode & 0x00FF ) {
case 0x0000: printf( StringTable[ ERROR_DISK_WRITE_PROTECTED ] ); break; case 0x0001: printf( StringTable[ ERROR_UNKNOWN_DISK_UNIT ] ); break; case 0x0002: printf( StringTable[ ERROR_DRIVE_NOT_READY ] ); break; case 0x0003: printf( StringTable[ ERROR_UNKNOWN_COMMAND ] ); break; case 0x0004: printf( StringTable[ ERROR_DATA_ERROR ] ); break; case 0x0005: printf( StringTable[ ERROR_BAD_REQUEST ] ); break; case 0x0006: printf( StringTable[ ERROR_SEEK_ERROR ] ); break; case 0x0007: printf( StringTable[ ERROR_MEDIA_TYPE_NOT_FOUND ] ); break; case 0x0008: printf( StringTable[ ERROR_SECTOR_NOT_FOUND ] ); break; case 0x000A: printf( StringTable[ ERROR_WRITE_FAULT ] ); break; case 0x000C: printf( StringTable[ ERROR_GENERAL_FAILURE ] ); break; }
//
// Print out the error code for the upper byte
//
switch( iBiosErrorCode & 0xFF00 ) { case 0x0100: printf( StringTable[ ERROR_INVALID_REQUEST ] ); break; case 0x0200: printf( StringTable[ ERROR_ADDRESS_MARK_NOT_FOUND ] ); break; case 0x0300: printf( StringTable[ ERROR_DISK_WRITE_FAULT ] ); break; case 0x0400: printf( StringTable[ ERROR_SECTOR_NOT_FOUND ] ); break; case 0x0800: printf( StringTable[ ERROR_DMA_OVERRUN ] ); break; case 0x1000: printf( StringTable[ ERROR_CRC_ERROR ] ); break; case 0x2000: printf( StringTable[ ERROR_CONTROLLER_FAILURE ] ); break; case 0x4000: printf( StringTable[ ERROR_SEEK_ERROR ] ); break; case 0x8000: printf( StringTable[ ERROR_DISK_TIMED_OUT ] ); break; }
}
//----------------------------------------------------------------------------
//
// Function: AbsoluteDiskWrite
//
// Purpose: To write a buffer in memory to a specific portion of a disk.
//
// Arguments: unsigned int *iErrorCode - if an error occurs, the error code
// is returned in this OUT variable
// unsigned int iDrive - drive to write the buffer to
// unsigned int iStartingSector - sector where the write is to begin
// unsigned int iNumberOfSectorsToWrite - the number of sectors
// to write
//
// Returns: returns 1 on success, 0 on failure
// If it fails, then the error code is returned in the argument
// iErrorCode.
// If it succeeds, iErrorCode is undefined.
//
//----------------------------------------------------------------------------
unsigned int AbsoluteDiskWrite( unsigned int *iErrorCode, unsigned int iDrive, unsigned int iStartingSector, unsigned int iNumberOfSectorsToWrite, void far *Buffer_to_be_written ) { //
// used to temporarily store the error code
//
unsigned int iTempErrorCode;
unsigned int iRetVal;
_asm { push ds push es push bp
mov ax, WORD PTR [Buffer_to_be_written + 2] mov ds, ax mov bx, WORD PTR [Buffer_to_be_written] mov dx, iStartingSector mov cx, iNumberOfSectorsToWrite mov al, BYTE PTR [iDrive]
int 26h // do the absolute disk write
lahf popf sahf
pop bp pop es pop ds
mov iRetVal, 1 // assume success
jnc done // see if an error occured
mov iRetVal, 0 mov iTempErrorCode, ax done: }
*iErrorCode = iTempErrorCode;
return( iRetVal );
}
unsigned DnGetCodepage(void)
/*++
Routine Description:
Determine the currently active codepage.
Arguments:
None.
Return Value:
Currently active codepage. 0 if we can't determine it.
--*/
{
unsigned int iRetVal;
_asm { mov ax,06601h int 21h jnc ok xor bx,bx ok: mov iRetVal,bx }
return( iRetVal );
}
|