win-pvdrivers

view shutdownmon/shutdownmon.c @ 846:1b1fde762e0c

Fix a bug in scsiport crash dump / hibernate
author James Harper <james.harper@bendigoit.com.au>
date Wed Feb 09 13:33:45 2011 +1100 (2011-02-09)
parents 5bdb7251370c
children 8f483a2b2991
line source
1 #pragma warning(disable: 4201)
2 #include <windows.h>
3 #include <basetyps.h>
4 #include <stdlib.h>
5 #include <wtypes.h>
6 #include <initguid.h>
7 #include <stdio.h>
8 #include <string.h>
9 #include <winioctl.h>
10 #include <setupapi.h>
11 #include <ctype.h>
12 #include <powrprof.h>
13 #include <strsafe.h>
15 #define SERVICE_ID "ShutdownMon"
16 #define SERVICE_NAME "Xen Shutdown Monitor"
18 #define OLD_SERVICE_ID "XenShutdownMon"
20 DEFINE_GUID(GUID_XENBUS_IFACE, 0x14ce175a, 0x3ee2, 0x4fae, 0x92, 0x52, 0x0, 0xdb, 0xd8, 0x4f, 0x1, 0x8e);
22 enum xsd_sockmsg_type
23 {
24 XS_DEBUG,
25 XS_DIRECTORY,
26 XS_READ,
27 XS_GET_PERMS,
28 XS_WATCH,
29 XS_UNWATCH,
30 XS_TRANSACTION_START,
31 XS_TRANSACTION_END,
32 XS_INTRODUCE,
33 XS_RELEASE,
34 XS_GET_DOMAIN_PATH,
35 XS_WRITE,
36 XS_MKDIR,
37 XS_RM,
38 XS_SET_PERMS,
39 XS_WATCH_EVENT,
40 XS_ERROR,
41 XS_IS_DOMAIN_INTRODUCED,
42 XS_RESUME,
43 XS_SET_TARGET
44 };
46 struct xsd_sockmsg
47 {
48 ULONG type; /* XS_??? */
49 ULONG req_id;/* Request identifier, echoed in daemon's response. */
50 ULONG tx_id; /* Transaction id (0 if not related to a transaction). */
51 ULONG len; /* Length of data following this. */
53 /* Generally followed by nul-terminated string(s). */
54 };
55 SERVICE_STATUS service_status;
56 SERVICE_STATUS_HANDLE hStatus;
58 static void
59 install_service()
60 {
61 SC_HANDLE manager_handle;
62 SC_HANDLE service_handle;
63 TCHAR path[MAX_PATH];
64 TCHAR command_line[MAX_PATH + 10];
66 if(!GetModuleFileName(NULL, path, MAX_PATH))
67 {
68 printf("Cannot install service (%d)\n", GetLastError());
69 return;
70 }
72 StringCbPrintf(command_line, MAX_PATH + 10, "\"%s\" -s", path);
73 manager_handle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
75 if (!manager_handle)
76 {
77 printf("OpenSCManager failed (%d)\n", GetLastError());
78 return;
79 }
81 service_handle = CreateService(
82 manager_handle, SERVICE_ID, SERVICE_NAME, SERVICE_ALL_ACCESS,
83 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
84 SERVICE_ERROR_NORMAL, command_line, NULL, NULL, NULL, NULL, NULL);
86 if (!service_handle)
87 {
88 printf("CreateService failed (%d)\n", GetLastError());
89 CloseServiceHandle(manager_handle);
90 return;
91 }
93 printf("Service installed\n");
95 CloseServiceHandle(service_handle);
96 CloseServiceHandle(manager_handle);
97 }
99 static void
100 remove_old_service()
101 {
102 SC_HANDLE manager_handle;
103 SC_HANDLE service_handle;
105 manager_handle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
107 if (!manager_handle)
108 {
109 printf("OpenSCManager failed (%d)\n", GetLastError());
110 return;
111 }
113 service_handle = OpenService(manager_handle, OLD_SERVICE_ID, DELETE);
115 if (!service_handle)
116 {
117 printf("OpenService failed (%d)\n", GetLastError());
118 CloseServiceHandle(manager_handle);
119 return;
120 }
122 if (!DeleteService(service_handle))
123 {
124 printf("DeleteService failed (%d)\n", GetLastError());
125 CloseServiceHandle(service_handle);
126 CloseServiceHandle(manager_handle);
127 return;
128 }
130 printf("Old Service removed\n");
132 CloseServiceHandle(service_handle);
133 CloseServiceHandle(manager_handle);
134 }
136 static void
137 remove_service()
138 {
139 SC_HANDLE manager_handle;
140 SC_HANDLE service_handle;
142 manager_handle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
144 if (!manager_handle)
145 {
146 printf("OpenSCManager failed (%d)\n", GetLastError());
147 return;
148 }
150 service_handle = OpenService(manager_handle, SERVICE_ID, DELETE);
152 if (!service_handle)
153 {
154 printf("OpenService failed (%d)\n", GetLastError());
155 CloseServiceHandle(manager_handle);
156 return;
157 }
159 if (!DeleteService(service_handle))
160 {
161 printf("DeleteService failed (%d)\n", GetLastError());
162 CloseServiceHandle(service_handle);
163 CloseServiceHandle(manager_handle);
164 return;
165 }
167 printf("Service removed\n");
169 CloseServiceHandle(service_handle);
170 CloseServiceHandle(manager_handle);
171 }
173 static void
174 do_hibernate()
175 {
176 HANDLE proc_handle = GetCurrentProcess();
177 TOKEN_PRIVILEGES *tp;
178 HANDLE token_handle;
180 printf("proc_handle = %p\n", proc_handle);
182 if (!OpenProcessToken(proc_handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
183 {
184 printf("OpenProcessToken failed\n");
185 return;
186 }
187 printf("token_handle = %p\n", token_handle);
189 tp = malloc(sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES));
190 tp->PrivilegeCount = 1;
191 if (!LookupPrivilegeValueA(NULL, SE_SHUTDOWN_NAME, &tp->Privileges[0].Luid))
192 {
193 printf("LookupPrivilegeValue failed\n");
194 CloseHandle(token_handle);
195 return;
196 }
198 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
199 if (!AdjustTokenPrivileges(token_handle, FALSE, tp, 0, NULL, NULL))
200 {
201 CloseHandle(token_handle);
202 return;
203 }
205 if (!SetSuspendState(TRUE, FALSE, FALSE))
206 {
207 printf("hibernate failed\n");
208 }
210 CloseHandle(token_handle);
211 }
213 static void
214 do_shutdown(BOOL bRebootAfterShutdown)
215 {
216 HANDLE proc_handle = GetCurrentProcess();
217 TOKEN_PRIVILEGES *tp;
218 HANDLE token_handle;
220 printf("proc_handle = %p\n", proc_handle);
222 if (!OpenProcessToken(proc_handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
223 {
224 printf("OpenProcessToken failed\n");
225 return;
226 }
227 printf("token_handle = %p\n", token_handle);
229 tp = malloc(sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES));
230 tp->PrivilegeCount = 1;
231 if (!LookupPrivilegeValueA(NULL, SE_SHUTDOWN_NAME, &tp->Privileges[0].Luid))
232 {
233 printf("LookupPrivilegeValue failed\n");
234 CloseHandle(token_handle);
235 return;
236 }
238 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
239 if (!AdjustTokenPrivileges(token_handle, FALSE, tp, 0, NULL, NULL))
240 {
241 CloseHandle(token_handle);
242 return;
243 }
245 if (!InitiateSystemShutdownEx(NULL, NULL, 0, TRUE, bRebootAfterShutdown, SHTDN_REASON_FLAG_PLANNED | SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER))
246 {
247 printf("InitiateSystemShutdownEx failed\n");
248 // Log a message to the system log here about a failed shutdown
249 }
250 printf("InitiateSystemShutdownEx succeeded\n");
252 CloseHandle(token_handle);
253 }
255 static char *
256 get_xen_interface_path()
257 {
258 HDEVINFO handle;
259 SP_DEVICE_INTERFACE_DATA sdid;
260 SP_DEVICE_INTERFACE_DETAIL_DATA *sdidd;
261 DWORD buf_len;
262 char *path;
264 handle = SetupDiGetClassDevs(&GUID_XENBUS_IFACE, 0, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
265 if (handle == INVALID_HANDLE_VALUE)
266 {
267 printf("SetupDiGetClassDevs failed\n");
268 return NULL;
269 }
270 sdid.cbSize = sizeof(sdid);
271 if (!SetupDiEnumDeviceInterfaces(handle, NULL, &GUID_XENBUS_IFACE, 0, &sdid))
272 {
273 printf("SetupDiEnumDeviceInterfaces failed\n");
274 return NULL;
275 }
276 SetupDiGetDeviceInterfaceDetail(handle, &sdid, NULL, 0, &buf_len, NULL);
277 sdidd = malloc(buf_len);
278 sdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
279 if (!SetupDiGetDeviceInterfaceDetail(handle, &sdid, sdidd, buf_len, NULL, NULL))
280 {
281 printf("SetupDiGetDeviceInterfaceDetail failed\n");
282 return NULL;
283 }
285 path = malloc(strlen(sdidd->DevicePath) + 1);
286 StringCbCopyA(path, strlen(sdidd->DevicePath) + 1, sdidd->DevicePath);
287 free(sdidd);
289 return path;
290 }
292 static int
293 xb_add_watch(HANDLE handle, char *path)
294 {
295 char buf[1024];
296 struct xsd_sockmsg *msg;
297 DWORD bytes_written;
298 DWORD bytes_read;
299 char *token = "0";
301 msg = (struct xsd_sockmsg *)buf;
302 msg->type = XS_WATCH;
303 msg->req_id = 0;
304 msg->tx_id = 0;
305 msg->len = (ULONG)(strlen(path) + 1 + strlen(token) + 1);
306 StringCbCopyA(buf + sizeof(*msg), 1024 - sizeof(*msg), path);
307 StringCbCopyA(buf + sizeof(*msg) + strlen(path) + 1, 1024 - sizeof(*msg) - strlen(path) - 1, token);
309 if (!WriteFile(handle, buf, sizeof(*msg) + msg->len, &bytes_written, NULL))
310 {
311 printf("write failed\n");
312 return 0;
313 }
314 if (!ReadFile(handle, buf, 1024, &bytes_read, NULL))
315 {
316 printf("read failed\n");
317 return 0;
318 }
319 printf("bytes_read = %d\n", bytes_read);
320 printf("msg->len = %d\n", msg->len);
321 buf[sizeof(*msg) + msg->len] = 0;
322 printf("msg text = %s\n", buf + sizeof(*msg));
324 return 1;
325 }
327 static int
328 xb_wait_event(HANDLE handle)
329 {
330 char buf[1024];
331 struct xsd_sockmsg *msg;
332 DWORD bytes_read;
334 printf("wait_event start\n");
335 msg = (struct xsd_sockmsg *)buf;
336 if (!ReadFile(handle, buf, 1024, &bytes_read, NULL))
337 {
338 printf("read failed\n");
339 return 0;
340 }
341 printf("bytes_read = %d\n", bytes_read);
342 printf("msg->len = %d\n", msg->len);
343 buf[sizeof(*msg) + msg->len] = 0;
344 printf("msg text = %s\n", buf + sizeof(*msg));
345 return 1;
346 }
348 static char *
349 xb_read(HANDLE handle, char *path)
350 {
351 char buf[1024];
352 struct xsd_sockmsg *msg;
353 char *ret;
354 DWORD bytes_written;
355 DWORD bytes_read;
357 printf("read start\n");
358 msg = (struct xsd_sockmsg *)buf;
359 msg->type = XS_READ;
360 msg->req_id = 0;
361 msg->tx_id = 0;
362 msg->len = (ULONG)(strlen(path) + 1);
363 StringCbCopyA(buf + sizeof(*msg), 1024 - sizeof(*msg), path);
365 if (!WriteFile(handle, buf, sizeof(*msg) + msg->len, &bytes_written, NULL))
366 {
367 printf("write failed\n");
368 return NULL;
369 }
371 if (!ReadFile(handle, buf, 1024, &bytes_read, NULL))
372 {
373 printf("read failed\n");
374 return NULL;
375 }
376 printf("bytes_read = %d\n", bytes_read);
377 printf("msg->len = %d\n", msg->len);
378 buf[sizeof(*msg) + msg->len] = 0;
379 printf("msg text = %s\n", buf + sizeof(*msg));
380 ret = malloc(strlen(buf + sizeof(*msg)) + 1);
381 StringCbCopyA(ret, 1024 - sizeof(*msg), buf + sizeof(*msg));
382 return ret;
383 }
385 static void
386 do_monitoring()
387 {
388 HANDLE handle;
389 int state;
390 char *path;
391 char *buf;
393 path = get_xen_interface_path();
394 if (path == NULL)
395 return;
397 handle = CreateFile(path, FILE_GENERIC_READ|FILE_GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
399 xb_add_watch(handle, "control/shutdown");
401 state = 0;
402 while(xb_wait_event(handle))
403 {
404 if (service_status.dwCurrentState != SERVICE_RUNNING)
405 return;
406 buf = xb_read(handle, "control/shutdown");
408 //printf("msg = '%s'\n", msg);
409 if (strcmp("poweroff", buf) == 0 || strcmp("halt", buf) == 0)
410 {
411 do_shutdown(FALSE);
412 }
413 else if (strcmp("reboot", buf) == 0)
414 {
415 do_shutdown(TRUE);
416 }
417 else if (strcmp("hibernate", buf) == 0)
418 {
419 do_hibernate();
420 }
421 }
422 }
424 void control_handler(DWORD request)
425 {
426 switch(request)
427 {
428 case SERVICE_CONTROL_STOP:
429 service_status.dwWin32ExitCode = 0;
430 service_status.dwCurrentState = SERVICE_STOPPED;
431 SetServiceStatus (hStatus, &service_status);
432 return;
434 case SERVICE_CONTROL_SHUTDOWN:
435 service_status.dwWin32ExitCode = 0;
436 service_status.dwCurrentState = SERVICE_STOPPED;
437 SetServiceStatus (hStatus, &service_status);
438 return;
440 default:
441 break;
442 }
444 SetServiceStatus (hStatus, &service_status);
446 return;
447 }
449 void service_main(int argc, char *argv[])
450 {
451 UNREFERENCED_PARAMETER (argc);
452 UNREFERENCED_PARAMETER (argv);
454 printf("Entering service_main\n");
456 service_status.dwServiceType = SERVICE_WIN32;
457 service_status.dwCurrentState = SERVICE_START_PENDING;
458 service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
459 service_status.dwWin32ExitCode = 0;
460 service_status.dwServiceSpecificExitCode = 0;
461 service_status.dwCheckPoint = 0;
462 service_status.dwWaitHint = 0;
464 hStatus = RegisterServiceCtrlHandler(SERVICE_ID, (LPHANDLER_FUNCTION)control_handler);
465 if (hStatus == (SERVICE_STATUS_HANDLE)0)
466 {
467 printf("RegisterServiceCtrlHandler failed\n");
468 return;
469 }
471 service_status.dwCurrentState = SERVICE_RUNNING;
472 SetServiceStatus(hStatus, &service_status);
474 do_monitoring();
476 printf("All done\n");
478 return;
479 }
482 static void
483 print_usage(char *name)
484 {
485 printf("Usage:\n");
486 printf(" %s <options>\n", name);
487 printf("\n");
488 printf("Options:\n");
489 printf(" -d run in foreground\n");
490 printf(" -s run as service\n");
491 printf(" -i install service\n");
492 printf(" -u uninstall service\n");
493 printf(" -o remove the old .NET service\n");
494 }
496 int __cdecl
497 main(
498 __in ULONG argc,
499 __in_ecount(argc) PCHAR argv[]
500 )
501 {
502 SERVICE_TABLE_ENTRY service_table[2];
504 if (argc == 0)
505 {
506 print_usage("shutdownmon");
507 return 1;
508 }
509 if (argc != 2 || (argc == 2 && (strlen(argv[1]) != 2 || argv[1][0] != '-')))
510 {
511 print_usage(argv[0]);
512 return 1;
513 }
515 switch(argv[1][1])
516 {
517 case 'd':
518 service_status.dwCurrentState = SERVICE_RUNNING;
519 do_monitoring();
520 break;
521 case 's':
522 service_table[0].lpServiceName = SERVICE_ID;
523 service_table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)service_main;
525 service_table[1].lpServiceName = NULL;
526 service_table[1].lpServiceProc = NULL;
528 StartServiceCtrlDispatcher(service_table);
529 break;
530 case 'i':
531 install_service();
532 break;
533 case 'u':
534 remove_service();
535 break;
536 case 'o':
537 remove_old_service();
538 break;
539 default:
540 print_usage(argv[0]);
541 return 1;
542 }
543 return 0;
544 }