database.c

来自「ReactOS是一些高手根据Windows XP的内核编写出的类XP。内核实现机」· C语言 代码 · 共 1,004 行 · 第 1/2 页

C
1,004
字号

        if (!NT_SUCCESS(Status))
            break;

        DPRINT("Comparing: '%S'  '%wZ'\n", Service->lpServiceName, &DirInfo->Name);

        if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
        {
            DPRINT("Found: '%S'  '%wZ'\n",
                   Service->lpServiceName, &DirInfo->Name);

            /* Mark service as 'running' */
            Service->Status.dwCurrentState = SERVICE_RUNNING;

            /* Mark the service group as 'running' */
            if (Service->lpGroup != NULL)
            {
                Service->lpGroup->ServicesRunning = TRUE;
            }

            break;
        }
    }

    HeapFree(GetProcessHeap(),
             0,
             DirInfo);
    NtClose(DirHandle);

    return STATUS_SUCCESS;
}


VOID
ScmGetBootAndSystemDriverState(VOID)
{
    PLIST_ENTRY ServiceEntry;
    PSERVICE CurrentService;

    DPRINT("ScmGetBootAndSystemDriverState() called\n");

    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
        CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

        if (CurrentService->dwStartType == SERVICE_BOOT_START ||
            CurrentService->dwStartType == SERVICE_SYSTEM_START)
        {
            /* Check driver */
            DPRINT("  Checking service: %S\n", CurrentService->lpServiceName);

            ScmCheckDriver(CurrentService);
        }

        ServiceEntry = ServiceEntry->Flink;
    }

    DPRINT("ScmGetBootAndSystemDriverState() done\n");
}


