mirror of
				https://github.com/winfsp/winfsp.git
				synced 2025-10-30 03:28:38 -05:00 
			
		
		
		
	launchctl: implementation
This commit is contained in:
		| @@ -19,12 +19,268 @@ | ||||
|  | ||||
| #define PROGNAME                        "launchctl" | ||||
|  | ||||
| #define fatal(ExitCode, format, ...)    (warn(format, __VA_ARGS__), ExitProcess(ExitCode)) | ||||
|  | ||||
| static void vwarn(const char *format, va_list ap) | ||||
| { | ||||
|     char buf[1024]; | ||||
|         /* wvsprintf is only safe with a 1024 byte buffer */ | ||||
|     size_t len; | ||||
|     DWORD BytesTransferred; | ||||
|  | ||||
|     wvsprintfA(buf, format, ap); | ||||
|     buf[sizeof buf - 1] = '\0'; | ||||
|  | ||||
|     len = lstrlenA(buf); | ||||
|     buf[len++] = '\n'; | ||||
|  | ||||
|     WriteFile(GetStdHandle(STD_ERROR_HANDLE), | ||||
|         buf, (DWORD)len, &BytesTransferred, 0); | ||||
| } | ||||
|  | ||||
| static void warn(const char *format, ...) | ||||
| { | ||||
|     va_list ap; | ||||
|  | ||||
|     va_start(ap, format); | ||||
|     vwarn(format, ap); | ||||
|     va_end(ap); | ||||
| } | ||||
|  | ||||
| static void usage(void) | ||||
| { | ||||
|     fatal(ERROR_INVALID_PARAMETER, | ||||
|         "usage: %s COMMAND ARGS\n" | ||||
|         "\n" | ||||
|         "commands:\n" | ||||
|         "    start ClassName InstanceName Args...\n" | ||||
|         "    stop InstanceName\n" | ||||
|         "    list\n" | ||||
|         "    info\n", | ||||
|         PROGNAME); | ||||
| } | ||||
|  | ||||
| static void report(PWSTR PipeBuf, ULONG PipeBufSize) | ||||
| { | ||||
|     if (0 == PipeBufSize) | ||||
|         warn("KO received empty buffer from launcher"); | ||||
|     else if (L'$' == PipeBuf[0]) | ||||
|     { | ||||
|         if (1 == PipeBufSize) | ||||
|             warn("OK"); | ||||
|         else | ||||
|         { | ||||
|             for (PWSTR P = PipeBuf, PipeBufEnd = P + PipeBufSize / sizeof(WCHAR); PipeBufEnd > P; P++) | ||||
|                 if (L'\0' == *P) | ||||
|                     *P = L'\n'; | ||||
|  | ||||
|             if (PipeBufSize < PIPE_BUFFER_SIZE) | ||||
|                 PipeBuf[PipeBufSize / sizeof(WCHAR)] = L'\0'; | ||||
|             else | ||||
|                 PipeBuf[PIPE_BUFFER_SIZE / sizeof(WCHAR) - 1] = L'\0'; | ||||
|  | ||||
|             warn("OK\n%S", PipeBuf + 1); | ||||
|         } | ||||
|     } | ||||
|     else if (L'!' == PipeBuf[0]) | ||||
|     { | ||||
|         if (PipeBufSize < PIPE_BUFFER_SIZE) | ||||
|             PipeBuf[PipeBufSize / sizeof(WCHAR)] = L'\0'; | ||||
|         else | ||||
|             PipeBuf[PIPE_BUFFER_SIZE / sizeof(WCHAR) - 1] = L'\0'; | ||||
|  | ||||
|         warn("KO %S", PipeBuf + 1); | ||||
|     } | ||||
|     else  | ||||
|         warn("KO received corrupted buffer from launcher", 0); | ||||
| } | ||||
|  | ||||
| int start(PWSTR PipeBuf, ULONG PipeBufSize, | ||||
|     PWSTR ClassName, PWSTR InstanceName, DWORD Argc, PWSTR *Argv) | ||||
| { | ||||
|     PWSTR P; | ||||
|     DWORD ClassNameSize, InstanceNameSize, ArgvSize; | ||||
|     DWORD LastError, BytesTransferred; | ||||
|  | ||||
|     ClassNameSize = lstrlenW(ClassName) + 1; | ||||
|     InstanceNameSize = lstrlenW(InstanceName) + 1; | ||||
|     ArgvSize = 0; | ||||
|     for (DWORD Argi = Argc; Argc > Argi; Argi++) | ||||
|         ArgvSize += lstrlenW(Argv[Argi]); | ||||
|  | ||||
|     if (PipeBufSize < (1 + ClassNameSize + InstanceNameSize + ArgvSize) * sizeof(WCHAR)) | ||||
|         return ERROR_INVALID_PARAMETER; | ||||
|  | ||||
|     P = PipeBuf; | ||||
|     *P++ = LauncherSvcInstanceStart; | ||||
|     memcpy(P, ClassName, ClassNameSize * sizeof(WCHAR)); P += ClassNameSize; | ||||
|     memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); P += InstanceNameSize; | ||||
|     for (DWORD Argi = Argc; Argc > Argi; Argi++) | ||||
|     { | ||||
|         ArgvSize = lstrlenW(Argv[Argi]); | ||||
|         memcpy(P, Argv[Argi], ArgvSize * sizeof(WCHAR)); P += ArgvSize; | ||||
|     } | ||||
|  | ||||
|     if (CallNamedPipeW(L"" PIPE_NAME, | ||||
|         PipeBuf, (DWORD)((P - PipeBuf) * sizeof(WCHAR)), PipeBuf, PipeBufSize, | ||||
|         &BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT)) | ||||
|     { | ||||
|         LastError = 0; | ||||
|         report(PipeBuf, BytesTransferred); | ||||
|     } | ||||
|     else | ||||
|         LastError = GetLastError(); | ||||
|  | ||||
|     return LastError; | ||||
| } | ||||
|  | ||||
| int stop(PWSTR PipeBuf, ULONG PipeBufSize, | ||||
|     PWSTR InstanceName) | ||||
| { | ||||
|     PWSTR P; | ||||
|     DWORD InstanceNameSize; | ||||
|     DWORD LastError, BytesTransferred; | ||||
|  | ||||
|     InstanceNameSize = lstrlenW(InstanceName) + 1; | ||||
|  | ||||
|     if (PipeBufSize < (1 + InstanceNameSize) * sizeof(WCHAR)) | ||||
|         return ERROR_INVALID_PARAMETER; | ||||
|  | ||||
|     P = PipeBuf; | ||||
|     *P++ = LauncherSvcInstanceStop; | ||||
|     memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); | ||||
|  | ||||
|     if (CallNamedPipeW(L"" PIPE_NAME, | ||||
|         PipeBuf, (DWORD)((P - PipeBuf) * sizeof(WCHAR)), PipeBuf, PipeBufSize, | ||||
|         &BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT)) | ||||
|     { | ||||
|         LastError = 0; | ||||
|         report(PipeBuf, BytesTransferred); | ||||
|     } | ||||
|     else | ||||
|         LastError = GetLastError(); | ||||
|  | ||||
|     return LastError; | ||||
| } | ||||
|  | ||||
| int list(PWSTR PipeBuf, ULONG PipeBufSize) | ||||
| { | ||||
|     PWSTR P; | ||||
|     DWORD LastError, BytesTransferred; | ||||
|  | ||||
|     if (PipeBufSize < 1 * sizeof(WCHAR)) | ||||
|         return ERROR_INVALID_PARAMETER; | ||||
|  | ||||
|     P = PipeBuf; | ||||
|     *P++ = LauncherSvcInstanceList; | ||||
|  | ||||
|     if (CallNamedPipeW(L"" PIPE_NAME, | ||||
|         PipeBuf, (DWORD)((P - PipeBuf) * sizeof(WCHAR)), PipeBuf, PipeBufSize, | ||||
|         &BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT)) | ||||
|     { | ||||
|         LastError = 0; | ||||
|         report(PipeBuf, BytesTransferred); | ||||
|     } | ||||
|     else | ||||
|         LastError = GetLastError(); | ||||
|  | ||||
|     return LastError; | ||||
| } | ||||
|  | ||||
| int info(PWSTR PipeBuf, ULONG PipeBufSize, | ||||
|     PWSTR InstanceName) | ||||
| { | ||||
|     PWSTR P; | ||||
|     DWORD InstanceNameSize; | ||||
|     DWORD LastError, BytesTransferred; | ||||
|  | ||||
|     InstanceNameSize = lstrlenW(InstanceName) + 1; | ||||
|  | ||||
|     if (PipeBufSize < (1 + InstanceNameSize) * sizeof(WCHAR)) | ||||
|         return ERROR_INVALID_PARAMETER; | ||||
|  | ||||
|     P = PipeBuf; | ||||
|     *P++ = LauncherSvcInstanceInfo; | ||||
|     memcpy(P, InstanceName, InstanceNameSize * sizeof(WCHAR)); | ||||
|  | ||||
|     if (CallNamedPipeW(L"" PIPE_NAME, | ||||
|         PipeBuf, (DWORD)((P - PipeBuf) * sizeof(WCHAR)), PipeBuf, PipeBufSize, | ||||
|         &BytesTransferred, NMPWAIT_USE_DEFAULT_WAIT)) | ||||
|     { | ||||
|         LastError = 0; | ||||
|         report(PipeBuf, BytesTransferred); | ||||
|     } | ||||
|     else | ||||
|         LastError = GetLastError(); | ||||
|  | ||||
|     return LastError; | ||||
| } | ||||
|  | ||||
| int wmain(int argc, wchar_t **argv) | ||||
| { | ||||
|     PWSTR PipeBuf = 0; | ||||
|  | ||||
|     /* allocate our PipeBuf early on; freed on process exit by the system */ | ||||
|     PipeBuf = MemAlloc(PIPE_BUFFER_SIZE); | ||||
|     if (0 == PipeBuf) | ||||
|         return ERROR_NO_SYSTEM_RESOURCES; | ||||
|  | ||||
|     argc--; | ||||
|     argv++; | ||||
|  | ||||
|     if (0 == argc) | ||||
|         usage(); | ||||
|  | ||||
|     if (0 == lstrcmp(L"start", argv[0])) | ||||
|     { | ||||
|         if (3 > argc || argc > 12) | ||||
|             usage(); | ||||
|  | ||||
|         return start(PipeBuf, PIPE_BUFFER_SIZE, argv[1], argv[2], argc - 3, argv + 3); | ||||
|     } | ||||
|     else | ||||
|     if (0 == lstrcmp(L"stop", argv[0])) | ||||
|     { | ||||
|         if (2 != argc) | ||||
|             usage(); | ||||
|  | ||||
|         return stop(PipeBuf, PIPE_BUFFER_SIZE, argv[1]); | ||||
|     } | ||||
|     if (0 == lstrcmp(L"list", argv[0])) | ||||
|     { | ||||
|         if (1 != argc) | ||||
|             usage(); | ||||
|  | ||||
|         return list(PipeBuf, PIPE_BUFFER_SIZE); | ||||
|     } | ||||
|     if (0 == lstrcmp(L"info", argv[0])) | ||||
|     { | ||||
|         if (2 != argc) | ||||
|             usage(); | ||||
|  | ||||
|         return info(PipeBuf, PIPE_BUFFER_SIZE, argv[1]); | ||||
|     } | ||||
|     else | ||||
|         usage(); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int wmainCRTStartup(void) | ||||
| void wmainCRTStartup(void) | ||||
| { | ||||
|     return wmain(0, 0); | ||||
|     DWORD Argc; | ||||
|     PWSTR *Argv; | ||||
|  | ||||
|     extern HANDLE ProcessHeap; | ||||
|     ProcessHeap = GetProcessHeap(); | ||||
|     if (0 == ProcessHeap) | ||||
|         ExitProcess(GetLastError()); | ||||
|  | ||||
|     Argv = CommandLineToArgvW(GetCommandLineW(), &Argc); | ||||
|     if (0 == Argv) | ||||
|         ExitProcess(GetLastError()); | ||||
|  | ||||
|     ExitProcess(wmain(Argc, Argv)); | ||||
| } | ||||
|  | ||||
| HANDLE ProcessHeap; | ||||
|   | ||||
| @@ -20,8 +20,6 @@ | ||||
| #define PROGNAME                        "WinFsp-Launcher" | ||||
| #define REGKEY                          "SYSTEM\\CurrentControlSet\\Services\\" PROGNAME "\\Services" | ||||
|  | ||||
| HANDLE ProcessHeap; | ||||
|  | ||||
| typedef struct | ||||
| { | ||||
|     PWSTR ClassName; | ||||
| @@ -367,7 +365,7 @@ static NTSTATUS SvcStart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) | ||||
|         PIPE_ACCESS_DUPLEX | | ||||
|             FILE_FLAG_FIRST_PIPE_INSTANCE | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, | ||||
|         PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS, | ||||
|         1, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, 0, 0); | ||||
|         1, PIPE_BUFFER_SIZE, PIPE_BUFFER_SIZE, PIPE_DEFAULT_TIMEOUT, 0); | ||||
|     if (INVALID_HANDLE_VALUE == SvcPipe) | ||||
|         goto fail; | ||||
|  | ||||
| @@ -630,13 +628,17 @@ static VOID SvcPipeTransact(PWSTR PipeBuf, PULONG PSize) | ||||
|  | ||||
| int wmain(int argc, wchar_t **argv) | ||||
| { | ||||
|     ProcessHeap = GetProcessHeap(); | ||||
|     if (0 == ProcessHeap) | ||||
|         return GetLastError(); | ||||
|     return FspServiceRun(L"" PROGNAME, SvcStart, SvcStop, 0); | ||||
| } | ||||
|  | ||||
| int wmainCRTStartup(void) | ||||
| void wmainCRTStartup(void) | ||||
| { | ||||
|     return wmain(0, 0); | ||||
|     extern HANDLE ProcessHeap; | ||||
|     ProcessHeap = GetProcessHeap(); | ||||
|     if (0 == ProcessHeap) | ||||
|         ExitProcess(GetLastError()); | ||||
|  | ||||
|     ExitProcess(wmain(0, 0)); | ||||
| } | ||||
|  | ||||
| HANDLE ProcessHeap; | ||||
|   | ||||
| @@ -23,6 +23,7 @@ | ||||
|  | ||||
| #define PIPE_NAME                       "\\\\.\\pipe\\WinFsp.{14E7137D-22B4-437A-B0C1-D21D1BDF3767}" | ||||
| #define PIPE_BUFFER_SIZE                2048 | ||||
| #define PIPE_DEFAULT_TIMEOUT            3000 | ||||
|  | ||||
| enum | ||||
| { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user