launchctl: implementation

This commit is contained in:
Bill Zissimopoulos 2016-05-11 17:40:49 -07:00
parent 9ae28a5529
commit ec21e830f1
3 changed files with 269 additions and 10 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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
{