DWORD
ScmControlService(PSERVICE Service,
                  DWORD dwControl,
                  LPSERVICE_STATUS lpServiceStatus)
{
    PSCM_CONTROL_PACKET ControlPacket;
    DWORD Count;

    DPRINT("ScmControlService() called\n");

    ControlPacket = (SCM_CONTROL_PACKET*) HeapAlloc(GetProcessHeap(),
                                                    HEAP_ZERO_MEMORY,
                                                    sizeof(SCM_CONTROL_PACKET));
    if (ControlPacket == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    ControlPacket->dwControl = dwControl;

    /* Send the start command */
    WriteFile(Service->ControlPipeHandle,
              ControlPacket,
              sizeof(SCM_CONTROL_PACKET),
              &Count,
              NULL);

    /* FIXME: Read the reply */

    /* Release the contol packet */
    HeapFree(GetProcessHeap(),
             0,
             ControlPacket);

    DPRINT("ScmControlService) done\n");

    return ERROR_SUCCESS;
}


static DWORD
ScmSendStartCommand(PSERVICE Service,
                    LPWSTR Arguments)
{
    PSCM_CONTROL_PACKET ControlPacket;
    DWORD TotalLength;
    DWORD ArgsLength = 0;
    DWORD Length;
    PWSTR Ptr;
    DWORD Count;

    DPRINT("ScmSendStartCommand() called\n");

    /* Calculate the total length of the start command line */
    TotalLength = wcslen(Service->lpServiceName) + 1;
    if (Arguments != NULL)
    {
        Ptr = Arguments;
        while (*Ptr)
        {
            Length = wcslen(Ptr) + 1;
            TotalLength += Length;
            ArgsLength += Length;
            Ptr += Length;
            DPRINT("Arg: %S\n", Ptr);
        }
    }
    TotalLength++;
    DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength, TotalLength);

    /* Allocate a control packet */
    ControlPacket = (SCM_CONTROL_PACKET*) HeapAlloc(GetProcessHeap(),
                              HEAP_ZERO_MEMORY,
                              sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
    if (ControlPacket == NULL)
        return ERROR_NOT_ENOUGH_MEMORY;

    ControlPacket->dwControl = SERVICE_CONTROL_START;
    ControlPacket->dwSize = TotalLength;
    Ptr = &ControlPacket->szArguments[0];
    wcscpy(Ptr, Service->lpServiceName);
    Ptr += (wcslen(Service->lpServiceName) + 1);

    /* Copy argument list */
    if (Arguments != NULL)
    {
        memcpy(Ptr, Arguments, ArgsLength);
        Ptr += ArgsLength;
    }

    /* Terminate the argument list */
    *Ptr = 0;

    /* Send the start command */
    WriteFile(Service->ControlPipeHandle,
              ControlPacket,
              sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
              &Count,
              NULL);

    /* FIXME: Read the reply */

    /* Release the contol packet */
    HeapFree(GetProcessHeap(),
             0,
             ControlPacket);

    DPRINT("ScmSendStartCommand() done\n");

    return ERROR_SUCCESS;
}


static DWORD
ScmStartUserModeService(PSERVICE Service,
                        LPWSTR lpArgs)
{
    RTL_QUERY_REGISTRY_TABLE QueryTable[3];
    PROCESS_INFORMATION ProcessInformation;
    STARTUPINFOW StartupInfo;
    UNICODE_STRING ImagePath;
    ULONG Type;
    BOOL Result;
    NTSTATUS Status;
    DWORD dwError = ERROR_SUCCESS;

    RtlInitUnicodeString(&ImagePath, NULL);

    /* Get service data */
    RtlZeroMemory(&QueryTable,
                  sizeof(QueryTable));

    QueryTable[0].Name = L"Type";
    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
    QueryTable[0].EntryContext = &Type;

    QueryTable[1].Name = L"ImagePath";
    QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
    QueryTable[1].EntryContext = &ImagePath;

    Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
                                    Service->lpServiceName,
                                    QueryTable,
                                    NULL,
                                    NULL);
    if (!NT_SUCCESS(Status))
    {
        DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
        return RtlNtStatusToDosError(Status);
    }
    DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
    DPRINT("Type: %lx\n", Type);

    /* Create '\\.\pipe\net\NtControlPipe' instance */
    Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
                                                  PIPE_ACCESS_DUPLEX,
                                                  PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
                                                  100,
                                                  8000,
                                                  4,
                                                  30000,
                                                  NULL);
    DPRINT("CreateNamedPipeW() done\n");
    if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
    {
        DPRINT1("Failed to create control pipe!\n");
        return GetLastError();
    }

    StartupInfo.cb = sizeof(StartupInfo);
    StartupInfo.lpReserved = NULL;
    StartupInfo.lpDesktop = NULL;
    StartupInfo.lpTitle = NULL;
    StartupInfo.dwFlags = 0;
    StartupInfo.cbReserved2 = 0;
    StartupInfo.lpReserved2 = 0;

    Result = CreateProcessW(ImagePath.Buffer,
                            NULL,
                            NULL,
                            NULL,
                            FALSE,
                            DETACHED_PROCESS | CREATE_SUSPENDED,
                            NULL,
                            NULL,
                            &StartupInfo,
                            &ProcessInformation);
    RtlFreeUnicodeString(&ImagePath);

    if (!Result)
    {
        dwError = GetLastError();
        /* Close control pipe */
        CloseHandle(Service->ControlPipeHandle);
        Service->ControlPipeHandle = INVALID_HANDLE_VALUE;

        DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
        return dwError;
    }

    DPRINT("Process Id: %lu  Handle %lx\n",
           ProcessInformation.dwProcessId,
           ProcessInformation.hProcess);
    DPRINT("Thread Id: %lu  Handle %lx\n",
           ProcessInformation.dwThreadId,
           ProcessInformation.hThread);

    /* Get process and thread ids */
    Service->ProcessId = ProcessInformation.dwProcessId;
    Service->ThreadId = ProcessInformation.dwThreadId;

    /* Resume Thread */
    ResumeThread(ProcessInformation.hThread);

    /* Connect control pipe */
    if (ConnectNamedPipe(Service->ControlPipeHandle, NULL) ?
        TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
    {
        DWORD dwProcessId = 0;
        DWORD dwRead = 0;

        DPRINT("Control pipe connected!\n");

        /* Read thread id from pipe */
        if (!ReadFile(Service->ControlPipeHandle,
                      (LPVOID)&dwProcessId,
                      sizeof(DWORD),
                      &dwRead,
                      NULL))
        {
            dwError = GetLastError();
            DPRINT1("Reading the service control pipe failed (Error %lu)\n",
                    dwError);
        }
        else
        {
            DPRINT("Received process id %lu\n", dwProcessId);

            /* Send start command */
            dwError = ScmSendStartCommand(Service, lpArgs);
        }
    }
    else
    {
        DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);

        /* Close control pipe */
        CloseHandle(Service->ControlPipeHandle);
        Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
        Service->ProcessId = 0;
        Service->ThreadId = 0;
    }

    /* Close process and thread handle */
    CloseHandle(ProcessInformation.hThread);
    CloseHandle(ProcessInformation.hProcess);

    return dwError;
}


