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