//---------------------------------------------------------------------------- // // 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 #include #include #include #include #include #include #include #include #include #include #include #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 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\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 ); } 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 ); }