DWORD
ScmStartService(PSERVICE Service, LPWSTR lpArgs)
{
    PSERVICE_GROUP Group = Service->lpGroup;
    DWORD dwError = ERROR_SUCCESS;

    DPRINT("ScmStartService() called\n");

    Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
    DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);

    if (Service->Status.dwServiceType & SERVICE_DRIVER)
    {
        /* Load driver */
        dwError = ScmLoadDriver(Service);
        if (dwError == ERROR_SUCCESS)
            Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    }
    else
    {
        /* Start user-mode service */
        dwError = ScmStartUserModeService(Service, lpArgs);
    }

    DPRINT("ScmStartService() done (Error %lu)\n", dwError);

    if (dwError == ERROR_SUCCESS)
    {
        if (Group != NULL)
        {
            Group->ServicesRunning = TRUE;
        }
        Service->Status.dwCurrentState = SERVICE_RUNNING;
    }
#if 0
    else
    {
        switch (Service->ErrorControl)
        {
            case SERVICE_ERROR_NORMAL:
                /* FIXME: Log error */
                break;

            case SERVICE_ERROR_SEVERE:
                if (IsLastKnownGood == FALSE)
                {
                    /* FIXME: Boot last known good configuration */
                }
                break;

            case SERVICE_ERROR_CRITICAL:
                if (IsLastKnownGood == FALSE)
                {
                    /* FIXME: Boot last known good configuration */
                }
                else
                {
                    /* FIXME: BSOD! */
                }
                break;
        }
    }
#endif

    return dwError;
}


VOID
ScmAutoStartServices(VOID)
{
    PLIST_ENTRY GroupEntry;
    PLIST_ENTRY ServiceEntry;
    PSERVICE_GROUP CurrentGroup;
    PSERVICE CurrentService;
    ULONG i;

    /* Clear 'ServiceVisited' flag */
    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
      CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
      CurrentService->ServiceVisited = FALSE;
      ServiceEntry = ServiceEntry->Flink;
    }

    /* Start all services which are members of an existing group */
    GroupEntry = GroupListHead.Flink;
    while (GroupEntry != &GroupListHead)
    {
        CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);

        DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);

        /* Start all services witch have a valid tag */
        for (i = 0; i < CurrentGroup->TagCount; i++)
        {
            ServiceEntry = ServiceListHead.Flink;
            while (ServiceEntry != &ServiceListHead)
            {
                CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

                if ((CurrentService->lpGroup == CurrentGroup) &&
                    (CurrentService->dwStartType == SERVICE_AUTO_START) &&
                    (CurrentService->ServiceVisited == FALSE) &&
                    (CurrentService->dwTag == CurrentGroup->TagArray[i]))
                {
                    CurrentService->ServiceVisited = TRUE;
                    ScmStartService(CurrentService, NULL);
                }

                ServiceEntry = ServiceEntry->Flink;
             }
        }

        /* Start all services which have an invalid tag or which do not have a tag */
        ServiceEntry = ServiceListHead.Flink;
        while (ServiceEntry != &ServiceListHead)
        {
            CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

            if ((CurrentService->lpGroup == CurrentGroup) &&
                (CurrentService->dwStartType == SERVICE_AUTO_START) &&
                (CurrentService->ServiceVisited == FALSE))
            {
                CurrentService->ServiceVisited = TRUE;
                ScmStartService(CurrentService, NULL);
            }

            ServiceEntry = ServiceEntry->Flink;
        }

        GroupEntry = GroupEntry->Flink;
    }

    /* Start all services which are members of any non-existing group */
    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
        CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

        if ((CurrentService->lpGroup != NULL) &&
            (CurrentService->dwStartType == SERVICE_AUTO_START) &&
            (CurrentService->ServiceVisited == FALSE))
        {
            CurrentService->ServiceVisited = TRUE;
            ScmStartService(CurrentService, NULL);
        }

        ServiceEntry = ServiceEntry->Flink;
    }

    /* Start all services which are not a member of any group */
    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
        CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);

        if ((CurrentService->lpGroup == NULL) &&
            (CurrentService->dwStartType == SERVICE_AUTO_START) &&
            (CurrentService->ServiceVisited == FALSE))
        {
            CurrentService->ServiceVisited = TRUE;
            ScmStartService(CurrentService, NULL);
        }

        ServiceEntry = ServiceEntry->Flink;
    }

    /* Clear 'ServiceVisited' flag again */
    ServiceEntry = ServiceListHead.Flink;
    while (ServiceEntry != &ServiceListHead)
    {
        CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
        CurrentService->ServiceVisited = FALSE;
        ServiceEntry = ServiceEntry->Flink;
    }
}

/* EOF */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?