[platform] a new restarter for Windows, with logging and wide characters

reference: ZD-830892
This commit is contained in:
Roman Shevchenko
2016-12-30 15:58:56 +01:00
parent 3869afcf2e
commit afd69323ea
3 changed files with 155 additions and 0 deletions
+10
View File
@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.1)
project(WinRestarter)
if (NOT WIN32)
message(FATAL_ERROR "Windows only.")
endif ()
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT")
add_executable(restarter restarter.c)
+13
View File
@@ -0,0 +1,13 @@
@ECHO OFF
SET BUILD_DIR=build32
SET CMAKE=%CMAKE_PATH%\bin\cmake
IF EXIST "%BUILD_DIR%" RMDIR /S /Q "%BUILD_DIR%"
MKDIR "%BUILD_DIR%" & CD "%BUILD_DIR%"
"%CMAKE%" -G "Visual Studio 12 2013" -T v120_xp -A win32 ..
IF ERRORLEVEL 1 EXIT 1
"%CMAKE%" --build . --config Release
IF ERRORLEVEL 1 EXIT 2
+132
View File
@@ -0,0 +1,132 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
#include <windows.h>
#define PROVIDER_NAME L"JB-Restarter"
#define ERR_OPEN_PROCESS (0xE0000000 + 1)
#define ERR_COMMAND_TOO_LONG (0xE0000000 + 2)
#define ERR_CREATE_PROCESS (0xE0000000 + 3)
#define ERR_GET_EXIT_CODE (0xE0000000 + 4)
#define WARN_COMMAND_FAILED (0x80000000 + 11)
#define COMMAND_SIZE 32768
#define MESSAGE_SIZE (COMMAND_SIZE + 1024)
static HANDLE event_log = NULL;
static void log_event(unsigned int event_id, const char *format, ...);
static void wait_for_parent(const wchar_t *pid_arg);
static void run_command(int cmd_argc, wchar_t *argv[], BOOL last);
int wmain(int argc, wchar_t *argv[]) {
if (argc < 3) {
printf("usage: %ls <pid> (n_args args ...)+\n", argv[0]);
return 0;
}
event_log = RegisterEventSourceW(NULL, PROVIDER_NAME);
wait_for_parent(argv[1]);
int arg_index = 2;
while (arg_index < argc - 1) {
int cmd_argc = (int)wcstol(argv[arg_index++], NULL, 10);
if (cmd_argc > 0) {
wchar_t **cmd_argv = argv + arg_index;
arg_index += cmd_argc;
run_command(cmd_argc, cmd_argv, arg_index >= argc - 1);
}
}
if (event_log != NULL) {
DeregisterEventSource(event_log);
}
return 0;
}
static void wait_for_parent(const wchar_t *pid_arg) {
int pid = (int)wcstol(pid_arg, NULL, 10);
HANDLE parent = OpenProcess(SYNCHRONIZE, FALSE, pid);
if (parent == NULL) {
log_event(ERR_OPEN_PROCESS, "OpenProcess(%d): %d", pid, (int)GetLastError());
return;
}
WaitForSingleObject(parent, INFINITE);
CloseHandle(parent);
}
static void run_command(int cmd_argc, wchar_t *cmd_argv[], BOOL last) {
wchar_t cmd_line[COMMAND_SIZE], *p = cmd_line;
for (int i = 0; i < cmd_argc; i++) {
wchar_t *arg = cmd_argv[i];
int arg_len = wcslen(arg);
BOOL space = wcschr(arg, L' ') != NULL;
if (space) *p++ = L'"';
if (wcscpy_s(p, COMMAND_SIZE - (p - cmd_line), arg) != 0) {
*p = L'\0';
log_event(ERR_COMMAND_TOO_LONG, "[%ls %ls ...]", cmd_line, arg);
return;
} else {
p += arg_len;
}
if (space) *p++ = L'"';
*p++ = i < cmd_argc - 1 ? L' ' : L'\0';
}
STARTUPINFOW si = {0};
PROCESS_INFORMATION pi = {0};
if (!CreateProcessW(NULL, cmd_line, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
log_event(ERR_CREATE_PROCESS, "CreateProcess(%ls): %d", cmd_line, (int)GetLastError());
return;
}
if (!last) {
WaitForSingleObject(pi.hProcess, INFINITE);
DWORD ec;
if (!GetExitCodeProcess(pi.hProcess, &ec)) {
log_event(ERR_GET_EXIT_CODE, "GetExitCode: %d", (int)GetLastError());
} else if (ec != 0) {
log_event(WARN_COMMAND_FAILED, "[%ls]: %d", cmd_line, (int)ec);
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
}
}
static void log_event(unsigned int event_id, const char *format, ...) {
va_list ap;
va_start(ap, format);
if (event_log != NULL) {
int severity = event_id >> 30;
WORD type = severity == 3 ? EVENTLOG_ERROR_TYPE : severity == 2 ? EVENTLOG_WARNING_TYPE : EVENTLOG_INFORMATION_TYPE;
char message[MESSAGE_SIZE];
int n = vsnprintf(message, MESSAGE_SIZE, format, ap);
ReportEventW(event_log, type, 0, event_id, NULL, 0, n, NULL, message);
}
va_end(ap);
}