win-pvdrivers

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