/*
This file is part of GNUnet
Copyright (C) 2010 GNUnet e.V.
GNUnet is free software: you can redistribute it and/or modify it
under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
GNUnet is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see .
SPDX-License-Identifier: AGPL3.0-or-later
*/
/**
* @file src/util/gnunet-timeout-w32.c
* @brief small tool starting a child process, waiting that it terminates or killing it after a given timeout period
* @author LRN
*/
#include
#include
#include
int
main (int argc, char *argv[])
{
int i;
DWORD wait_result;
wchar_t *commandline;
wchar_t **wargv;
wchar_t *arg;
unsigned int cmdlen;
STARTUPINFOW start;
PROCESS_INFORMATION proc;
wchar_t wpath[MAX_PATH + 1];
wchar_t *pathbuf;
DWORD pathbuf_len, alloc_len;
wchar_t *ptr;
wchar_t *non_const_filename;
wchar_t *wcmd;
int wargc;
int timeout = 0;
ssize_t wrote;
HANDLE job;
if (argc < 3)
{
printf
("arg 1: timeout in sec., arg 2: executable, arg arguments\n");
exit (1);
}
timeout = atoi (argv[1]);
if (timeout == 0)
timeout = 600;
commandline = GetCommandLineW ();
if (commandline == NULL)
{
printf ("Failed to get commandline: %lu\n", GetLastError ());
exit (2);
}
wargv = CommandLineToArgvW (commandline, &wargc);
if (wargv == NULL || wargc <= 1)
{
printf ("Failed to get parse commandline: %lu\n", GetLastError ());
exit (3);
}
job = CreateJobObject (NULL, NULL);
if (job == NULL)
{
printf ("Failed to create a job: %lu\n", GetLastError ());
exit (4);
}
pathbuf_len = GetEnvironmentVariableW (L"PATH", (wchar_t *) &pathbuf, 0);
alloc_len = pathbuf_len + 1;
pathbuf = malloc (alloc_len * sizeof (wchar_t));
ptr = pathbuf;
alloc_len = GetEnvironmentVariableW (L"PATH", ptr, pathbuf_len);
cmdlen = wcslen (wargv[2]);
if (cmdlen < 5 || wcscmp (&wargv[2][cmdlen - 4], L".exe") != 0)
{
non_const_filename = malloc (sizeof (wchar_t) * (cmdlen + 5));
swprintf (non_const_filename, cmdlen + 5, L"%S.exe", wargv[2]);
}
else
{
non_const_filename = wcsdup (wargv[2]);
}
/* Check that this is the full path. If it isn't, search. */
if (non_const_filename[1] == L':')
swprintf (wpath, sizeof (wpath) / sizeof (wchar_t), L"%S", non_const_filename);
else if (!SearchPathW
(pathbuf, non_const_filename, NULL, sizeof (wpath) / sizeof (wchar_t),
wpath, NULL))
{
printf ("Failed to get find executable: %lu\n", GetLastError ());
exit (5);
}
free (pathbuf);
free (non_const_filename);
cmdlen = wcslen (wpath) + 4;
i = 3;
while (NULL != (arg = wargv[i++]))
cmdlen += wcslen (arg) + 4;
wcmd = malloc (sizeof (wchar_t) * (cmdlen + 1));
wrote = 0;
i = 2;
while (NULL != (arg = wargv[i++]))
{
/* This is to escape trailing slash */
wchar_t arg_lastchar = arg[wcslen (arg) - 1];
if (wrote == 0)
{
wrote += swprintf (&wcmd[wrote], cmdlen + 1 - wrote, L"\"%S%S\" ", wpath,
arg_lastchar == L'\\' ? L"\\" : L"");
}
else
{
if (wcschr (arg, L' ') != NULL)
wrote += swprintf (&wcmd[wrote], cmdlen + 1 - wrote, L"\"%S%S\"%S", arg,
arg_lastchar == L'\\' ? L"\\" : L"", i == wargc ? L"" : L" ");
else
wrote += swprintf (&wcmd[wrote], cmdlen + 1 - wrote, L"%S%S%S", arg,
arg_lastchar == L'\\' ? L"\\" : L"", i == wargc ? L"" : L" ");
}
}
LocalFree (wargv);
memset (&start, 0, sizeof (start));
start.cb = sizeof (start);
if (!CreateProcessW (wpath, wcmd, NULL, NULL, TRUE, CREATE_SUSPENDED,
NULL, NULL, &start, &proc))
{
wprintf (L"Failed to get spawn process `%S' with arguments `%S': %lu\n", wpath, wcmd, GetLastError ());
exit (6);
}
AssignProcessToJobObject (job, proc.hProcess);
ResumeThread (proc.hThread);
CloseHandle (proc.hThread);
free (wcmd);
wait_result = WaitForSingleObject (proc.hProcess, timeout * 1000);
if (wait_result == WAIT_OBJECT_0)
{
DWORD status;
wait_result = GetExitCodeProcess (proc.hProcess, &status);
CloseHandle (proc.hProcess);
if (wait_result != 0)
{
printf ("Test process exited with result %lu\n", status);
TerminateJobObject (job, status);
exit (status);
}
printf ("Test process exited (failed to obtain exit status)\n");
TerminateJobObject (job, 0);
exit (0);
}
printf ("Child processes were killed after timeout of %u seconds\n",
timeout);
TerminateJobObject (job, 1);
CloseHandle (proc.hProcess);
exit (1);
}
/* end of timeout_watchdog_w32.c */