win-pvdrivers

view shutdownmon/shutdownmon.c @ 623:b79b67b46d0c

Added hibernate response to shutdownmon (need to manually write 'hibernate' to /local/domain/<domid>/control/shutdown)
author James Harper <james.harper@bendigoit.com.au>
date Sat Aug 08 20:55:53 2009 +1000 (2009-08-08)
parents 47fae39bc373
children 5bdb7251370c
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>
14 #define SERVICE_ID "ShutdownMon"
15 #define SERVICE_NAME "Xen Shutdown Monitor"
17 #define OLD_SERVICE_ID "XenShutdownMon"
19 DEFINE_GUID(GUID_XENBUS_IFACE, 0x14ce175a, 0x3ee2, 0x4fae, 0x92, 0x52, 0x0, 0xdb, 0xd8, 0x4f, 0x1, 0x8e);
21 enum xsd_sockmsg_type
22 {
23 XS_DEBUG,
24 XS_DIRECTORY,
25 XS_READ,
26 XS_GET_PERMS,
27 XS_WATCH,
28 XS_UNWATCH,
29 XS_TRANSACTION_START,
30 XS_TRANSACTION_END,
31 XS_INTRODUCE,
32 XS_RELEASE,
33 XS_GET_DOMAIN_PATH,
34 XS_WRITE,
35 XS_MKDIR,
36 XS_RM,
37 XS_SET_PERMS,
38 XS_WATCH_EVENT,
39 XS_ERROR,
40 XS_IS_DOMAIN_INTRODUCED,
41 XS_RESUME,
42 XS_SET_TARGET
43 };
45 struct xsd_sockmsg
46 {
47 ULONG type; /* XS_??? */
48 ULONG req_id;/* Request identifier, echoed in daemon's response. */
49 ULONG tx_id; /* Transaction id (0 if not related to a transaction). */
50 ULONG len; /* Length of data following this. */
52 /* Generally followed by nul-terminated string(s). */
53 };
54 SERVICE_STATUS service_status;
55 SERVICE_STATUS_HANDLE hStatus;
57 static void
58 install_service()
59 {
60 SC_HANDLE manager_handle;
61 SC_HANDLE service_handle;
62 TCHAR path[MAX_PATH];
63 TCHAR command_line[MAX_PATH + 10];
65 if(!GetModuleFileName(NULL, path, MAX_PATH))
66 {
67 printf("Cannot install service (%d)\n", GetLastError());
68 return;
69 }
71 sprintf(command_line, "\"%s\" -s", path);
72 manager_handle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
74 if (!manager_handle)
75 {
76 printf("OpenSCManager failed (%d)\n", GetLastError());
77 return;
78 }
80 service_handle = CreateService(
81 manager_handle, SERVICE_ID, SERVICE_NAME, SERVICE_ALL_ACCESS,
82 SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
83 SERVICE_ERROR_NORMAL, command_line, NULL, NULL, NULL, NULL, NULL);
85 if (!service_handle)
86 {
87 printf("CreateService failed (%d)\n", GetLastError());
88 CloseServiceHandle(manager_handle);
89 return;
90 }
92 printf("Service installed\n");
94 CloseServiceHandle(service_handle);
95 CloseServiceHandle(manager_handle);
96 }
98 static void
99 remove_old_service()
100 {
101 SC_HANDLE manager_handle;
102 SC_HANDLE service_handle;
104 manager_handle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
106 if (!manager_handle)
107 {
108 printf("OpenSCManager failed (%d)\n", GetLastError());
109 return;
110 }
112 service_handle = OpenService(manager_handle, OLD_SERVICE_ID, DELETE);
114 if (!service_handle)
115 {
116 printf("OpenService failed (%d)\n", GetLastError());
117 CloseServiceHandle(manager_handle);
118 return;
119 }
121 if (!DeleteService(service_handle))
122 {
123 printf("DeleteService failed (%d)\n", GetLastError());
124 CloseServiceHandle(service_handle);
125 CloseServiceHandle(manager_handle);
126 return;
127 }
129 printf("Old Service removed\n");
131 CloseServiceHandle(service_handle);
132 CloseServiceHandle(manager_handle);
133 }
135 static void
136 remove_service()
137 {
138 SC_HANDLE manager_handle;
139 SC_HANDLE service_handle;
141 manager_handle = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
143 if (!manager_handle)
144 {
145 printf("OpenSCManager failed (%d)\n", GetLastError());
146 return;
147 }
149 service_handle = OpenService(manager_handle, SERVICE_ID, DELETE);
151 if (!service_handle)
152 {
153 printf("OpenService failed (%d)\n", GetLastError());
154 CloseServiceHandle(manager_handle);
155 return;
156 }
158 if (!DeleteService(service_handle))
159 {
160 printf("DeleteService failed (%d)\n", GetLastError());
161 CloseServiceHandle(service_handle);
162 CloseServiceHandle(manager_handle);
163 return;
164 }
166 printf("Service removed\n");
168 CloseServiceHandle(service_handle);
169 CloseServiceHandle(manager_handle);
170 }
172 static void
173 do_hibernate()
174 {
175 HANDLE proc_handle = GetCurrentProcess();
176 TOKEN_PRIVILEGES *tp;
177 HANDLE token_handle;
179 printf("proc_handle = %p\n", proc_handle);
181 if (!OpenProcessToken(proc_handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
182 {
183 printf("OpenProcessToken failed\n");
184 return;
185 }
186 printf("token_handle = %p\n", token_handle);
188 tp = malloc(sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES));
189 tp->PrivilegeCount = 1;
190 if (!LookupPrivilegeValueA(NULL, SE_SHUTDOWN_NAME, &tp->Privileges[0].Luid))
191 {
192 printf("LookupPrivilegeValue failed\n");
193 CloseHandle(token_handle);
194 return;
195 }
197 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
198 if (!AdjustTokenPrivileges(token_handle, FALSE, tp, 0, NULL, NULL))
199 {
200 CloseHandle(token_handle);
201 return;
202 }
204 if (!SetSuspendState(TRUE, FALSE, FALSE))
205 {
206 printf("hibernate failed\n");
207 }
209 CloseHandle(token_handle);
210 }
212 static void
213 do_shutdown(BOOL bRebootAfterShutdown)
214 {
215 HANDLE proc_handle = GetCurrentProcess();
216 TOKEN_PRIVILEGES *tp;
217 HANDLE token_handle;
219 printf("proc_handle = %p\n", proc_handle);
221 if (!OpenProcessToken(proc_handle, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token_handle))
222 {
223 printf("OpenProcessToken failed\n");
224 return;
225 }
226 printf("token_handle = %p\n", token_handle);
228 tp = malloc(sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES));
229 tp->PrivilegeCount = 1;
230 if (!LookupPrivilegeValueA(NULL, SE_SHUTDOWN_NAME, &tp->Privileges[0].Luid))
231 {
232 printf("LookupPrivilegeValue failed\n");
233 CloseHandle(token_handle);
234 return;
235 }
237 tp->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
238 if (!AdjustTokenPrivileges(token_handle, FALSE, tp, 0, NULL, NULL))
239 {
240 CloseHandle(token_handle);
241 return;
242 }
244 if (!InitiateSystemShutdownEx(NULL, NULL, 0, TRUE, bRebootAfterShutdown, SHTDN_REASON_FLAG_PLANNED | SHTDN_REASON_MAJOR_OTHER | SHTDN_REASON_MINOR_OTHER))
245 {
246 printf("InitiateSystemShutdownEx failed\n");
247 // Log a message to the system log here about a failed shutdown
248 }
249 printf("InitiateSystemShutdownEx succeeded\n");
251 CloseHandle(token_handle);
252 }
254 static char *
255 get_xen_interface_path()
256 {
257 HDEVINFO handle;
258 SP_DEVICE_INTERFACE_DATA sdid;
259 SP_DEVICE_INTERFACE_DETAIL_DATA *sdidd;
260 DWORD buf_len;
261 char *path;
263 handle = SetupDiGetClassDevs(&GUID_XENBUS_IFACE, 0, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
264 if (handle == INVALID_HANDLE_VALUE)
265 {
266 printf("SetupDiGetClassDevs failed\n");
267 return NULL;
268 }
269 sdid.cbSize = sizeof(sdid);
270 if (!SetupDiEnumDeviceInterfaces(handle, NULL, &GUID_XENBUS_IFACE, 0, &sdid))
271 {
272 printf("SetupDiEnumDeviceInterfaces failed\n");
273 return NULL;
274 }
275 SetupDiGetDeviceInterfaceDetail(handle, &sdid, NULL, 0, &buf_len, NULL);
276 sdidd = malloc(buf_len);
277 sdidd->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
278 if (!SetupDiGetDeviceInterfaceDetail(handle, &sdid, sdidd, buf_len, NULL, NULL))
279 {
280 printf("SetupDiGetDeviceInterfaceDetail failed\n");
281 return NULL;
282 }
284 path = malloc(strlen(sdidd->DevicePath) + 1);
285 strcpy(path, sdidd->DevicePath);
286 free(sdidd);
288 return path;
289 }
291 static int
292 xb_add_watch(HANDLE handle, char *path)
293 {
294 char buf[1024];
295 struct xsd_sockmsg *msg;
296 DWORD bytes_written;
297 DWORD bytes_read;
298 char *token = "0";
300 msg = (struct xsd_sockmsg *)buf;
301 msg->type = XS_WATCH;
302 msg->req_id = 0;
303 msg->tx_id = 0;
304 msg->len = (ULONG)(strlen(path) + 1 + strlen(token) + 1);
305 strcpy(buf + sizeof(*msg), path);
306 strcpy(buf + sizeof(*msg) + strlen(path) + 1, token);
308 if (!WriteFile(handle, buf, sizeof(*msg) + msg->len, &bytes_written, NULL))
309 {
310 printf("write failed\n");
311 return 0;
312 }
313 if (!ReadFile(handle, buf, 1024, &bytes_read, NULL))
314 {
315 printf("read failed\n");
316 return 0;
317 }
318 printf("bytes_read = %d\n", bytes_read);
319 printf("msg->len = %d\n", msg->len);
320 buf[sizeof(*msg) + msg->len] = 0;
321 printf("msg text = %s\n", buf + sizeof(*msg));
323 return 1;
324 }
326 static int
327 xb_wait_event(HANDLE handle)
328 {
329 char buf[1024];
330 struct xsd_sockmsg *msg;
331 DWORD bytes_read;
333 printf("wait_event start\n");
334 msg = (struct xsd_sockmsg *)buf;
335 if (!ReadFile(handle, buf, 1024, &bytes_read, NULL))
336 {
337 printf("read failed\n");
338 return 0;
339 }
340 printf("bytes_read = %d\n", bytes_read);
341 printf("msg->len = %d\n", msg->len);
342 buf[sizeof(*msg) + msg->len] = 0;
343 printf("msg text = %s\n", buf + sizeof(*msg));
344 return 1;
345 }
347 static char *
348 xb_read(HANDLE handle, char *path)
349 {
350 char buf[1024];
351 struct xsd_sockmsg *msg;
352 char *ret;
353 DWORD bytes_written;
354 DWORD bytes_read;
356 printf("read start\n");
357 msg = (struct xsd_sockmsg *)buf;
358 msg->type = XS_READ;
359 msg->req_id = 0;
360 msg->tx_id = 0;
361 msg->len = (ULONG)(strlen(path) + 1);
362 strcpy(buf + sizeof(*msg), path);
364 if (!WriteFile(handle, buf, sizeof(*msg) + msg->len, &bytes_written, NULL))
365 {
366 printf("write failed\n");
367 return NULL;
368 }
370 if (!ReadFile(handle, buf, 1024, &bytes_read, NULL))
371 {
372 printf("read failed\n");
373 return NULL;
374 }
375 printf("bytes_read = %d\n", bytes_read);
376 printf("msg->len = %d\n", msg->len);
377 buf[sizeof(*msg) + msg->len] = 0;
378 printf("msg text = %s\n", buf + sizeof(*msg));
379 ret = malloc(strlen(buf + sizeof(*msg)) + 1);
380 strcpy(ret, buf + sizeof(*msg));
381 return ret;
382 }
384 static void
385 do_monitoring()
386 {
387 HANDLE handle;
388 int state;
389 char *path;
390 char *buf;
392 path = get_xen_interface_path();
393 if (path == NULL)
394 return;
396 handle = CreateFile(path, FILE_GENERIC_READ|FILE_GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
398 xb_add_watch(handle, "control/shutdown");
400 state = 0;
401 while(xb_wait_event(handle))
402 {
403 if (service_status.dwCurrentState != SERVICE_RUNNING)
404 return;
405 buf = xb_read(handle, "control/shutdown");
407 //printf("msg = '%s'\n", msg);
408 if (strcmp("poweroff", buf) == 0 || strcmp("halt", buf) == 0)
409 {
410 do_shutdown(FALSE);
411 }
412 else if (strcmp("reboot", buf) == 0)
413 {
414 do_shutdown(TRUE);
415 }
416 else if (strcmp("hibernate", buf) == 0)
417 {
418 do_hibernate();
419 }
420 }
421 }
423 void control_handler(DWORD request)
424 {
425 switch(request)
426 {
427 case SERVICE_CONTROL_STOP:
428 service_status.dwWin32ExitCode = 0;
429 service_status.dwCurrentState = SERVICE_STOPPED;
430 SetServiceStatus (hStatus, &service_status);
431 return;
433 case SERVICE_CONTROL_SHUTDOWN:
434 service_status.dwWin32ExitCode = 0;
435 service_status.dwCurrentState = SERVICE_STOPPED;
436 SetServiceStatus (hStatus, &service_status);
437 return;
439 default:
440 break;
441 }
443 SetServiceStatus (hStatus, &service_status);
445 return;
446 }
448 void service_main(int argc, char *argv[])
449 {
450 UNREFERENCED_PARAMETER (argc);
451 UNREFERENCED_PARAMETER (argv);
453 printf("Entering service_main\n");
455 service_status.dwServiceType = SERVICE_WIN32;
456 service_status.dwCurrentState = SERVICE_START_PENDING;
457 service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
458 service_status.dwWin32ExitCode = 0;
459 service_status.dwServiceSpecificExitCode = 0;
460 service_status.dwCheckPoint = 0;
461 service_status.dwWaitHint = 0;
463 hStatus = RegisterServiceCtrlHandler(SERVICE_ID, (LPHANDLER_FUNCTION)control_handler);
464 if (hStatus == (SERVICE_STATUS_HANDLE)0)
465 {
466 printf("RegisterServiceCtrlHandler failed\n");
467 return;
468 }
470 service_status.dwCurrentState = SERVICE_RUNNING;
471 SetServiceStatus(hStatus, &service_status);
473 do_monitoring();
475 printf("All done\n");
477 return;
478 }
481 static void
482 print_usage(char *name)
483 {
484 printf("Usage:\n");
485 printf(" %s <options>\n", name);
486 printf("\n");
487 printf("Options:\n");
488 printf(" -d run in foreground\n");
489 printf(" -s run as service\n");
490 printf(" -i install service\n");
491 printf(" -u uninstall service\n");
492 printf(" -o remove the old .NET service\n");
493 }
495 int __cdecl
496 main(
497 __in ULONG argc,
498 __in_ecount(argc) PCHAR argv[]
499 )
500 {
501 SERVICE_TABLE_ENTRY service_table[2];
503 if (argc == 0)
504 {
505 print_usage("shutdownmon");
506 return 1;
507 }
508 if (argc != 2 || (argc == 2 && (strlen(argv[1]) != 2 || argv[1][0] != '-')))
509 {
510 print_usage(argv[0]);
511 return 1;
512 }
514 switch(argv[1][1])
515 {
516 case 'd':
517 service_status.dwCurrentState = SERVICE_RUNNING;
518 do_monitoring();
519 break;
520 case 's':
521 service_table[0].lpServiceName = SERVICE_ID;
522 service_table[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)service_main;
524 service_table[1].lpServiceName = NULL;
525 service_table[1].lpServiceProc = NULL;
527 StartServiceCtrlDispatcher(service_table);
528 break;
529 case 'i':
530 install_service();
531 break;
532 case 'u':
533 remove_service();
534 break;
535 case 'o':
536 remove_old_service();
537 break;
538 default:
539 print_usage(argv[0]);
540 return 1;
541 }
542 return 0;
543 }