windows-nt/Source/XPSP1/NT/base/remoteboot/rbsetup/server/main.cpp
2020-09-26 16:20:57 +08:00

685 lines
18 KiB
C++

/****************************************************************************
Copyright (c) Microsoft Corporation 1997-1999
All rights reserved
***************************************************************************/
#include "pch.h"
#include "dialogs.h"
#include "check.h"
#include "setup.h"
#include "automate.h"
DEFINE_MODULE("Main");
// Globals
HINSTANCE g_hinstance = NULL;
OPTIONS g_Options;
// Command line flags
#define OPTION_UNKNOWN 0x00
#define OPTION_VERSIONINGOVERRIDE 0x01
#define OPTION_DEBUG 0x02
#define OPTION_FUNC 0x03
#define OPTION_CHECK 0x04
#define OPTION_ADD 0x05
#define OPTION_UPGRADE 0x06
#define OPTION_AUTOMATED 0x08
// Constants
#define NUMBER_OF_PAGES 15
//
// Adds a page to the dialog.
//
void
AddPage(
LPPROPSHEETHEADER ppsh,
UINT id,
DLGPROC pfn,
UINT idTitle,
UINT idSubtitle )
{
PROPSHEETPAGE psp;
TCHAR szTitle[ SMALL_BUFFER_SIZE ];
TCHAR szSubTitle[ SMALL_BUFFER_SIZE ];
ZeroMemory( &psp, sizeof(psp) );
psp.dwSize = sizeof(psp);
psp.dwFlags = PSP_DEFAULT | PSP_USETITLE;
if ( id == IDD_WELCOME || id == IDD_WELCOME_ADD || id == IDD_WELCOME_CHECK )
{
psp.dwFlags |= PSP_HIDEHEADER;
}
else
{
psp.dwFlags |= PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
if ( idTitle )
{
DWORD dw;
dw = LoadString( g_hinstance, idTitle, szTitle, ARRAYSIZE(szTitle) );
Assert( dw );
psp.pszHeaderTitle = szTitle;
}
else
{
psp.pszHeaderTitle = NULL;
}
if ( idSubtitle )
{
DWORD dw;
dw = LoadString( g_hinstance, idSubtitle , szSubTitle, ARRAYSIZE(szSubTitle) );
Assert( dw );
psp.pszHeaderSubTitle = szSubTitle;
}
else
{
psp.pszHeaderSubTitle = NULL;
}
}
psp.pszTitle = g_Options.fCheckServer
? MAKEINTRESOURCE( IDS_CHECK_SERVER_TITLE)
: MAKEINTRESOURCE( IDS_APPNAME );
psp.hInstance = ppsh->hInstance;
psp.pszTemplate = MAKEINTRESOURCE(id);
psp.pfnDlgProc = pfn;
ppsh->phpage[ ppsh->nPages ] = CreatePropertySheetPage( &psp );
if ( ppsh->phpage[ ppsh->nPages ] )
ppsh->nPages++;
}
//
// Creates the UI pages and kicks off the property sheet.
//
HRESULT
WizardPages( )
{
TraceFunc( "WizardPages( )\n" );
HRESULT hr = S_OK;
HPROPSHEETPAGE rPages[ NUMBER_OF_PAGES ];
PROPSHEETHEADER pshead;
ZeroMemory( &pshead, sizeof(pshead) );
pshead.dwSize = sizeof(pshead);
pshead.dwFlags = PSH_WIZARD97 | PSH_PROPTITLE | PSH_USEHICON
| PSH_WATERMARK | PSH_HEADER;
pshead.hInstance = g_hinstance;
pshead.pszCaption = g_Options.fCheckServer
? MAKEINTRESOURCE( IDS_CHECK_SERVER_TITLE)
: MAKEINTRESOURCE( IDS_APPNAME );
pshead.phpage = rPages;
pshead.pszbmWatermark = MAKEINTRESOURCE( IDB_TITLEPAGE );
pshead.pszbmHeader = MAKEINTRESOURCE( IDB_HEADER );
AddPage( &pshead, IDD_WELCOME, (DLGPROC) WelcomeDlgProc, 0, 0 );
AddPage( &pshead, IDD_WELCOME_ADD, (DLGPROC) AddWelcomeDlgProc, 0, 0 );
AddPage( &pshead, IDD_WELCOME_CHECK, (DLGPROC) CheckWelcomeDlgProc, 0, 0 );
AddPage( &pshead, IDD_EXAMINING_SERVER, (DLGPROC) ExamineServerDlgProc, IDS_EXAMINING_TITLE, IDS_EXAMINING_SUBTITLE );
AddPage( &pshead, IDD_INTELLIMIRRORROOT,(DLGPROC) IntelliMirrorRootDlgProc, IDS_INTELLIMIRRORROOT_TITLE, IDS_INTELLIMIRRORROOT_SUBTITLE );
AddPage( &pshead, IDD_SCP, (DLGPROC) SCPDlgProc, IDS_SCP_TITLE, IDS_SCP_SUBTITLE );
AddPage( &pshead, IDD_OPTIONS, (DLGPROC) OptionsDlgProc, IDS_OPTIONS_TITLE, IDS_OPTIONS_SUBTITLE );
AddPage( &pshead, IDD_IMAGESOURCE, (DLGPROC) ImageSourceDlgProc, IDS_IMAGESOURCE_TITLE, IDS_IMAGESOURCE_SUBTITLE );
AddPage( &pshead, IDD_LANGUAGE, (DLGPROC) LanguageDlgProc, IDS_LANGUAGE_TITLE, IDS_LANGUAGE_SUBTITLE );
AddPage( &pshead, IDD_OSDIRECTORY, (DLGPROC) OSDirectoryDlgProc, IDS_OSDIRECTORY_TITLE, IDS_OSDIRECTORY_SUBTITLE );
AddPage( &pshead, IDD_DEFAULTSIF, (DLGPROC) DefaultSIFDlgProc, IDS_DEFAULTSIF_TITLE, IDS_DEFAULTSIF_SUBTITLE );
AddPage( &pshead, IDD_SCREENS, (DLGPROC) ScreensDlgProc, IDS_SCREENS_TITLE, IDS_SCREENS_SUBTITLE );
AddPage( &pshead, IDD_SUMMARY, (DLGPROC) SummaryDlgProc, IDS_SUMMARY_TITLE, IDS_SUMMARY_SUBTITLE );
AddPage( &pshead, IDD_WARNING, (DLGPROC) WarningDlgProc, IDS_WARNING_TITLE, IDS_WARNING_SUBTITLE );
AddPage( &pshead, IDD_SERVEROK, (DLGPROC) ServerOKDlgProc, IDS_SERVEROK_TITLE, IDS_SERVEROK_SUBTITLE );
PropertySheet( &pshead );
if ( g_Options.fAbort )
{
hr = S_FALSE;
goto Error;
}
if ( g_Options.fError )
{
hr = E_FAIL;
goto Error;
}
Error:
RETURN(hr);
}
//
// Initializes g_Options.
//
HRESULT
InitializeOptions( void )
{
DWORD dw;
LRESULT lResult;
HKEY hkeySetup;
TraceFunc( "InitializeOptions( )\n" );
//
// Initialize all variable to NULL strings or FALSE
//
memset( &g_Options, 0, sizeof(OPTIONS) );
//
// Load default strings
//
dw = LoadString( g_hinstance, IDS_DEFAULTSETUP,
g_Options.szInstallationName, ARRAYSIZE(g_Options.szInstallationName) );
Assert( dw );
dw = LoadString( g_hinstance, IDS_UNKNOWN, g_Options.szLanguage, ARRAYSIZE(g_Options.szLanguage) );
Assert( dw );
wcscpy( g_Options.szSourcePath, L"C:\\" );
for( ; g_Options.szSourcePath[0] <= L'Z'; g_Options.szSourcePath[0]++ )
{
UINT uDriveType;
uDriveType = GetDriveType( g_Options.szSourcePath );
if ( DRIVE_CDROM == uDriveType )
break;
}
if ( g_Options.szSourcePath[0] > L'Z' ) {
g_Options.szSourcePath[0] = L'\0';
}
g_Options.hinf = INVALID_HANDLE_VALUE;
g_Options.fFirstTime = TRUE;
lResult = RegOpenKey( HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Setup", &hkeySetup );
if ( lResult == ERROR_SUCCESS )
{
DWORD dwValue;
DWORD cbValue;
// Find out if we should authorize DCHP
cbValue = sizeof(dwValue);
lResult = RegQueryValueEx( hkeySetup, L"RemInst_DontAuthorizeDHCP", NULL, NULL, (LPBYTE)&dwValue, &cbValue );
if ( lResult == ERROR_SUCCESS ) {
g_Options.fDontAuthorizeDhcp = dwValue;
}
RegCloseKey( hkeySetup );
}
if (SUCCEEDED(GetSetRanFlag(TRUE, FALSE))) {
g_Options.fFirstTime = FALSE;
} else {
g_Options.fFirstTime = TRUE;
}
HRETURN(S_OK);
}
//
// IsWhiteSpace()
//
BOOL
IsWhiteSpace( wchar_t ch )
{
if ( ch <=32 )
return TRUE;
return FALSE;
}
//
// CheckWhichOption()
DWORD
CheckWhichOption(
LPWSTR pszOption )
{
DWORD dw;
WCHAR szOptionTag[ 64 ];
if ( StrCmpNI( pszOption, L"xyzzy", 6 ) == 0 )
return OPTION_VERSIONINGOVERRIDE;
if ( StrCmpNI( pszOption, L"debug", 5 ) == 0 )
return OPTION_DEBUG;
if ( StrCmpNI( pszOption, L"func", 4 ) == 0 )
return OPTION_FUNC;
if ( StrCmpNI( pszOption, L"add", 3 ) == 0 )
return OPTION_ADD;
if ( StrCmpNI( pszOption, L"check", 5 ) == 0 )
return OPTION_CHECK;
if ( StrCmpNI( pszOption, L"upgrade", 7 ) == 0 )
return OPTION_UPGRADE;
if ( StrCmpNI( pszOption, L"auto", 4 ) == 0 )
return OPTION_AUTOMATED;
// Internationalized words
dw = LoadString( g_hinstance, IDS_ADD, szOptionTag, ARRAYSIZE(szOptionTag) );
Assert( dw );
if ( StrCmpNIW( pszOption, szOptionTag, lstrlen(szOptionTag) == 0 ) )
return OPTION_ADD;
dw = LoadString( g_hinstance, IDS_CHECK, szOptionTag, ARRAYSIZE(szOptionTag) );
Assert( dw );
if ( StrCmpNI( pszOption, szOptionTag, lstrlen(szOptionTag) == 0 ) )
return OPTION_CHECK;
return OPTION_UNKNOWN;
}
//
// ParseCommandLine()
// Returns false if the call required useage to be printed else true
//
BOOL
ParseCommandLine( LPWSTR lpCmdLine )
{
LPWSTR psz = lpCmdLine;
while (*psz)
{
if ( *psz == L'/' || *psz == L'-' )
{
LPWSTR pszStartOption = ++psz;
while (*psz && !IsWhiteSpace( *psz ) )
psz++;
*psz = L'\0'; // terminate
switch ( CheckWhichOption( pszStartOption ) )
{
case OPTION_VERSIONINGOVERRIDE:
g_Options.fServerCompatible = TRUE;
break;
#ifdef DEBUG
case OPTION_DEBUG:
g_dwTraceFlags |= TF_HRESULTS;
break;
case OPTION_FUNC:
g_dwTraceFlags |= TF_FUNC;
break;
#endif
case OPTION_ADD:
g_Options.fAddOption = TRUE;
break;
case OPTION_AUTOMATED:
{
LPWSTR pszScriptFilename;
UINT ErrLine;
g_Options.fAutomated = TRUE;
WCHAR UnattendedFile[MAX_PATH];
LPWSTR p;
//
// get the script name
//
//
// first eat all the whitespace
//
psz++;
while(*psz && IsWhiteSpace( *psz )) {
psz++;
}
//
// now get the filename, which may or may not be quoted
//
if (*psz == L'\"') {
pszScriptFilename = ++psz;
while (*psz && ( L'\"' != *psz ) ) {
psz++;
}
} else {
pszScriptFilename = psz;
while (*psz && !IsWhiteSpace( *psz ) ) {
psz++;
}
}
//
// NULL terminate the filename and try to open the file as
// an INF file
//
*psz = L'\0';
g_Options.hinfAutomated = INVALID_HANDLE_VALUE;
if( GetFullPathName( pszScriptFilename,
MAX_PATH,
UnattendedFile,
&p ) ) {
g_Options.hinfAutomated = SetupOpenInfFileW( UnattendedFile, NULL, INF_STYLE_WIN4, &ErrLine );
}
if ( g_Options.hinfAutomated == INVALID_HANDLE_VALUE ) {
ErrorBox( NULL, NULL );
g_Options.fError = TRUE;
}
}
break;
case OPTION_CHECK:
g_Options.fCheckServer = TRUE;
break;
case OPTION_UPGRADE:
g_Options.fUpgrade = TRUE;
break;
case OPTION_UNKNOWN :
default :
WCHAR szCaption[ SMALL_BUFFER_SIZE ];
WCHAR szUsage[ SMALL_BUFFER_SIZE * 2 ];
DWORD dw;
dw = LoadStringW( g_hinstance, IDS_APPNAME, szCaption, ARRAYSIZE( szCaption ) );
Assert( dw );
dw = LoadStringW( g_hinstance, IDS_USAGE, szUsage, ARRAYSIZE( szUsage ));
Assert( dw );
MessageBoxW( NULL, szUsage, szCaption, MB_OK );
return FALSE;
}
}
psz++;
}
return TRUE;
}
//
// DoSetup( )
//
HRESULT
DoSetup( )
{
HRESULT hr = S_OK;
INT iReturn;
//
// Setup dialog
//
iReturn = (INT)DialogBox( g_hinstance,
MAKEINTRESOURCE(IDD_TASKS),
NULL,
SetupDlgProc );
return hr;
}
//
// CheckForReboot( )
//
void
CheckForReboot( )
{
if ( !g_Options.fSISServiceInstalled )
{
MessageBoxFromStrings( NULL,
IDS_MUST_REBOOT_TITLE,
IDS_MUST_REBOOT_MESSAGE,
MB_OK | MB_ICONEXCLAMATION );
SetupPromptReboot( NULL, NULL, FALSE );
}
}
//
// RunningOnNTServer( )
//
BOOL
RunningOnNTServer(void)
{
TraceFunc( "RunningOnNtServer()\n" );
HKEY hkey;
LONG lResult;
WCHAR szProductType[50] = { 0 };
DWORD dwType;
DWORD dwSize = ARRAYSIZE(szProductType);
BOOL fReturn = FALSE; // assume that we are not on NTServer.
// Query the registry for the product type.
lResult = RegOpenKeyEx ( HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Control\\ProductOptions",
0,
KEY_READ,
&hkey);
Assert( lResult == ERROR_SUCCESS );
if ( lResult != ERROR_SUCCESS )
goto Error;
lResult = RegQueryValueEx ( hkey,
L"ProductType",
NULL,
&dwType,
(LPBYTE) szProductType,
&dwSize);
Assert( lResult == ERROR_SUCCESS );
RegCloseKey (hkey);
if (lResult != ERROR_SUCCESS)
goto Error;
if ( StrCmpI( szProductType, L"ServerNT" ) == 0 )
{
fReturn = TRUE; // yep. NT Server alright.
}
if ( StrCmpI( szProductType, L"LanmanNT" ) == 0 )
{
fReturn = TRUE; // yep. NT Server alright.
}
Error:
RETURN(fReturn);
}
//
// WinMain()
//
int APIENTRY
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
TraceFunc( "WinMain( ... )\n" );
HANDLE hMutex;
HRESULT hr = E_FAIL;
WSADATA wsdata;
LPWSTR pszCommandLine = GetCommandLine( );
int iReturn;
g_hinstance = hInstance;
INITIALIZE_TRACE_MEMORY_PROCESS;
// allow only one instance running at a time
hMutex = CreateMutex( NULL, TRUE, L"RemoteBootSetup.Mutext");
if (GetLastError() == ERROR_ALREADY_EXISTS)
{
MessageBoxFromStrings( NULL,
IDS_ALREADY_RUNNING_TITLE,
IDS_ALREADY_RUNNING_MESSAGE,
MB_OK | MB_ICONSTOP );
goto Cleanup;
}
CoInitialize(NULL);
WSAStartup( 0x02, &wsdata );
if( !pSetupIsUserAdmin()
|| !pSetupDoesUserHavePrivilege(SE_SHUTDOWN_NAME)
|| !pSetupDoesUserHavePrivilege(SE_BACKUP_NAME)
|| !pSetupDoesUserHavePrivilege(SE_RESTORE_NAME)
|| !pSetupDoesUserHavePrivilege(SE_SYSTEM_ENVIRONMENT_NAME)) {
MessageBoxFromStrings( NULL, IDS_MUST_BE_ADMINISTRATOR_CAPTION, IDS_MUST_BE_ADMINISTRATOR_TEXT, MB_OK );
goto Cleanup;
}
if ( !RunningOnNTServer( ) )
{
MessageBoxFromStrings( NULL, IDS_NOT_RUNNING_ON_NT_SERVER_CAPTION, IDS_NOT_RUNNING_ON_NT_SERVER_TEXT, MB_OK );
goto Cleanup;
}
hr = InitializeOptions( );
if ( FAILED(hr) )
goto Cleanup;
if( !ParseCommandLine( pszCommandLine )) {
goto Cleanup;
}
// Change SetupAPI to Non-backup mode.
// also set a flag that makes it fail all signature checks.
// since we're subject to non-driver signing policy and that
// is set to ignore by default, this means that every copy
// operation will generate a signature warning in setupapi.log
// ...but the memory footprint and speed of risetup process
// will both go down significantly since we won't drag the
// crypto libraries into the process.
//
pSetupSetGlobalFlags( pSetupGetGlobalFlags( ) | PSPGF_NO_BACKUP | PSPGF_AUTOFAIL_VERIFIES );
//
// Go figure out a default for what processor we're
// building an image for.
//
GetProcessorType();
if ( !g_Options.fUpgrade && !g_Options.fAutomated )
{
hr = WizardPages( );
if ( hr != S_OK ) {
goto Cleanup;
}
hr = DoSetup( );
if ( hr != S_OK ) {
goto Cleanup;
}
CheckForReboot( );
}
else if ( g_Options.fAutomated )
{
if ( g_Options.fError ) {
goto Cleanup;
}
hr = GetAutomatedOptions( );
if ( hr != S_OK ) {
goto Cleanup;
}
hr = FindImageSource( NULL );
if ( hr != S_OK ) {
MessageBoxFromStrings( NULL, IDS_FILE_NOT_FOUND_TITLE, IDS_FILE_NOT_FOUND_TEXT, MB_OK );
goto Cleanup;
}
hr = CheckImageSource( NULL );
if ( hr != S_OK ) {
goto Cleanup;
}
hr = CheckInstallation( );
if ( FAILED(hr) ) {
goto Cleanup;
}
hr = DoSetup( );
if ( hr != S_OK ) {
goto Cleanup;
}
}
else if ( g_Options.fUpgrade )
{
hr = UpdateRemoteInstallTree( );
}
else
{
AssertMsg( 0, "How did I get here?" );
}
Cleanup:
CoUninitialize();
if ( hMutex ) {
CloseHandle( hMutex );
}
if ( g_Options.hinf != INVALID_HANDLE_VALUE ) {
SetupCloseInfFile( g_Options.hinf );
}
UNINITIALIZE_TRACE_MEMORY;
RETURN(hr);
}
// stolen from the CRT, used to shrink our code
int _stdcall ModuleEntry(void)
{
int i;
STARTUPINFOA si;
LPSTR pszCmdLine = GetCommandLineA();
if ( *pszCmdLine == '\"' )
{
/*
* Scan, and skip over, subsequent characters until
* another double-quote or a null is encountered.
*/
while ( *++pszCmdLine && (*pszCmdLine != '\"') );
/*
* If we stopped on a double-quote (usual case), skip
* over it.
*/
if ( *pszCmdLine == '\"' )
pszCmdLine++;
}
else
{
while (*pszCmdLine > ' ')
pszCmdLine++;
}
/*
* Skip past any white space preceeding the second token.
*/
while (*pszCmdLine && (*pszCmdLine <= ' '))
{
pszCmdLine++;
}
si.dwFlags = 0;
GetStartupInfoA(&si);
i = WinMain(GetModuleHandle(NULL), NULL, pszCmdLine,
si.dwFlags & STARTF_USESHOWWINDOW ? si.wShowWindow : SW_SHOWDEFAULT);
ExitProcess(i);
return i; // We never come here.
}