mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 16:33:02 -05:00
launcher: SvcInstance implementation
This commit is contained in:
parent
dc4109fc22
commit
457e151fa5
@ -175,6 +175,9 @@
|
||||
<Project>{4a7c0b21-9e10-4c81-92de-1493efcf24eb}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\minimal.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
|
@ -5,10 +5,21 @@
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Include">
|
||||
<UniqueIdentifier>{11e7c0f2-7782-43ee-84fa-9e56efbe39de}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Include\shared">
|
||||
<UniqueIdentifier>{d83ea433-d9f7-494c-90b9-3a8997483cd9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\..\src\launcher\launcher.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\src\shared\minimal.h">
|
||||
<Filter>Include\shared</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -16,21 +16,289 @@
|
||||
*/
|
||||
|
||||
#include <winfsp/winfsp.h>
|
||||
#include <shared/minimal.h>
|
||||
#include <sddl.h>
|
||||
|
||||
#define PROGNAME "winfsp-launcher"
|
||||
#define PROGNAME "WinFsp-Launcher"
|
||||
#define REGKEY "SYSTEM\\CurrentControlSet\\Services\\" PROGNAME "\\Services"
|
||||
|
||||
NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
HANDLE ProcessHeap;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PWSTR ClassName;
|
||||
PWSTR InstanceName;
|
||||
PWSTR CommandLine;
|
||||
DWORD ProcessId;
|
||||
HANDLE Process;
|
||||
HANDLE ProcessWait;
|
||||
LIST_ENTRY ListEntry;
|
||||
WCHAR Buffer[];
|
||||
} SVC_INSTANCE;
|
||||
|
||||
static CRITICAL_SECTION SvcInstanceLock;
|
||||
static LIST_ENTRY SvcInstanceList = { &SvcInstanceList, &SvcInstanceList };
|
||||
|
||||
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Fired);
|
||||
|
||||
static SVC_INSTANCE *SvcInstanceFromName(PWSTR InstanceName)
|
||||
{
|
||||
SVC_INSTANCE *SvcInstance;
|
||||
PLIST_ENTRY ListEntry;
|
||||
|
||||
for (ListEntry = SvcInstanceList.Flink;
|
||||
&SvcInstanceList != ListEntry;
|
||||
ListEntry = ListEntry->Flink)
|
||||
{
|
||||
SvcInstance = CONTAINING_RECORD(ListEntry, SVC_INSTANCE, ListEntry);
|
||||
|
||||
if (0 == lstrcmpW(InstanceName, SvcInstance->InstanceName))
|
||||
return SvcInstance;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ULONG SvcInstanceArgumentLength(PWSTR Arg)
|
||||
{
|
||||
ULONG Length;
|
||||
|
||||
Length = 2; /* for beginning and ending quotes */
|
||||
for (PWSTR P = Arg; *P; P++)
|
||||
if (L'"' != *P)
|
||||
Length++;
|
||||
|
||||
return Length;
|
||||
}
|
||||
|
||||
static PWSTR SvcInstanceArgumentCopy(PWSTR Dest, PWSTR Arg)
|
||||
{
|
||||
*Dest++ = L'"';
|
||||
for (PWSTR P = Arg; *P; P++)
|
||||
if (L'"' != *P)
|
||||
*Dest++ = *P;
|
||||
*Dest++ = L'"';
|
||||
|
||||
return Dest;
|
||||
}
|
||||
|
||||
static NTSTATUS SvcInstanceReplaceArguments(PWSTR String, ULONG Argc, PWSTR *Argv,
|
||||
PWSTR *PNewString)
|
||||
{
|
||||
PWSTR NewString = 0;
|
||||
ULONG Length;
|
||||
|
||||
*PNewString = 0;
|
||||
|
||||
Length = 0;
|
||||
for (PWSTR P = String; *P; P++)
|
||||
{
|
||||
switch (*P)
|
||||
{
|
||||
case L'%':
|
||||
P++;
|
||||
if (L'0' <= *P && *P <= '9' && Argc > (ULONG)(*P - L'0'))
|
||||
Length += SvcInstanceArgumentLength(Argv[*P - L'0']);
|
||||
break;
|
||||
default:
|
||||
Length++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
NewString = MemAlloc((Length + 1) * sizeof(WCHAR));
|
||||
if (0 == NewString)
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
*PNewString = NewString;
|
||||
for (PWSTR P = String, Q = NewString; *P; P++)
|
||||
{
|
||||
switch (*P)
|
||||
{
|
||||
case L'%':
|
||||
P++;
|
||||
if (L'0' <= *P && *P <= '9' && Argc > (ULONG)(*P - L'0'))
|
||||
Q = SvcInstanceArgumentCopy(Q, Argv[*P - L'0']);
|
||||
break;
|
||||
default:
|
||||
Q++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS SvcStop(FSP_SERVICE *Service)
|
||||
NTSTATUS SvcInstanceCreate(PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv,
|
||||
SVC_INSTANCE **PSvcInstance)
|
||||
{
|
||||
SVC_INSTANCE *SvcInstance = 0;
|
||||
HKEY RegKey = 0;
|
||||
DWORD RegResult, RegSize;
|
||||
DWORD ClassNameSize, InstanceNameSize;
|
||||
WCHAR Executable[MAX_PATH], CommandLine[512];
|
||||
STARTUPINFOW StartupInfo;
|
||||
PROCESS_INFORMATION ProcessInfo;
|
||||
NTSTATUS Result;
|
||||
|
||||
*PSvcInstance = 0;
|
||||
|
||||
EnterCriticalSection(&SvcInstanceLock);
|
||||
|
||||
if (0 != SvcInstanceFromName(InstanceName))
|
||||
{
|
||||
Result = STATUS_OBJECT_NAME_COLLISION;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"" REGKEY, 0, KEY_READ, &RegKey);
|
||||
if (ERROR_SUCCESS != RegResult)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
RegSize = sizeof Executable;
|
||||
RegResult = RegGetValueW(RegKey, ClassName, L"Executable", RRF_RT_REG_SZ, 0,
|
||||
&Executable, &RegSize);
|
||||
if (ERROR_SUCCESS != RegResult)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
RegSize = sizeof CommandLine;
|
||||
RegResult = RegGetValueW(RegKey, ClassName, L"CommandLine", RRF_RT_REG_SZ, 0,
|
||||
&CommandLine, &RegSize);
|
||||
if (ERROR_SUCCESS != RegResult)
|
||||
{
|
||||
Result = FspNtStatusFromWin32(RegResult);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
RegCloseKey(RegKey);
|
||||
RegKey = 0;
|
||||
|
||||
ClassNameSize = (lstrlenW(ClassName) + 1) * sizeof(WCHAR);
|
||||
InstanceNameSize = (lstrlenW(InstanceName) + 1) * sizeof(WCHAR);
|
||||
|
||||
SvcInstance = MemAlloc(sizeof *SvcInstance + ClassNameSize + InstanceNameSize);
|
||||
if (0 == SvcInstance)
|
||||
{
|
||||
Result = STATUS_INSUFFICIENT_RESOURCES;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
memset(SvcInstance, 0, sizeof *SvcInstance);
|
||||
memcpy(SvcInstance->Buffer, ClassName, ClassNameSize);
|
||||
memcpy(SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR), InstanceName, InstanceNameSize);
|
||||
SvcInstance->ClassName = SvcInstance->Buffer;
|
||||
SvcInstance->InstanceName = SvcInstance->Buffer + ClassNameSize / sizeof(WCHAR);
|
||||
|
||||
Result = SvcInstanceReplaceArguments(CommandLine, Argc, Argv, &SvcInstance->CommandLine);
|
||||
if (!NT_SUCCESS(Result))
|
||||
goto exit;
|
||||
|
||||
memset(&StartupInfo, 0, sizeof StartupInfo);
|
||||
StartupInfo.cb = sizeof StartupInfo;
|
||||
if (!CreateProcessW(0, SvcInstance->CommandLine, 0, 0, FALSE, CREATE_NEW_PROCESS_GROUP, 0, 0,
|
||||
&StartupInfo, &ProcessInfo))
|
||||
{
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
goto exit;
|
||||
}
|
||||
|
||||
CloseHandle(ProcessInfo.hThread);
|
||||
SvcInstance->ProcessId = ProcessInfo.dwProcessId;
|
||||
SvcInstance->Process = ProcessInfo.hProcess;
|
||||
|
||||
if (!RegisterWaitForSingleObject(&SvcInstance->ProcessWait, SvcInstance->Process,
|
||||
SvcInstanceTerminated, SvcInstance, INFINITE, WT_EXECUTEONLYONCE))
|
||||
{
|
||||
/* we have no way when the new process will terminate so go ahead and close its handle */
|
||||
FspServiceLog(EVENTLOG_WARNING_TYPE,
|
||||
L"RegisterWaitForSingleObject = %ld", GetLastError());
|
||||
CloseHandle(SvcInstance->Process);
|
||||
SvcInstance->Process = 0;
|
||||
}
|
||||
|
||||
InsertTailList(&SvcInstanceList, &SvcInstance->ListEntry);
|
||||
|
||||
*PSvcInstance = SvcInstance;
|
||||
|
||||
Result = STATUS_SUCCESS;
|
||||
|
||||
exit:
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
MemFree(SvcInstance->CommandLine);
|
||||
MemFree(SvcInstance);
|
||||
}
|
||||
|
||||
if (0 != RegKey)
|
||||
RegCloseKey(RegKey);
|
||||
|
||||
LeaveCriticalSection(&SvcInstanceLock);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
VOID SvcInstanceDelete(SVC_INSTANCE *SvcInstance)
|
||||
{
|
||||
EnterCriticalSection(&SvcInstanceLock);
|
||||
RemoveEntryList(&SvcInstance->ListEntry);
|
||||
LeaveCriticalSection(&SvcInstanceLock);
|
||||
|
||||
if (0 != SvcInstance->ProcessWait)
|
||||
UnregisterWaitEx(SvcInstance->ProcessWait, 0);
|
||||
if (0 != SvcInstance->Process)
|
||||
CloseHandle(SvcInstance->Process);
|
||||
MemFree(SvcInstance->CommandLine);
|
||||
MemFree(SvcInstance);
|
||||
}
|
||||
|
||||
static VOID CALLBACK SvcInstanceTerminated(PVOID Context, BOOLEAN Fired)
|
||||
{
|
||||
SVC_INSTANCE *SvcInstance = Context;
|
||||
|
||||
SvcInstanceDelete(SvcInstance);
|
||||
}
|
||||
|
||||
NTSTATUS SvcInstanceStart(PWSTR ClassName, PWSTR InstanceName, ULONG Argc, PWSTR *Argv)
|
||||
{
|
||||
SVC_INSTANCE *SvcInstance;
|
||||
|
||||
return SvcInstanceCreate(ClassName, InstanceName, Argc, Argv, &SvcInstance);
|
||||
}
|
||||
|
||||
VOID SvcInstanceStop(PWSTR InstanceName)
|
||||
{
|
||||
SVC_INSTANCE *SvcInstance;
|
||||
|
||||
EnterCriticalSection(&SvcInstanceLock);
|
||||
SvcInstance = SvcInstanceFromName(InstanceName);
|
||||
if (0 != SvcInstance)
|
||||
GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, SvcInstance->ProcessId);
|
||||
LeaveCriticalSection(&SvcInstanceLock);
|
||||
}
|
||||
|
||||
static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
{
|
||||
InitializeCriticalSection(&SvcInstanceLock);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static NTSTATUS SvcStop(FSP_SERVICE *Service)
|
||||
{
|
||||
DeleteCriticalSection(&SvcInstanceLock);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
int wmain(int argc, wchar_t **argv)
|
||||
{
|
||||
ProcessHeap = GetProcessHeap();
|
||||
if (0 == ProcessHeap)
|
||||
return GetLastError();
|
||||
return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user