service-win32.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. /*
  2. * QEMU Guest Agent helpers for win32 service management
  3. *
  4. * Copyright IBM Corp. 2012
  5. *
  6. * Authors:
  7. * Gal Hammer <ghammer@redhat.com>
  8. * Michael Roth <mdroth@linux.vnet.ibm.com>
  9. *
  10. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  11. * See the COPYING file in the top-level directory.
  12. */
  13. #include "qemu/osdep.h"
  14. #include <windows.h>
  15. #include "qga/service-win32.h"
  16. static int printf_win_error(const char *text)
  17. {
  18. DWORD err = GetLastError();
  19. char *message;
  20. int n;
  21. FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  22. FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
  23. NULL,
  24. err,
  25. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  26. (char *)&message, 0,
  27. NULL);
  28. n = fprintf(stderr, "%s. (Error: %d) %s", text, (int)err, message);
  29. LocalFree(message);
  30. return n;
  31. }
  32. /* Windows command line escaping. Based on
  33. * <http://blogs.msdn.com/b/oldnewthing/archive/2010/09/17/10063629.aspx> and
  34. * <http://msdn.microsoft.com/en-us/library/windows/desktop/17w5ykft%28v=vs.85%29.aspx>.
  35. *
  36. * The caller is responsible for initializing @buffer; prior contents are lost.
  37. */
  38. static const char *win_escape_arg(const char *to_escape, GString *buffer)
  39. {
  40. size_t backslash_count;
  41. const char *c;
  42. /* open with a double quote */
  43. g_string_assign(buffer, "\"");
  44. backslash_count = 0;
  45. for (c = to_escape; *c != '\0'; ++c) {
  46. switch (*c) {
  47. case '\\':
  48. /* The meaning depends on the first non-backslash character coming
  49. * up.
  50. */
  51. ++backslash_count;
  52. break;
  53. case '"':
  54. /* We must escape each pending backslash, then escape the double
  55. * quote. This creates a case of "odd number of backslashes [...]
  56. * followed by a double quotation mark".
  57. */
  58. while (backslash_count) {
  59. --backslash_count;
  60. g_string_append(buffer, "\\\\");
  61. }
  62. g_string_append(buffer, "\\\"");
  63. break;
  64. default:
  65. /* Any pending backslashes are without special meaning, flush them.
  66. * "Backslashes are interpreted literally, unless they immediately
  67. * precede a double quotation mark."
  68. */
  69. while (backslash_count) {
  70. --backslash_count;
  71. g_string_append_c(buffer, '\\');
  72. }
  73. g_string_append_c(buffer, *c);
  74. }
  75. }
  76. /* We're about to close with a double quote in string delimiter role.
  77. * Double all pending backslashes, creating a case of "even number of
  78. * backslashes [...] followed by a double quotation mark".
  79. */
  80. while (backslash_count) {
  81. --backslash_count;
  82. g_string_append(buffer, "\\\\");
  83. }
  84. g_string_append_c(buffer, '"');
  85. return buffer->str;
  86. }
  87. int ga_install_service(const char *path, const char *logfile,
  88. const char *state_dir)
  89. {
  90. int ret = EXIT_FAILURE;
  91. SC_HANDLE manager;
  92. SC_HANDLE service;
  93. TCHAR module_fname[MAX_PATH];
  94. GString *esc;
  95. GString *cmdline;
  96. SERVICE_DESCRIPTION desc = { (char *)QGA_SERVICE_DESCRIPTION };
  97. if (GetModuleFileName(NULL, module_fname, MAX_PATH) == 0) {
  98. printf_win_error("No full path to service's executable");
  99. return EXIT_FAILURE;
  100. }
  101. esc = g_string_new("");
  102. cmdline = g_string_new("");
  103. g_string_append_printf(cmdline, "%s -d",
  104. win_escape_arg(module_fname, esc));
  105. if (path) {
  106. g_string_append_printf(cmdline, " -p %s", win_escape_arg(path, esc));
  107. }
  108. if (logfile) {
  109. g_string_append_printf(cmdline, " -l %s -v",
  110. win_escape_arg(logfile, esc));
  111. }
  112. if (state_dir) {
  113. g_string_append_printf(cmdline, " -t %s",
  114. win_escape_arg(state_dir, esc));
  115. }
  116. g_debug("service's cmdline: %s", cmdline->str);
  117. manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  118. if (manager == NULL) {
  119. printf_win_error("No handle to service control manager");
  120. goto out_strings;
  121. }
  122. service = CreateService(manager, QGA_SERVICE_NAME, QGA_SERVICE_DISPLAY_NAME,
  123. SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
  124. SERVICE_ERROR_NORMAL, cmdline->str, NULL, NULL, NULL, NULL, NULL);
  125. if (service == NULL) {
  126. printf_win_error("Failed to install service");
  127. goto out_manager;
  128. }
  129. ChangeServiceConfig2(service, SERVICE_CONFIG_DESCRIPTION, &desc);
  130. fprintf(stderr, "Service was installed successfully.\n");
  131. ret = EXIT_SUCCESS;
  132. CloseServiceHandle(service);
  133. out_manager:
  134. CloseServiceHandle(manager);
  135. out_strings:
  136. g_string_free(cmdline, TRUE);
  137. g_string_free(esc, TRUE);
  138. return ret;
  139. }
  140. int ga_uninstall_service(void)
  141. {
  142. SC_HANDLE manager;
  143. SC_HANDLE service;
  144. manager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
  145. if (manager == NULL) {
  146. printf_win_error("No handle to service control manager");
  147. return EXIT_FAILURE;
  148. }
  149. service = OpenService(manager, QGA_SERVICE_NAME, DELETE);
  150. if (service == NULL) {
  151. printf_win_error("No handle to service");
  152. CloseServiceHandle(manager);
  153. return EXIT_FAILURE;
  154. }
  155. if (DeleteService(service) == FALSE) {
  156. printf_win_error("Failed to delete service");
  157. } else {
  158. fprintf(stderr, "Service was deleted successfully.\n");
  159. }
  160. CloseServiceHandle(service);
  161. CloseServiceHandle(manager);
  162. return EXIT_SUCCESS;
  163. }