/*++ 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 #include // // 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