first stab at nfsd as a service
This commit is contained in:
parent
88c28ec995
commit
c80946b258
6 changed files with 784 additions and 5 deletions
|
|
@ -131,7 +131,7 @@
|
||||||
<CompileAs>CompileAsC</CompileAs>
|
<CompileAs>CompileAsC</CompileAs>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<Link>
|
<Link>
|
||||||
<AdditionalDependencies>ws2_32.lib;iphlpapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
<AdditionalDependencies>ws2_32.lib;iphlpapi.lib;kernel32.lib;advapi32.lib;shell32.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||||
<TargetMachine>MachineX64</TargetMachine>
|
<TargetMachine>MachineX64</TargetMachine>
|
||||||
|
|
@ -217,6 +217,7 @@
|
||||||
<ClCompile Include="..\daemon\rbtree.c" />
|
<ClCompile Include="..\daemon\rbtree.c" />
|
||||||
<ClCompile Include="..\daemon\readdir.c" />
|
<ClCompile Include="..\daemon\readdir.c" />
|
||||||
<ClCompile Include="..\daemon\readwrite.c" />
|
<ClCompile Include="..\daemon\readwrite.c" />
|
||||||
|
<ClCompile Include="..\daemon\service.c" />
|
||||||
<ClCompile Include="..\daemon\setattr.c" />
|
<ClCompile Include="..\daemon\setattr.c" />
|
||||||
<ClCompile Include="..\daemon\upcall.c" />
|
<ClCompile Include="..\daemon\upcall.c" />
|
||||||
<ClCompile Include="..\daemon\util.c" />
|
<ClCompile Include="..\daemon\util.c" />
|
||||||
|
|
@ -236,6 +237,7 @@
|
||||||
<ClInclude Include="..\daemon\nfs41_xdr.h" />
|
<ClInclude Include="..\daemon\nfs41_xdr.h" />
|
||||||
<ClInclude Include="..\daemon\pnfs.h" />
|
<ClInclude Include="..\daemon\pnfs.h" />
|
||||||
<ClInclude Include="..\daemon\rbtree.h" />
|
<ClInclude Include="..\daemon\rbtree.h" />
|
||||||
|
<ClInclude Include="..\daemon\service.h" />
|
||||||
<ClInclude Include="..\daemon\upcall.h" />
|
<ClInclude Include="..\daemon\upcall.h" />
|
||||||
<ClInclude Include="..\daemon\util.h" />
|
<ClInclude Include="..\daemon\util.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,9 @@
|
||||||
<ClCompile Include="..\daemon\callback_xdr.c">
|
<ClCompile Include="..\daemon\callback_xdr.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\daemon\service.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\daemon\daemon_debug.h">
|
<ClInclude Include="..\daemon\daemon_debug.h">
|
||||||
|
|
@ -151,6 +154,9 @@
|
||||||
<ClInclude Include="..\daemon\nfs41_callback.h">
|
<ClInclude Include="..\daemon\nfs41_callback.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="..\daemon\service.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<None Include="..\daemon\sources">
|
<None Include="..\daemon\sources">
|
||||||
|
|
|
||||||
|
|
@ -35,10 +35,13 @@
|
||||||
#include "upcall.h"
|
#include "upcall.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
#define MAX_NUM_THREADS 128
|
#define MAX_NUM_THREADS 128
|
||||||
BOOLEAN CREATED_SESSION = FALSE;
|
BOOLEAN CREATED_SESSION = FALSE;
|
||||||
|
|
||||||
|
#ifndef STANDALONE_NFSD //make sure to define it in "sources" not here
|
||||||
|
#include "service.h"
|
||||||
|
HANDLE stop_event = NULL;
|
||||||
|
#endif
|
||||||
typedef struct _nfs41_process_thread {
|
typedef struct _nfs41_process_thread {
|
||||||
HANDLE handle;
|
HANDLE handle;
|
||||||
uint32_t tid;
|
uint32_t tid;
|
||||||
|
|
@ -131,7 +134,19 @@ write_downcall:
|
||||||
return GetLastError();
|
return GetLastError();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef STANDALONE_NFSD
|
||||||
|
VOID ServiceStop()
|
||||||
|
{
|
||||||
|
if (stop_event)
|
||||||
|
SetEvent(stop_event);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef STANDALONE_NFSD
|
||||||
void __cdecl _tmain(int argc, TCHAR *argv[])
|
void __cdecl _tmain(int argc, TCHAR *argv[])
|
||||||
|
#else
|
||||||
|
VOID ServiceStart(DWORD argc, LPTSTR *argv)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
DWORD status = 0, len;
|
DWORD status = 0, len;
|
||||||
// handle to our drivers
|
// handle to our drivers
|
||||||
|
|
@ -175,6 +190,12 @@ void __cdecl _tmain(int argc, TCHAR *argv[])
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef STANDALONE_NFSD
|
||||||
|
stop_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||||
|
if (stop_event == NULL)
|
||||||
|
goto quit;
|
||||||
|
#endif
|
||||||
|
|
||||||
for (i = 0; i < MAX_NUM_THREADS; i++) {
|
for (i = 0; i < MAX_NUM_THREADS; i++) {
|
||||||
tids[i].handle = (HANDLE)_beginthreadex(NULL, 0, thread_main,
|
tids[i].handle = (HANDLE)_beginthreadex(NULL, 0, thread_main,
|
||||||
NULL, 0, &tids[i].tid);
|
NULL, 0, &tids[i].tid);
|
||||||
|
|
@ -184,10 +205,17 @@ void __cdecl _tmain(int argc, TCHAR *argv[])
|
||||||
goto quit;
|
goto quit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifndef STANDALONE_NFSD
|
||||||
|
// report the status to the service control manager.
|
||||||
|
if (!ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0))
|
||||||
|
goto quit;
|
||||||
|
WaitForSingleObject(stop_event, INFINITE);
|
||||||
|
#else
|
||||||
//This can be changed to waiting on an array of handles and using waitformultipleobjects
|
//This can be changed to waiting on an array of handles and using waitformultipleobjects
|
||||||
dprintf(1, "Parent waiting for children threads\n");
|
dprintf(1, "Parent waiting for children threads\n");
|
||||||
for (i = 0; i < MAX_NUM_THREADS; i++)
|
for (i = 0; i < MAX_NUM_THREADS; i++)
|
||||||
WaitForSingleObject(tids[i].handle, INFINITE );
|
WaitForSingleObject(tids[i].handle, INFINITE );
|
||||||
|
#endif
|
||||||
dprintf(1, "Parent woke up!!!!\n");
|
dprintf(1, "Parent woke up!!!!\n");
|
||||||
|
|
||||||
quit:
|
quit:
|
||||||
|
|
|
||||||
601
daemon/service.c
Normal file
601
daemon/service.c
Normal file
|
|
@ -0,0 +1,601 @@
|
||||||
|
/*---------------------------------------------------------------------------
|
||||||
|
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
Copyright (C) Microsoft Corporation. All rights reserved.
|
||||||
|
|
||||||
|
MODULE: service.c
|
||||||
|
|
||||||
|
PURPOSE: Implements functions required by all Windows NT services
|
||||||
|
|
||||||
|
FUNCTIONS:
|
||||||
|
main(int argc, char **argv);
|
||||||
|
service_ctrl(DWORD dwCtrlCode);
|
||||||
|
service_main(DWORD dwArgc, LPTSTR *lpszArgv);
|
||||||
|
CmdInstallService();
|
||||||
|
CmdRemoveService();
|
||||||
|
CmdDebugService(int argc, char **argv);
|
||||||
|
ControlHandler ( DWORD dwCtrlType );
|
||||||
|
GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
#ifndef STANDALONE_NFSD
|
||||||
|
#include <windows.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <process.h>
|
||||||
|
#include <tchar.h>
|
||||||
|
|
||||||
|
#include "service.h"
|
||||||
|
|
||||||
|
// internal variables
|
||||||
|
SERVICE_STATUS ssStatus; // current status of the service
|
||||||
|
SERVICE_STATUS_HANDLE sshStatusHandle;
|
||||||
|
DWORD dwErr = 0;
|
||||||
|
BOOL bDebug = FALSE;
|
||||||
|
TCHAR szErr[256];
|
||||||
|
|
||||||
|
// internal function prototypes
|
||||||
|
VOID WINAPI service_ctrl(DWORD dwCtrlCode);
|
||||||
|
VOID WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv);
|
||||||
|
VOID CmdInstallService();
|
||||||
|
VOID CmdRemoveService();
|
||||||
|
VOID CmdDebugService(int argc, char **argv);
|
||||||
|
BOOL WINAPI ControlHandler ( DWORD dwCtrlType );
|
||||||
|
LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize );
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: main
|
||||||
|
//
|
||||||
|
// PURPOSE: entrypoint for service
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// argc - number of command line arguments
|
||||||
|
// argv - array of command line arguments
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
// main() either performs the command line task, or
|
||||||
|
// call StartServiceCtrlDispatcher to register the
|
||||||
|
// main service thread. When the this call returns,
|
||||||
|
// the service has stopped, so exit.
|
||||||
|
//
|
||||||
|
void __cdecl main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
SERVICE_TABLE_ENTRY dispatchTable[] =
|
||||||
|
{
|
||||||
|
{ TEXT(SZSERVICENAME), (LPSERVICE_MAIN_FUNCTION)service_main},
|
||||||
|
{ NULL, NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
if ( (argc > 1) &&
|
||||||
|
((*argv[1] == '-') || (*argv[1] == '/')) )
|
||||||
|
{
|
||||||
|
if ( _stricmp( "install", argv[1]+1 ) == 0 )
|
||||||
|
{
|
||||||
|
CmdInstallService();
|
||||||
|
}
|
||||||
|
else if ( _stricmp( "remove", argv[1]+1 ) == 0 )
|
||||||
|
{
|
||||||
|
CmdRemoveService();
|
||||||
|
}
|
||||||
|
else if ( _stricmp( "debug", argv[1]+1 ) == 0 )
|
||||||
|
{
|
||||||
|
bDebug = TRUE;
|
||||||
|
CmdDebugService(argc, argv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
goto dispatch;
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it doesn't match any of the above parameters
|
||||||
|
// the service control manager may be starting the service
|
||||||
|
// so we must call StartServiceCtrlDispatcher
|
||||||
|
dispatch:
|
||||||
|
// this is just to be friendly
|
||||||
|
printf( "%s -install to install the service\n", SZAPPNAME );
|
||||||
|
printf( "%s -remove to remove the service\n", SZAPPNAME );
|
||||||
|
printf( "%s -debug <params> to run as a console app for debugging\n", SZAPPNAME );
|
||||||
|
printf( "\nStartServiceCtrlDispatcher being called.\n" );
|
||||||
|
printf( "This may take several seconds. Please wait.\n" );
|
||||||
|
|
||||||
|
if (!StartServiceCtrlDispatcher(dispatchTable))
|
||||||
|
AddToMessageLog(TEXT("StartServiceCtrlDispatcher failed."));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: service_main
|
||||||
|
//
|
||||||
|
// PURPOSE: To perform actual initialization of the service
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// dwArgc - number of command line arguments
|
||||||
|
// lpszArgv - array of command line arguments
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
// This routine performs the service initialization and then calls
|
||||||
|
// the user defined ServiceStart() routine to perform majority
|
||||||
|
// of the work.
|
||||||
|
//
|
||||||
|
void WINAPI service_main(DWORD dwArgc, LPTSTR *lpszArgv)
|
||||||
|
{
|
||||||
|
|
||||||
|
// register our service control handler:
|
||||||
|
//
|
||||||
|
sshStatusHandle = RegisterServiceCtrlHandler( TEXT(SZSERVICENAME), service_ctrl);
|
||||||
|
|
||||||
|
if (!sshStatusHandle)
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
// SERVICE_STATUS members that don't change in example
|
||||||
|
//
|
||||||
|
ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
||||||
|
ssStatus.dwServiceSpecificExitCode = 0;
|
||||||
|
|
||||||
|
|
||||||
|
// report the status to the service control manager.
|
||||||
|
//
|
||||||
|
if (!ReportStatusToSCMgr(
|
||||||
|
SERVICE_START_PENDING, // service state
|
||||||
|
NO_ERROR, // exit code
|
||||||
|
3000)) // wait hint
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
|
||||||
|
ServiceStart( dwArgc, lpszArgv );
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
// try to report the stopped status to the service control manager.
|
||||||
|
//
|
||||||
|
if (sshStatusHandle)
|
||||||
|
(VOID)ReportStatusToSCMgr(
|
||||||
|
SERVICE_STOPPED,
|
||||||
|
dwErr,
|
||||||
|
0);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: service_ctrl
|
||||||
|
//
|
||||||
|
// PURPOSE: This function is called by the SCM whenever
|
||||||
|
// ControlService() is called on this service.
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// dwCtrlCode - type of control requested
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
//
|
||||||
|
VOID WINAPI service_ctrl(DWORD dwCtrlCode)
|
||||||
|
{
|
||||||
|
// Handle the requested control code.
|
||||||
|
//
|
||||||
|
switch (dwCtrlCode)
|
||||||
|
{
|
||||||
|
// Stop the service.
|
||||||
|
//
|
||||||
|
// SERVICE_STOP_PENDING should be reported before
|
||||||
|
// setting the Stop Event - hServerStopEvent - in
|
||||||
|
// ServiceStop(). This avoids a race condition
|
||||||
|
// which may result in a 1053 - The Service did not respond...
|
||||||
|
// error.
|
||||||
|
case SERVICE_CONTROL_STOP:
|
||||||
|
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
||||||
|
ServiceStop();
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Update the service status.
|
||||||
|
//
|
||||||
|
case SERVICE_CONTROL_INTERROGATE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
// invalid control code
|
||||||
|
//
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportStatusToSCMgr(ssStatus.dwCurrentState, NO_ERROR, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: ReportStatusToSCMgr()
|
||||||
|
//
|
||||||
|
// PURPOSE: Sets the current status of the service and
|
||||||
|
// reports it to the Service Control Manager
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// dwCurrentState - the state of the service
|
||||||
|
// dwWin32ExitCode - error code to report
|
||||||
|
// dwWaitHint - worst case estimate to next checkpoint
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// TRUE - success
|
||||||
|
// FALSE - failure
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
//
|
||||||
|
BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
|
||||||
|
DWORD dwWin32ExitCode,
|
||||||
|
DWORD dwWaitHint)
|
||||||
|
{
|
||||||
|
static DWORD dwCheckPoint = 1;
|
||||||
|
BOOL fResult = TRUE;
|
||||||
|
|
||||||
|
|
||||||
|
if ( !bDebug ) // when debugging we don't report to the SCM
|
||||||
|
{
|
||||||
|
if (dwCurrentState == SERVICE_START_PENDING)
|
||||||
|
ssStatus.dwControlsAccepted = 0;
|
||||||
|
else
|
||||||
|
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||||
|
|
||||||
|
ssStatus.dwCurrentState = dwCurrentState;
|
||||||
|
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
|
||||||
|
ssStatus.dwWaitHint = dwWaitHint;
|
||||||
|
|
||||||
|
if ( ( dwCurrentState == SERVICE_RUNNING ) ||
|
||||||
|
( dwCurrentState == SERVICE_STOPPED ) )
|
||||||
|
ssStatus.dwCheckPoint = 0;
|
||||||
|
else
|
||||||
|
ssStatus.dwCheckPoint = dwCheckPoint++;
|
||||||
|
|
||||||
|
|
||||||
|
// Report the status of the service to the service control manager.
|
||||||
|
//
|
||||||
|
if (!(fResult = SetServiceStatus( sshStatusHandle, &ssStatus)))
|
||||||
|
{
|
||||||
|
AddToMessageLog(TEXT("SetServiceStatus"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
|
||||||
|
//
|
||||||
|
// PURPOSE: Allows any thread to log an error message
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// lpszMsg - text for message
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
//
|
||||||
|
VOID AddToMessageLog(LPTSTR lpszMsg)
|
||||||
|
{
|
||||||
|
TCHAR szMsg [(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100 ];
|
||||||
|
HANDLE hEventSource;
|
||||||
|
LPTSTR lpszStrings[2];
|
||||||
|
|
||||||
|
if ( !bDebug )
|
||||||
|
{
|
||||||
|
dwErr = GetLastError();
|
||||||
|
|
||||||
|
// Use event logging to log the error.
|
||||||
|
//
|
||||||
|
hEventSource = RegisterEventSource(NULL, TEXT(SZSERVICENAME));
|
||||||
|
|
||||||
|
_stprintf_s(szMsg,(sizeof(SZSERVICENAME) / sizeof(TCHAR)) + 100, TEXT("%s error: %d"), TEXT(SZSERVICENAME), dwErr);
|
||||||
|
lpszStrings[0] = szMsg;
|
||||||
|
lpszStrings[1] = lpszMsg;
|
||||||
|
|
||||||
|
if (hEventSource != NULL)
|
||||||
|
{
|
||||||
|
ReportEvent(hEventSource, // handle of event source
|
||||||
|
EVENTLOG_ERROR_TYPE, // event type
|
||||||
|
0, // event category
|
||||||
|
0, // event ID
|
||||||
|
NULL, // current user's SID
|
||||||
|
2, // strings in lpszStrings
|
||||||
|
0, // no bytes of raw data
|
||||||
|
lpszStrings, // array of error strings
|
||||||
|
NULL); // no raw data
|
||||||
|
|
||||||
|
(VOID) DeregisterEventSource(hEventSource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// The following code handles service installation and removal
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: CmdInstallService()
|
||||||
|
//
|
||||||
|
// PURPOSE: Installs the service
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
//
|
||||||
|
void CmdInstallService()
|
||||||
|
{
|
||||||
|
SC_HANDLE schService;
|
||||||
|
SC_HANDLE schSCManager;
|
||||||
|
|
||||||
|
TCHAR szPath[512];
|
||||||
|
|
||||||
|
if ( GetModuleFileName( NULL, szPath, 512 ) == 0 )
|
||||||
|
{
|
||||||
|
_tprintf(TEXT("Unable to install %s - %s\n"), TEXT(SZSERVICEDISPLAYNAME), GetLastErrorText(szErr, 256));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
schSCManager = OpenSCManager(
|
||||||
|
NULL, // machine (NULL == local)
|
||||||
|
NULL, // database (NULL == default)
|
||||||
|
SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE // access required
|
||||||
|
);
|
||||||
|
if ( schSCManager )
|
||||||
|
{
|
||||||
|
schService = CreateService(
|
||||||
|
schSCManager, // SCManager database
|
||||||
|
TEXT(SZSERVICENAME), // name of service
|
||||||
|
TEXT(SZSERVICEDISPLAYNAME), // name to display
|
||||||
|
SERVICE_QUERY_STATUS, // desired access
|
||||||
|
SERVICE_WIN32_OWN_PROCESS, // service type
|
||||||
|
SERVICE_DEMAND_START, // start type
|
||||||
|
SERVICE_ERROR_NORMAL, // error control type
|
||||||
|
szPath, // service's binary
|
||||||
|
NULL, // no load ordering group
|
||||||
|
NULL, // no tag identifier
|
||||||
|
TEXT(SZDEPENDENCIES), // dependencies
|
||||||
|
NULL, // LocalSystem account
|
||||||
|
NULL); // no password
|
||||||
|
|
||||||
|
if ( schService )
|
||||||
|
{
|
||||||
|
_tprintf(TEXT("%s installed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
|
||||||
|
CloseServiceHandle(schService);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_tprintf(TEXT("CreateService failed - %s\n"), GetLastErrorText(szErr, 256));
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: CmdRemoveService()
|
||||||
|
//
|
||||||
|
// PURPOSE: Stops and removes the service
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
//
|
||||||
|
void CmdRemoveService()
|
||||||
|
{
|
||||||
|
SC_HANDLE schService;
|
||||||
|
SC_HANDLE schSCManager;
|
||||||
|
|
||||||
|
schSCManager = OpenSCManager(
|
||||||
|
NULL, // machine (NULL == local)
|
||||||
|
NULL, // database (NULL == default)
|
||||||
|
SC_MANAGER_CONNECT // access required
|
||||||
|
);
|
||||||
|
if ( schSCManager )
|
||||||
|
{
|
||||||
|
schService = OpenService(schSCManager, TEXT(SZSERVICENAME), DELETE | SERVICE_STOP | SERVICE_QUERY_STATUS);
|
||||||
|
|
||||||
|
if (schService)
|
||||||
|
{
|
||||||
|
// try to stop the service
|
||||||
|
if ( ControlService( schService, SERVICE_CONTROL_STOP, &ssStatus ) )
|
||||||
|
{
|
||||||
|
_tprintf(TEXT("Stopping %s."), TEXT(SZSERVICEDISPLAYNAME));
|
||||||
|
Sleep( 1000 );
|
||||||
|
|
||||||
|
while ( QueryServiceStatus( schService, &ssStatus ) )
|
||||||
|
{
|
||||||
|
if ( ssStatus.dwCurrentState == SERVICE_STOP_PENDING )
|
||||||
|
{
|
||||||
|
_tprintf(TEXT("."));
|
||||||
|
Sleep( 1000 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( ssStatus.dwCurrentState == SERVICE_STOPPED )
|
||||||
|
_tprintf(TEXT("\n%s stopped.\n"), TEXT(SZSERVICEDISPLAYNAME) );
|
||||||
|
else
|
||||||
|
_tprintf(TEXT("\n%s failed to stop.\n"), TEXT(SZSERVICEDISPLAYNAME) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// now remove the service
|
||||||
|
if ( DeleteService(schService) )
|
||||||
|
_tprintf(TEXT("%s removed.\n"), TEXT(SZSERVICEDISPLAYNAME) );
|
||||||
|
else
|
||||||
|
_tprintf(TEXT("DeleteService failed - %s\n"), GetLastErrorText(szErr,256));
|
||||||
|
|
||||||
|
|
||||||
|
CloseServiceHandle(schService);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_tprintf(TEXT("OpenService failed - %s\n"), GetLastErrorText(szErr,256));
|
||||||
|
|
||||||
|
CloseServiceHandle(schSCManager);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
_tprintf(TEXT("OpenSCManager failed - %s\n"), GetLastErrorText(szErr,256));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// The following code is for running the service as a console app
|
||||||
|
//
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: CmdDebugService(int argc, char ** argv)
|
||||||
|
//
|
||||||
|
// PURPOSE: Runs the service as a console application
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// argc - number of command line arguments
|
||||||
|
// argv - array of command line arguments
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
//
|
||||||
|
void CmdDebugService(int argc, char ** argv)
|
||||||
|
{
|
||||||
|
DWORD dwArgc;
|
||||||
|
LPTSTR *lpszArgv;
|
||||||
|
|
||||||
|
#ifdef UNICODE
|
||||||
|
lpszArgv = CommandLineToArgvW(GetCommandLineW(), &(dwArgc) );
|
||||||
|
if (NULL == lpszArgv)
|
||||||
|
{
|
||||||
|
// CommandLineToArvW failed!!
|
||||||
|
_tprintf(TEXT("CmdDebugService CommandLineToArgvW returned NULL\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
dwArgc = (DWORD) argc;
|
||||||
|
lpszArgv = argv;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
_tprintf(TEXT("Debugging %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
|
||||||
|
|
||||||
|
SetConsoleCtrlHandler( ControlHandler, TRUE );
|
||||||
|
|
||||||
|
ServiceStart( dwArgc, lpszArgv );
|
||||||
|
|
||||||
|
#ifdef UNICODE
|
||||||
|
// Must free memory allocated for arguments
|
||||||
|
|
||||||
|
GlobalFree(lpszArgv);
|
||||||
|
#endif // UNICODE
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: ControlHandler ( DWORD dwCtrlType )
|
||||||
|
//
|
||||||
|
// PURPOSE: Handled console control events
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// dwCtrlType - type of control event
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// True - handled
|
||||||
|
// False - unhandled
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
//
|
||||||
|
BOOL WINAPI ControlHandler ( DWORD dwCtrlType )
|
||||||
|
{
|
||||||
|
switch ( dwCtrlType )
|
||||||
|
{
|
||||||
|
case CTRL_BREAK_EVENT: // use Ctrl+C or Ctrl+Break to simulate
|
||||||
|
case CTRL_C_EVENT: // SERVICE_CONTROL_STOP in debug mode
|
||||||
|
_tprintf(TEXT("Stopping %s.\n"), TEXT(SZSERVICEDISPLAYNAME));
|
||||||
|
ServiceStop();
|
||||||
|
return TRUE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: GetLastErrorText
|
||||||
|
//
|
||||||
|
// PURPOSE: copies error message text to string
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// lpszBuf - destination buffer
|
||||||
|
// dwSize - size of buffer
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// destination buffer
|
||||||
|
//
|
||||||
|
// COMMENTS:
|
||||||
|
//
|
||||||
|
LPTSTR GetLastErrorText( LPTSTR lpszBuf, DWORD dwSize )
|
||||||
|
{
|
||||||
|
DWORD dwRet;
|
||||||
|
LPTSTR lpszTemp = NULL;
|
||||||
|
|
||||||
|
dwRet = FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |FORMAT_MESSAGE_ARGUMENT_ARRAY,
|
||||||
|
NULL,
|
||||||
|
GetLastError(),
|
||||||
|
LANG_NEUTRAL,
|
||||||
|
(LPTSTR)&lpszTemp,
|
||||||
|
0,
|
||||||
|
NULL );
|
||||||
|
|
||||||
|
// supplied buffer is not long enough
|
||||||
|
if ( !dwRet || ( (long)dwSize < (long)dwRet+14 ) )
|
||||||
|
lpszBuf[0] = TEXT('\0');
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (NULL != lpszTemp)
|
||||||
|
{
|
||||||
|
lpszTemp[lstrlen(lpszTemp)-2] = TEXT('\0'); //remove cr and newline character
|
||||||
|
_stprintf_s( lpszBuf, dwSize, TEXT("%s (0x%x)"), lpszTemp, GetLastError() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( NULL != lpszTemp )
|
||||||
|
LocalFree((HLOCAL) lpszTemp );
|
||||||
|
|
||||||
|
return lpszBuf;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
137
daemon/service.h
Normal file
137
daemon/service.h
Normal file
|
|
@ -0,0 +1,137 @@
|
||||||
|
/*---------------------------------------------------------------------------
|
||||||
|
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||||
|
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
|
||||||
|
TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE.
|
||||||
|
|
||||||
|
Copyright (C) Microsoft Corporation. All rights reserved.
|
||||||
|
|
||||||
|
MODULE: service.h
|
||||||
|
|
||||||
|
Comments: The use of this header file and the accompanying service.c
|
||||||
|
file simplifies the process of writting a service. You as a developer
|
||||||
|
simply need to follow the TODO's outlined in this header file, and
|
||||||
|
implement the ServiceStart() and ServiceStop() functions.
|
||||||
|
|
||||||
|
There is no need to modify the code in service.c. Just add service.c
|
||||||
|
to your project and link with the following libraries...
|
||||||
|
|
||||||
|
libcmt.lib kernel32.lib advapi.lib shell32.lib
|
||||||
|
|
||||||
|
This code also supports unicode. Be sure to compile both service.c and
|
||||||
|
and code #include "service.h" with the same Unicode setting.
|
||||||
|
|
||||||
|
Upon completion, your code will have the following command line interface
|
||||||
|
|
||||||
|
<service exe> -? to display this list
|
||||||
|
<service exe> -install to install the service
|
||||||
|
<service exe> -remove to remove the service
|
||||||
|
<service exe> -debug <params> to run as a console app for debugging
|
||||||
|
|
||||||
|
Note: This code also implements Ctrl+C and Ctrl+Break handlers
|
||||||
|
when using the debug option. These console events cause
|
||||||
|
your ServiceStop routine to be called
|
||||||
|
|
||||||
|
Also, this code only handles the OWN_SERVICE service type
|
||||||
|
running in the LOCAL_SYSTEM security context.
|
||||||
|
|
||||||
|
To control your service ( start, stop, etc ) you may use the
|
||||||
|
Services control panel applet or the NET.EXE program.
|
||||||
|
|
||||||
|
To aid in writing/debugging service, the
|
||||||
|
SDK contains a utility (MSTOOLS\BIN\SC.EXE) that
|
||||||
|
can be used to control, configure, or obtain service status.
|
||||||
|
SC displays complete status for any service/driver
|
||||||
|
in the service database, and allows any of the configuration
|
||||||
|
parameters to be easily changed at the command line.
|
||||||
|
For more information on SC.EXE, type SC at the command line.
|
||||||
|
|
||||||
|
|
||||||
|
------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef _SERVICE_H
|
||||||
|
#define _SERVICE_H
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//// todo: change to desired strings
|
||||||
|
////
|
||||||
|
// name of the executable
|
||||||
|
#define SZAPPNAME "nfsd"
|
||||||
|
// internal name of the service
|
||||||
|
#define SZSERVICENAME "pnfs"
|
||||||
|
// displayed name of the service
|
||||||
|
#define SZSERVICEDISPLAYNAME "pnfs client"
|
||||||
|
// list of service dependencies - "dep1\0dep2\0\0"
|
||||||
|
#define SZDEPENDENCIES ""
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//// todo: ServiceStart()must be defined by in your code.
|
||||||
|
//// The service should use ReportStatusToSCMgr to indicate
|
||||||
|
//// progress. This routine must also be used by StartService()
|
||||||
|
//// to report to the SCM when the service is running.
|
||||||
|
////
|
||||||
|
//// If a ServiceStop procedure is going to take longer than
|
||||||
|
//// 3 seconds to execute, it should spawn a thread to
|
||||||
|
//// execute the stop code, and return. Otherwise, the
|
||||||
|
//// ServiceControlManager will believe that the service has
|
||||||
|
//// stopped responding
|
||||||
|
////
|
||||||
|
VOID ServiceStart(DWORD dwArgc, LPTSTR *lpszArgv);
|
||||||
|
VOID ServiceStop();
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
//// The following are procedures which
|
||||||
|
//// may be useful to call within the above procedures,
|
||||||
|
//// but require no implementation by the user.
|
||||||
|
//// They are implemented in service.c
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: ReportStatusToSCMgr()
|
||||||
|
//
|
||||||
|
// PURPOSE: Sets the current status of the service and
|
||||||
|
// reports it to the Service Control Manager
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// dwCurrentState - the state of the service
|
||||||
|
// dwWin32ExitCode - error code to report
|
||||||
|
// dwWaitHint - worst case estimate to next checkpoint
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// TRUE - success
|
||||||
|
// FALSE - failure
|
||||||
|
//
|
||||||
|
BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// FUNCTION: AddToMessageLog(LPTSTR lpszMsg)
|
||||||
|
//
|
||||||
|
// PURPOSE: Allows any thread to log an error message
|
||||||
|
//
|
||||||
|
// PARAMETERS:
|
||||||
|
// lpszMsg - text for message
|
||||||
|
//
|
||||||
|
// RETURN VALUE:
|
||||||
|
// none
|
||||||
|
//
|
||||||
|
void AddToMessageLog(LPTSTR lpszMsg);
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -4,13 +4,18 @@ SOURCES=nfs41_daemon.c daemon_debug.c nfs41_ops.c nfs41_compound.c nfs41_xdr.c \
|
||||||
nfs41_server.c nfs41_client.c nfs41_superblock.c nfs41_session.c lookup.c \
|
nfs41_server.c nfs41_client.c nfs41_superblock.c nfs41_session.c lookup.c \
|
||||||
mount.c open.c readwrite.c lock.c readdir.c getattr.c setattr.c upcall.c \
|
mount.c open.c readwrite.c lock.c readdir.c getattr.c setattr.c upcall.c \
|
||||||
nfs41_rpc.c util.c pnfs_layout.c pnfs_device.c pnfs_debug.c pnfs_io.c \
|
nfs41_rpc.c util.c pnfs_layout.c pnfs_device.c pnfs_debug.c pnfs_io.c \
|
||||||
name_cache.c namespace.c rbtree.c volume.c callback_server.c callback_xdr.c
|
name_cache.c namespace.c rbtree.c volume.c callback_server.c callback_xdr.c \
|
||||||
|
service.c
|
||||||
UMTYPE=console
|
UMTYPE=console
|
||||||
USE_LIBCMT=1
|
USE_LIBCMT=1
|
||||||
#USE_MSVCRT=1
|
#USE_MSVCRT=1
|
||||||
|
#C_DEFINES=-DSTANDALONE_NFSD -- use this for non-service nfsd
|
||||||
INCLUDES=..\sys;..\dll;..\libtirpc\tirpc
|
INCLUDES=..\sys;..\dll;..\libtirpc\tirpc
|
||||||
TARGETLIBS=$(SDK_LIB_PATH)\ws2_32.lib $(SDK_LIB_PATH)\iphlpapi.lib \
|
TARGETLIBS=$(SDK_LIB_PATH)\ws2_32.lib $(SDK_LIB_PATH)\iphlpapi.lib \
|
||||||
..\libtirpc\src\obj$(BUILD_ALT_DIR)\*\libtirpc.lib
|
..\libtirpc\src\obj$(BUILD_ALT_DIR)\*\libtirpc.lib \
|
||||||
|
$(SDK_LIB_PATH)\kernel32.lib \
|
||||||
|
$(SDK_LIB_PATH)\advapi32.lib \
|
||||||
|
$(SDK_LIB_PATH)\shell32.lib
|
||||||
|
|
||||||
!IF 0
|
!IF 0
|
||||||
/W3 is default level
|
/W3 is default level
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue