337 lines
6.8 KiB
C
337 lines
6.8 KiB
C
/*++
|
||
|
||
Copyright (c) 1991-1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
CmdLine.c
|
||
|
||
Abstract:
|
||
|
||
This module contains support routines for processing server service
|
||
command-line arguments.
|
||
|
||
Author:
|
||
|
||
David Treadwell (davidtr) 10-Mar-1991
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "srvsvcp.h"
|
||
|
||
#include <netlibnt.h>
|
||
#include <tstr.h>
|
||
|
||
|
||
//
|
||
// Forward declarations.
|
||
//
|
||
|
||
PFIELD_DESCRIPTOR
|
||
FindSwitchMatch (
|
||
IN LPWCH Argument,
|
||
IN BOOLEAN Starting
|
||
);
|
||
|
||
NET_API_STATUS
|
||
SetField (
|
||
IN PFIELD_DESCRIPTOR SwitchDesc,
|
||
IN LPWCH Argument
|
||
);
|
||
|
||
|
||
NET_API_STATUS
|
||
SsParseCommandLine (
|
||
IN DWORD argc,
|
||
IN LPWSTR argv[],
|
||
IN BOOLEAN Starting
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets server parameters using a command line. It parses
|
||
the command line, changing one parameter at a time as it comes up.
|
||
|
||
Arguments:
|
||
|
||
argc - the number of command-line arguments.
|
||
|
||
argv - an arrray of pointers to the arguments.
|
||
|
||
Starting - TRUE if the command line is from server startup, i.e.
|
||
net start server. This is needed because some fields may only
|
||
be set at startup.
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - 0 or reason for failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
NET_API_STATUS error;
|
||
DWORD i;
|
||
PFIELD_DESCRIPTOR switchDesc;
|
||
PSERVER_SERVICE_DATA saveSsData;
|
||
|
||
//
|
||
// Save the service data in case there is an invalid param and we have
|
||
// to back out.
|
||
//
|
||
|
||
saveSsData = MIDL_user_allocate( sizeof(SERVER_SERVICE_DATA) );
|
||
if ( saveSsData == NULL ) {
|
||
return ERROR_NOT_ENOUGH_MEMORY;
|
||
}
|
||
|
||
RtlCopyMemory( saveSsData, &SsData, sizeof(SERVER_SERVICE_DATA) );
|
||
|
||
//
|
||
// Loop through the command-line arguments, setting as we go.
|
||
//
|
||
|
||
for ( i = 0; i < argc; i++ ) {
|
||
|
||
LPWCH arg;
|
||
|
||
arg = argv[i];
|
||
|
||
//
|
||
// A hack to aid debugging.
|
||
//
|
||
|
||
if ( _wcsnicmp( L"/debug", arg, 6 ) == 0 ) {
|
||
continue;
|
||
}
|
||
|
||
//
|
||
// Try to match the switch against the legal switches.
|
||
//
|
||
|
||
switchDesc = FindSwitchMatch( arg, Starting );
|
||
if ( switchDesc == NULL ) {
|
||
error = ERROR_INVALID_PARAMETER;
|
||
goto err_exit;
|
||
}
|
||
|
||
//
|
||
// Set the value in the field.
|
||
//
|
||
|
||
error = SetField( switchDesc, arg );
|
||
if ( error != NO_ERROR ) {
|
||
IF_DEBUG(INITIALIZATION_ERRORS) {
|
||
SS_PRINT(( "SsParseCommandLine: SetField failed for switch "
|
||
"\"%ws\": %ld\n", arg, error ));
|
||
}
|
||
goto err_exit;
|
||
}
|
||
}
|
||
|
||
error = NO_ERROR;
|
||
goto normal_exit;
|
||
|
||
err_exit:
|
||
|
||
//
|
||
// Restore the original server settings.
|
||
//
|
||
|
||
RtlCopyMemory( &SsData, saveSsData, sizeof(SERVER_SERVICE_DATA) );
|
||
|
||
normal_exit:
|
||
|
||
MIDL_user_free( saveSsData );
|
||
|
||
return error;
|
||
|
||
} // SsParseCommandLine
|
||
|
||
|
||
PFIELD_DESCRIPTOR
|
||
FindSwitchMatch (
|
||
IN LPWCH Argument,
|
||
IN BOOLEAN Starting
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine tries to match a given switch against the possible
|
||
switch values.
|
||
|
||
Arguments:
|
||
|
||
Argument - a pointer to the text argument.
|
||
|
||
Starting - TRUE if the command line is from server startup, i.e.
|
||
net start server. This is needed because some fields may only
|
||
be set at startup.
|
||
|
||
Return Value:
|
||
|
||
A pointer to a FIELD_DESCRIPTOR field from SsServerInfoFields[], or NULL if
|
||
no valid match could be found.
|
||
|
||
--*/
|
||
|
||
{
|
||
SHORT i;
|
||
PFIELD_DESCRIPTOR foundSwitch = NULL;
|
||
ULONG switchLength;
|
||
LPWCH s;
|
||
|
||
//
|
||
// Ignore the leading /.
|
||
//
|
||
|
||
if ( *Argument != '/' ) {
|
||
SS_PRINT(( "Invalid switch: %ws\n", Argument ));
|
||
return NULL;
|
||
}
|
||
|
||
Argument++;
|
||
|
||
//
|
||
// Find out how long the passed-in switch is.
|
||
//
|
||
|
||
for ( s = Argument, switchLength = 0;
|
||
*s != ':' && *s != '\0';
|
||
s++, switchLength++ );
|
||
|
||
//
|
||
// Compare at most that many bytes. We allow a minimal matching--
|
||
// as long as the specified switch uniquely identifies a switch, then
|
||
// is is usable.
|
||
//
|
||
|
||
for ( i = 0; SsServerInfoFields[i].FieldName != NULL; i++ ) {
|
||
|
||
if ( _wcsnicmp( Argument, SsServerInfoFields[i].FieldName, switchLength ) == 0 ) {
|
||
|
||
if ( SsServerInfoFields[i].Settable == NOT_SETTABLE ||
|
||
( !Starting && SsServerInfoFields[i].Settable == SET_ON_STARTUP ) ) {
|
||
|
||
SS_PRINT(( "Cannot set field %ws at this time.\n",
|
||
SsServerInfoFields[i].FieldName ));
|
||
|
||
return NULL;
|
||
}
|
||
|
||
if ( foundSwitch != NULL ) {
|
||
SS_PRINT(( "Ambiguous switch name: %ws (matches %ws and %ws)\n",
|
||
Argument-1, foundSwitch->FieldName,
|
||
SsServerInfoFields[i].FieldName ));
|
||
return NULL;
|
||
}
|
||
|
||
foundSwitch = &SsServerInfoFields[i];
|
||
}
|
||
}
|
||
|
||
if ( foundSwitch == NULL ) {
|
||
SS_PRINT(( "Unknown argument: %ws\n", Argument-1 ));
|
||
}
|
||
|
||
return foundSwitch;
|
||
|
||
} // FindSwitchMatch
|
||
|
||
|
||
NET_API_STATUS
|
||
SetField (
|
||
IN PFIELD_DESCRIPTOR Field,
|
||
IN LPWCH Argument
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets the value of a server info parameter.
|
||
|
||
Arguments:
|
||
|
||
Field - a pointer to the appropriate FIELD_DESCRIPTOR field
|
||
from SsServerInfoFields[].
|
||
|
||
Argument - a pointer to the text argument. It should be of the form
|
||
"/switch:value".
|
||
|
||
Return Value:
|
||
|
||
NET_API_STATUS - NO_ERROR or reason for failure.
|
||
|
||
--*/
|
||
|
||
{
|
||
LPWCH valueStart;
|
||
DWORD_PTR value;
|
||
|
||
//
|
||
// Find out where the ':' is in the argument.
|
||
//
|
||
|
||
valueStart = wcschr( Argument, L':' );
|
||
|
||
if ( valueStart == NULL && Field->FieldType != BOOLEAN_FIELD ) {
|
||
SS_PRINT(( "Invalid argument: %s\n", Argument ));
|
||
}
|
||
|
||
switch ( Field->FieldType ) {
|
||
|
||
case BOOLEAN_FIELD:
|
||
|
||
//
|
||
// If the first character of the value is Y or there is no
|
||
// value specified, set the field to TRUE, otherwise set it
|
||
// to FALSE.
|
||
//
|
||
|
||
if ( valueStart == NULL || *(valueStart+1) == L'y' ||
|
||
*(valueStart+1) == L'Y' ) {
|
||
value = TRUE;
|
||
} else if ( *(valueStart+1) == L'n' || *(valueStart+1) == L'N' ) {
|
||
value = FALSE;
|
||
} else {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
break;
|
||
|
||
case DWORD_FIELD:
|
||
{
|
||
NTSTATUS status;
|
||
UNICODE_STRING unicodeString;
|
||
DWORD intValue;
|
||
|
||
RtlInitUnicodeString( &unicodeString, valueStart + 1 );
|
||
status = RtlUnicodeStringToInteger( &unicodeString, 0, &intValue );
|
||
if ( !NT_SUCCESS(status) ) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
value = intValue;
|
||
|
||
break;
|
||
}
|
||
case LPSTR_FIELD:
|
||
|
||
value = (DWORD_PTR)( valueStart + 1 );
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Call SsSetField to actually set the field.
|
||
//
|
||
|
||
return SsSetField( Field, &value, TRUE, NULL );
|
||
|
||
} // SetField
|
||
|