Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

715 lines
23 KiB

/*++
Copyright (c) Microsoft Corporation
Module Name:
Timeout.c
Abstract:
This file implements the parsing of the command line for the arguments and also the
wait functionality.
Author:
EricB
Revision History:
26-Aug-1991 Created by EricB.
10-Mar-1992 Added the _getch() call to flush the hit key.
17-Apr-1992 Added countdown display.
03-Oct-1992 Ported to NT/Win32
23-May-1995 Added Sleep call
14-Jun-2001 localization added by Wipro Technologies
01-Aug-2001 Added /nobreak option by Wipro Technologies
--*/
#include "pch.h"
#include "Timeout.h"
#include "Resource.h"
DWORD _cdecl
wmain(
IN DWORD argc,
IN LPCWSTR argv[]
)
/*++
Routine Description:
This is main entry point to this utility. Different function calls are made
from here to achieve the required functionality.
Arguments:
[in] argc : Number of Command line arguments.
[in] argv : Pointer to Command line arguments.
Return Value:
0 on success
1 on failure.
--*/
{
//local variables
CONSOLE_SCREEN_BUFFER_INFO csbi;
time_t tWait = 0L;
time_t tLast = 0L;
time_t tNow = 0L;
time_t tEnd = 0L;
DWORD dwTimeActuals = 0;
BOOL bNBActuals = 0;
BOOL bUsage = FALSE;
BOOL bResult = FALSE;
BOOL bStatus = FALSE;
WCHAR wszProgressMsg[ MAX_STRING_LENGTH ] = NULL_U_STRING ;
DWORD dwWidth = 0;
WCHAR wszBackup[12] = NULL_U_STRING;
WCHAR wszTimeout[ MAX_RES_STRING] = NULL_U_STRING;
LPWSTR pszStopString = NULL;
COORD coord = {0};
HANDLE hOutput = NULL;
HANDLE hStdIn = NULL;
DWORD dwMode = 0L;
DWORD dwRead = 0L;
INPUT_RECORD InputBuffer[ MAX_NUM_RECS ] = {0};
HRESULT hr = S_OK;
if ( NULL == argv )
{
SetLastError (ERROR_INVALID_PARAMETER );
SaveLastError();
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
return EXIT_FAILURE;
}
// Parse the command line and get the actual values
bResult = ProcessOptions( argc, argv, &bUsage, &dwTimeActuals, wszTimeout , &bNBActuals );
if( FALSE == bResult )
{
// display an error message with respect to the GetReason()
ShowLastErrorEx ( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
ReleaseGlobals();
return( EXIT_FAILURE );
}
// check for invalid syntax
// 1. check for the case c:\>timeout.exe
// 2. check for the case c:\>timeout.exe /nobreak
// 3. check for the case c:\>timeout.exe /? /?
if ( ( ( 0 == dwTimeActuals ) && ( FALSE == bNBActuals ) && ( FALSE == bUsage ) ) ||
( ( 0 == dwTimeActuals ) && ( TRUE == bNBActuals ) ) || ( ( TRUE == bUsage ) && (argc > 2 )) )
{
// display an error message as specified syntax is invalid
ShowMessage ( stderr, GetResString (IDS_INVALID_SYNTAX) );
ReleaseGlobals();
return( EXIT_FAILURE );
}
// Check whether the usage(/?) is specified
if( TRUE == bUsage )
{
// Display the help/usage for the tool
DisplayUsage();
ReleaseGlobals();
return( EXIT_SUCCESS );
}
// get the value for timeout (/T)
tWait = ( time_t ) wcstol(wszTimeout,&pszStopString,BASE_TEN);
//check whether any non-numeric value specified for timeout value
// if so, display appropriate error message as invalid timeout value specified.
// Also, check for overflow and underflow conds
if( ((NULL != pszStopString) && ( StringLength( pszStopString, 0 ) != 0 )) ||
(errno == ERANGE) ||
( tWait < MIN_TIME_VAL ) || ( tWait >= MAX_TIME_VAL ) )
{
ShowMessage ( stderr, GetResString (IDS_ERROR_TIME_VALUE) );
ReleaseGlobals();
return( EXIT_FAILURE );
}
// Get the time elapsed in secs since midnight (00:00:00), January 1, 1970
bResult = GetTimeInSecs( &tNow );
if( FALSE == bResult )
{
ReleaseGlobals();
// could not get the time so exit...
return( EXIT_FAILURE );
}
// check for /nobreak option is specified
if ( TRUE == bNBActuals )
{
// set console handler to capture the keys like CTRL+BREAK or CRTL+C
bStatus = SetConsoleCtrlHandler( &HandlerRoutine, TRUE );
if ( FALSE == bStatus )
{
// Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
}
hStdIn = GetStdHandle( STD_INPUT_HANDLE );
// check for the input redirection on console and telnet session
if( ( hStdIn != (HANDLE)0x0000000F ) &&
( hStdIn != (HANDLE)0x00000003 ) &&
( hStdIn != INVALID_HANDLE_VALUE ) )
{
ShowMessage( stderr, GetResString (IDS_INVALID_INPUT_REDIRECT) );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return EXIT_FAILURE;
}
#ifdef WIN32
// Set input mode so that a single key hit can be detected.
if ( GetConsoleMode( hStdIn, &dwMode ) == FALSE )
{
// Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
// Turn off the following modes:
dwMode &= ~( ENABLE_LINE_INPUT | // Don't wait for CR.
ENABLE_ECHO_INPUT | // Don't echo input.
ENABLE_WINDOW_INPUT | // Don't record window events.
ENABLE_MOUSE_INPUT // Don't record mouse events.
);
// set the input mode of a console's input buffer
if ( SetConsoleMode( hStdIn, dwMode ) == FALSE )
{
// Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
// retrieve number of unread input records in the console's input buffer.
if( GetNumberOfConsoleInputEvents( hStdIn, &dwRead ) == FALSE )
{
// Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
// clear the console input buffer
if ( FALSE == FlushConsoleInputBuffer (hStdIn))
{
// Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
#endif
// check whether /T value is -1. If so, need to wait indefinitely for a key press..
if( -1 == tWait )
{
// check whether /nobreak is specified
if ( FALSE == bNBActuals )
{
// Wait until a key hit.
ShowMessage( stdout, GetResString( IDS_WAIT_MSG ) );
}
else // /nobreak option is not specified
{
// Wait until a CTRL+C key hit.
ShowMessage( stdout, GetResString( IDS_NO_BREAK_MSG ) );
}
// Ensure infinite do loop.
tEnd = tNow + 1;
}
else
{
// Wait with a timeout period.
// Compute end time.
tEnd = tNow + tWait;
// Figure the time display dwWidth.
// Need to decrement the time factor (/T) specified at a specified
// location. To get the position where it needs to be decremented,
// get the width of the /T value
if (tWait < 10)
{
// if the /T value is less than 10 then set the width as 1
dwWidth = 1;
}
else
{
if (tWait < 100)
{
// if the /T value is less than 100 then set width as 2
dwWidth = 2;
}
else
{
if (tWait < 1000)
{
// if the /T value is less than 1000 then set width as 3
dwWidth = 3;
}
else
{
if (tWait < 10000)
{
// if the /T value is less than 10000 then set width as 4
dwWidth = 4;
}
else
{
// if the /T value is less than 100000 then set width as 5
dwWidth = 5;
}
}
}
}
if ( FALSE == Replicate ( wszBackup, ONE_BACK_SPACE, dwWidth, SIZE_OF_ARRAY(wszBackup)))
{
// Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_INTERNAL );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
//
// Initialize the console screen buffer structure to zero's
// and then get the console handle and screen buffer information
//
SecureZeroMemory( wszProgressMsg, sizeof( WCHAR ) * MAX_STRING_LENGTH );
// display the message as ..Waiting for...
//ShowMessage ( stdout, GetResString (IDS_WAIT_MSG_TIME1 ) );
//format the message as .. n seconds...for wait time
//_snwprintf( wszProgressMsg, SIZE_OF_ARRAY(wszProgressMsg), WAIT_TIME , dwWidth, tWait );
hr = StringCchPrintf( wszProgressMsg, SIZE_OF_ARRAY(wszProgressMsg), GetResString(IDS_WAIT_MSG_TIME1) , dwWidth, tWait );
if ( FAILED (hr))
{
SetLastError (HRESULT_CODE (hr));
SaveLastError();
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
// print the message.
ShowMessage ( stdout, wszProgressMsg );
//
// Initialize the console screen buffer structure to zero's
// and then get the console handle and screen buffer information
//
SecureZeroMemory( &csbi, sizeof( CONSOLE_SCREEN_BUFFER_INFO ) );
hOutput = GetStdHandle( STD_OUTPUT_HANDLE );
if ( NULL != hOutput )
{
// Get the info of screen buffer.
GetConsoleScreenBufferInfo( hOutput, &csbi );
}
// set the cursor position
coord.X = csbi.dwCursorPosition.X;
coord.Y = csbi.dwCursorPosition.Y;
// check whether /nobreak is specified or not
if ( FALSE == bNBActuals )
{
// display the message as ...press a key to continue ...
ShowMessage ( stdout, GetResString (IDS_WAIT_MSG_TIME2) );
}
else
{
// display the message as ...press CTRL+C to quit...
ShowMessage ( stdout, GetResString (IDS_NB_MSG_TIME) );
}
}
do
{
// Break out if a key is pressed.
#ifdef WIN32
//reads data from the specified console input buffer without removing it from the buffer.
if( PeekConsoleInput( hStdIn, InputBuffer, MAX_NUM_RECS, &dwRead ) == FALSE )
{
// Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
if (dwRead > 0)
{
//reads data from a console input buffer and removes it from the buffer
if( ReadConsoleInput(hStdIn, InputBuffer, MAX_NUM_RECS, &dwRead ) == FALSE )
{
// Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
// Filter the input so that ctrl-c can be generated and passed on.
// Also, ignore alt key presses and window focus events.
if( (FOCUS_EVENT != InputBuffer[0].EventType)
&& (VK_CONTROL != InputBuffer[0].Event.KeyEvent.wVirtualKeyCode)
&& (VK_CONTROL != InputBuffer[0].Event.KeyEvent.wVirtualScanCode)
&& (MOUSE_MOVED != InputBuffer[0].Event.MouseEvent.dwEventFlags)
&& (MOUSE_WHEELED != InputBuffer[0].Event.MouseEvent.dwEventFlags)
&& (FALSE != InputBuffer[0].Event.KeyEvent.bKeyDown)
&& (VK_MENU != InputBuffer[0].Event.KeyEvent.wVirtualKeyCode)
&& ( FALSE == bNBActuals ) )
{
// exit from the loop
break;
}
}
#else
//Checks the console for keyboard input.
if( ( _kbhit() ) && ( FALSE == bNBActuals ) )
{
// get characters from the console without echo
_getch();
// exit from the loop
break;
}
#endif
// check if /T value is other than -1
if( -1 != tWait )
{
// Update the time and time value display.
tLast = tNow;
// call the function GetTimeInSecs to get the current time in seconds
bResult = GetTimeInSecs( &tNow );
if( FALSE == bResult )
{
// Format an error message accroding to GetLastError() return by API.
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
// could not get the time so exit...
return( EXIT_FAILURE );
}
// check if tLast value is same as tNow.. if not, display the
// message with tEnd-tNow as a wait value
if (tLast != tNow)
{
// Print the message.
SecureZeroMemory( wszProgressMsg, sizeof( WCHAR ) * MAX_STRING_LENGTH );
// fromat the message
//_snwprintf( wszProgressMsg, SIZE_OF_ARRAY(wszProgressMsg), STRING_FORMAT2 , wszBackup, dwWidth, tEnd - tNow );
hr = StringCchPrintf( wszProgressMsg, SIZE_OF_ARRAY(wszProgressMsg), STRING_FORMAT2 , wszBackup, dwWidth, tEnd - tNow );
if ( FAILED (hr))
{
SetLastError (HRESULT_CODE (hr));
SaveLastError();
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
return( EXIT_FAILURE );
}
// set the cursor position
SetConsoleCursorPosition( hOutput, coord );
// display the message as ..tEnd - tNow seconds.. at the current cursor location
ShowMessage ( stdout, wszProgressMsg );
}
}
#ifdef WIN32
// Sleep for sometime...
Sleep( 100 );
#endif
}while( tNow < tEnd ); //check till tNow is less than tEnd value
ShowMessage ( stdout, L"\n" );
// release global variables
ReleaseGlobals();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
// return 0
return( EXIT_SUCCESS );
}
BOOL
GetTimeInSecs(
OUT time_t *ptTime
)
/*++
Routine Description
This function calculates the time elapsed in secs since
midnight (00:00:00), January 1, 1970
Arguments:
[out] time_t ptTime : variable to hold the time in secs
Return Value
TRUE on success
FALSE on failure
--*/
{
#ifdef YANK
//local variables
SYSTEMTIME st = {0};
FILETIME ft = {0};
// check for NULL
if ( NULL == ptTime )
{
SetLastError (ERROR_INVALID_PARAMETER );
SaveLastError();
ShowLastErrorEx( stderr, SLE_TYPE_ERROR | SLE_INTERNAL );
return FALSE;
}
// get the system time
GetSystemTime( &st );
// convert system time to file time
if( SystemTimeToFileTime( &st, &ft ) == FALSE )
{
// Format an error message accroding to GetLastError() return by API.
ShowLastErrorEx( stderr, SLE_TYPE_ERROR| SLE_SYSTEM );
return( FALSE );
}
// need to check for LowDateTime rollover...
*ptTime = ft.dwLowDateTime / LOW_DATE_TIME_ROLL_OVER;
#else
// This function returns the time elapsed in secs since midnight (00:00:00), January 1, 1970
time( ptTime );
#endif
// return 0
return( TRUE );
}
VOID
DisplayUsage(
VOID
)
/*++
Routine Description
This function displays the usage of this utility
Arguments:
NONE
Return Value
NONE
--*/
{
// local variable
DWORD dwIndex = 0;
// Displaying main usage
for( dwIndex = IDS_HELP_START; dwIndex <= IDS_HELP_END; dwIndex++ )
{
ShowMessage( stdout, GetResString( dwIndex ) );
}
return;
}
BOOL ProcessOptions(
IN DWORD argc,
IN LPCWSTR argv[],
OUT BOOL *pbUsage,
OUT DWORD *pwTimeActuals,
OUT LPWSTR wszTimeout,
OUT BOOL *pbNBActuals
)
/*++
Routine Description
This function processes the command line for the main options
Arguments:
[in] argc : Number of Command line arguments.
[in] argv : Pointer to Command line arguments.
[out] pbUsage : Flag that indicates whether the usage is to be displayed or not.
[out] plTimeoutVal : contains the timeout value specified on the command line
Return Value
TRUE on success
FALSE on failure
--*/
{
// sub-local variables
TCMDPARSER2* pcmdParser = NULL;
TCMDPARSER2 cmdParserOptions[MAX_COMMANDLINE_OPTIONS];
BOOL bReturn = FALSE;
// command line options
const WCHAR szTimeoutOpt[] = L"t";
const WCHAR szNoBreakOpt[] = L"nobreak";
const WCHAR szHelpOpt[] = L"?";
// -? help/usage
pcmdParser = cmdParserOptions + OI_USAGE;
StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
pcmdParser->dwType = CP_TYPE_BOOLEAN;
pcmdParser->pwszOptions = szHelpOpt;
pcmdParser->pwszFriendlyName = NULL;
pcmdParser->pwszValues = NULL;
pcmdParser->dwFlags = CP2_USAGE;
pcmdParser->dwCount = 1;
pcmdParser->dwActuals = 0;
pcmdParser->pValue = pbUsage;
pcmdParser->dwLength = MAX_STRING_LENGTH;
pcmdParser->pFunction = NULL;
pcmdParser->pFunctionData = NULL;
pcmdParser->dwReserved = 0;
pcmdParser->pReserved1 = NULL;
pcmdParser->pReserved2 = NULL;
pcmdParser->pReserved3 = NULL;
// -T <timeout>
pcmdParser = cmdParserOptions + OI_TIME_OUT;
StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
pcmdParser->dwType = CP_TYPE_TEXT;
pcmdParser->pwszOptions = szTimeoutOpt;
pcmdParser->pwszFriendlyName = NULL;
pcmdParser->pwszValues = NULL;
pcmdParser->dwFlags = CP2_DEFAULT|CP2_VALUE_TRIMINPUT|CP2_VALUE_NONULL;
pcmdParser->dwCount = 1;
pcmdParser->dwActuals = 0;
pcmdParser->pValue = wszTimeout;
pcmdParser->dwLength = MAX_STRING_LENGTH;
pcmdParser->pFunction = NULL;
pcmdParser->pFunctionData = NULL;
pcmdParser->dwReserved = 0;
pcmdParser->pReserved1 = NULL;
pcmdParser->pReserved2 = NULL;
pcmdParser->pReserved3 = NULL;
// -NOBREAK
pcmdParser = cmdParserOptions + OI_NB_OUT;
StringCopyA( pcmdParser->szSignature, "PARSER2\0", 8 );
pcmdParser->dwType = CP_TYPE_BOOLEAN;
pcmdParser->pwszOptions = szNoBreakOpt;
pcmdParser->pwszFriendlyName = NULL;
pcmdParser->pwszValues = NULL;
pcmdParser->dwFlags = 0;
pcmdParser->dwCount = 1;
pcmdParser->dwActuals = 0;
pcmdParser->pValue = pbNBActuals;
pcmdParser->dwLength = MAX_STRING_LENGTH;
pcmdParser->pFunction = NULL;
pcmdParser->pFunctionData = NULL;
pcmdParser->dwReserved = 0;
pcmdParser->pReserved1 = NULL;
pcmdParser->pReserved2 = NULL;
pcmdParser->pReserved3 = NULL;
//
// do the command line parsing and get the appropriate values
//
bReturn = DoParseParam2( argc, argv, -1, SIZE_OF_ARRAY(cmdParserOptions), cmdParserOptions, 0);
if( FALSE == bReturn) // Invalid commandline
{
// Reason is already set by DoParseParam2
return FALSE;
}
pcmdParser = cmdParserOptions + OI_TIME_OUT;
// get the value for /T value
*pwTimeActuals = pcmdParser->dwActuals;
//return 0
return TRUE;
}
BOOL WINAPI
HandlerRoutine(
IN DWORD dwCtrlType // control signal type
)
/*++
Routine Description:
This function handles the control key CTRL+C.
Arguments:
IN dwCtrlType : Error code value
Return Value:
TRUE on success and FALSE on failure
--*/
{
// check for CTRL+C key
if ( dwCtrlType == CTRL_C_EVENT )
{
ShowMessage ( stdout, L"\n" );
// release globals
ReleaseGlobals ();
// to remove the handle
SetConsoleCtrlHandler( NULL, FALSE );
// exit 0
ExitProcess ( TRUE );
}
// for remaining keys return false
return FALSE;
}