timeout_watchdog_w32.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. This file is part of GNUnet
  3. (C) 2010 Christian Grothoff (and other contributing authors)
  4. GNUnet is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published
  6. by the Free Software Foundation; either version 3, or (at your
  7. option) any later version.
  8. GNUnet is distributed in the hope that it will be useful, but
  9. WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with GNUnet; see the file COPYING. If not, write to the
  14. Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  15. Boston, MA 02111-1307, USA.
  16. */
  17. /**
  18. * @file contrib/timeout_watchdog_w32.c
  19. * @brief small tool starting a child process, waiting that it terminates or killing it after a given timeout period
  20. * @author LRN
  21. */
  22. #include <windows.h>
  23. #include <sys/types.h>
  24. #include <stdio.h>
  25. int
  26. main (int argc, char *argv[])
  27. {
  28. int i;
  29. DWORD wait_result;
  30. wchar_t *commandline;
  31. wchar_t **wargv;
  32. wchar_t *arg;
  33. unsigned int cmdlen;
  34. STARTUPINFOW start;
  35. PROCESS_INFORMATION proc;
  36. wchar_t wpath[MAX_PATH + 1];
  37. wchar_t *pathbuf;
  38. DWORD pathbuf_len, alloc_len;
  39. wchar_t *ptr;
  40. wchar_t *non_const_filename;
  41. wchar_t *wcmd;
  42. int wargc;
  43. int timeout = 0;
  44. ssize_t wrote;
  45. HANDLE job;
  46. if (argc < 3)
  47. {
  48. printf
  49. ("arg 1: timeout in sec., arg 2: executable, arg<n> arguments\n");
  50. exit (1);
  51. }
  52. timeout = atoi (argv[1]);
  53. if (timeout == 0)
  54. timeout = 600;
  55. commandline = GetCommandLineW ();
  56. if (commandline == NULL)
  57. {
  58. printf ("Failed to get commandline: %lu\n", GetLastError ());
  59. exit (2);
  60. }
  61. wargv = CommandLineToArgvW (commandline, &wargc);
  62. if (wargv == NULL || wargc <= 1)
  63. {
  64. printf ("Failed to get parse commandline: %lu\n", GetLastError ());
  65. exit (3);
  66. }
  67. job = CreateJobObject (NULL, NULL);
  68. if (job == NULL)
  69. {
  70. printf ("Failed to create a job: %lu\n", GetLastError ());
  71. exit (4);
  72. }
  73. pathbuf_len = GetEnvironmentVariableW (L"PATH", (wchar_t *) &pathbuf, 0);
  74. alloc_len = pathbuf_len + 1;
  75. pathbuf = malloc (alloc_len * sizeof (wchar_t));
  76. ptr = pathbuf;
  77. alloc_len = GetEnvironmentVariableW (L"PATH", ptr, pathbuf_len);
  78. cmdlen = wcslen (wargv[2]);
  79. if (cmdlen < 5 || wcscmp (&wargv[2][cmdlen - 4], L".exe") != 0)
  80. {
  81. non_const_filename = malloc (sizeof (wchar_t) * (cmdlen + 5));
  82. swprintf (non_const_filename, cmdlen + 5, L"%S.exe", wargv[2]);
  83. }
  84. else
  85. {
  86. non_const_filename = wcsdup (wargv[2]);
  87. }
  88. /* Check that this is the full path. If it isn't, search. */
  89. if (non_const_filename[1] == L':')
  90. swprintf (wpath, sizeof (wpath) / sizeof (wchar_t), L"%S", non_const_filename);
  91. else if (!SearchPathW
  92. (pathbuf, non_const_filename, NULL, sizeof (wpath) / sizeof (wchar_t),
  93. wpath, NULL))
  94. {
  95. printf ("Failed to get find executable: %lu\n", GetLastError ());
  96. exit (5);
  97. }
  98. free (pathbuf);
  99. free (non_const_filename);
  100. cmdlen = wcslen (wpath) + 4;
  101. i = 3;
  102. while (NULL != (arg = wargv[i++]))
  103. cmdlen += wcslen (arg) + 4;
  104. wcmd = malloc (sizeof (wchar_t) * (cmdlen + 1));
  105. wrote = 0;
  106. i = 2;
  107. while (NULL != (arg = wargv[i++]))
  108. {
  109. /* This is to escape trailing slash */
  110. wchar_t arg_lastchar = arg[wcslen (arg) - 1];
  111. if (wrote == 0)
  112. {
  113. wrote += swprintf (&wcmd[wrote], cmdlen + 1 - wrote, L"\"%S%S\" ", wpath,
  114. arg_lastchar == L'\\' ? L"\\" : L"");
  115. }
  116. else
  117. {
  118. if (wcschr (arg, L' ') != NULL)
  119. wrote += swprintf (&wcmd[wrote], cmdlen + 1 - wrote, L"\"%S%S\"%S", arg,
  120. arg_lastchar == L'\\' ? L"\\" : L"", i == wargc ? L"" : L" ");
  121. else
  122. wrote += swprintf (&wcmd[wrote], cmdlen + 1 - wrote, L"%S%S%S", arg,
  123. arg_lastchar == L'\\' ? L"\\" : L"", i == wargc ? L"" : L" ");
  124. }
  125. }
  126. LocalFree (wargv);
  127. memset (&start, 0, sizeof (start));
  128. start.cb = sizeof (start);
  129. if (!CreateProcessW (wpath, wcmd, NULL, NULL, TRUE, CREATE_SUSPENDED,
  130. NULL, NULL, &start, &proc))
  131. {
  132. wprintf (L"Failed to get spawn process `%S' with arguments `%S': %lu\n", wpath, wcmd, GetLastError ());
  133. exit (6);
  134. }
  135. AssignProcessToJobObject (job, proc.hProcess);
  136. ResumeThread (proc.hThread);
  137. CloseHandle (proc.hThread);
  138. free (wcmd);
  139. wait_result = WaitForSingleObject (proc.hProcess, timeout * 1000);
  140. if (wait_result == WAIT_OBJECT_0)
  141. {
  142. DWORD status;
  143. wait_result = GetExitCodeProcess (proc.hProcess, &status);
  144. CloseHandle (proc.hProcess);
  145. if (wait_result != 0)
  146. {
  147. printf ("Test process exited with result %lu\n", status);
  148. TerminateJobObject (job, status);
  149. exit (status);
  150. }
  151. printf ("Test process exited (failed to obtain exit status)\n");
  152. TerminateJobObject (job, 0);
  153. exit (0);
  154. }
  155. printf ("Child processes were killed after timeout of %u seconds\n",
  156. timeout);
  157. TerminateJobObject (job, 1);
  158. CloseHandle (proc.hProcess);
  159. exit (1);
  160. }
  161. /* end of timeout_watchdog_w32.c */