commands-win32.c 57 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979
  1. /*
  2. * QEMU Guest Agent win32-specific command implementations
  3. *
  4. * Copyright IBM Corp. 2012
  5. *
  6. * Authors:
  7. * Michael Roth <mdroth@linux.vnet.ibm.com>
  8. * Gal Hammer <ghammer@redhat.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. #ifndef _WIN32_WINNT
  14. # define _WIN32_WINNT 0x0600
  15. #endif
  16. #include "qemu/osdep.h"
  17. #include <wtypes.h>
  18. #include <powrprof.h>
  19. #include <winsock2.h>
  20. #include <ws2tcpip.h>
  21. #include <iptypes.h>
  22. #include <iphlpapi.h>
  23. #ifdef CONFIG_QGA_NTDDSCSI
  24. #include <winioctl.h>
  25. #include <ntddscsi.h>
  26. #include <setupapi.h>
  27. #include <initguid.h>
  28. #endif
  29. #include <lm.h>
  30. #include <wtsapi32.h>
  31. #include <wininet.h>
  32. #include "guest-agent-core.h"
  33. #include "vss-win32.h"
  34. #include "qga-qapi-commands.h"
  35. #include "qapi/error.h"
  36. #include "qapi/qmp/qerror.h"
  37. #include "qemu/queue.h"
  38. #include "qemu/host-utils.h"
  39. #include "qemu/base64.h"
  40. #ifndef SHTDN_REASON_FLAG_PLANNED
  41. #define SHTDN_REASON_FLAG_PLANNED 0x80000000
  42. #endif
  43. /* multiple of 100 nanoseconds elapsed between windows baseline
  44. * (1/1/1601) and Unix Epoch (1/1/1970), accounting for leap years */
  45. #define W32_FT_OFFSET (10000000ULL * 60 * 60 * 24 * \
  46. (365 * (1970 - 1601) + \
  47. (1970 - 1601) / 4 - 3))
  48. #define INVALID_SET_FILE_POINTER ((DWORD)-1)
  49. typedef struct GuestFileHandle {
  50. int64_t id;
  51. HANDLE fh;
  52. QTAILQ_ENTRY(GuestFileHandle) next;
  53. } GuestFileHandle;
  54. static struct {
  55. QTAILQ_HEAD(, GuestFileHandle) filehandles;
  56. } guest_file_state = {
  57. .filehandles = QTAILQ_HEAD_INITIALIZER(guest_file_state.filehandles),
  58. };
  59. #define FILE_GENERIC_APPEND (FILE_GENERIC_WRITE & ~FILE_WRITE_DATA)
  60. typedef struct OpenFlags {
  61. const char *forms;
  62. DWORD desired_access;
  63. DWORD creation_disposition;
  64. } OpenFlags;
  65. static OpenFlags guest_file_open_modes[] = {
  66. {"r", GENERIC_READ, OPEN_EXISTING},
  67. {"rb", GENERIC_READ, OPEN_EXISTING},
  68. {"w", GENERIC_WRITE, CREATE_ALWAYS},
  69. {"wb", GENERIC_WRITE, CREATE_ALWAYS},
  70. {"a", FILE_GENERIC_APPEND, OPEN_ALWAYS },
  71. {"r+", GENERIC_WRITE|GENERIC_READ, OPEN_EXISTING},
  72. {"rb+", GENERIC_WRITE|GENERIC_READ, OPEN_EXISTING},
  73. {"r+b", GENERIC_WRITE|GENERIC_READ, OPEN_EXISTING},
  74. {"w+", GENERIC_WRITE|GENERIC_READ, CREATE_ALWAYS},
  75. {"wb+", GENERIC_WRITE|GENERIC_READ, CREATE_ALWAYS},
  76. {"w+b", GENERIC_WRITE|GENERIC_READ, CREATE_ALWAYS},
  77. {"a+", FILE_GENERIC_APPEND|GENERIC_READ, OPEN_ALWAYS },
  78. {"ab+", FILE_GENERIC_APPEND|GENERIC_READ, OPEN_ALWAYS },
  79. {"a+b", FILE_GENERIC_APPEND|GENERIC_READ, OPEN_ALWAYS }
  80. };
  81. static OpenFlags *find_open_flag(const char *mode_str)
  82. {
  83. int mode;
  84. Error **errp = NULL;
  85. for (mode = 0; mode < ARRAY_SIZE(guest_file_open_modes); ++mode) {
  86. OpenFlags *flags = guest_file_open_modes + mode;
  87. if (strcmp(flags->forms, mode_str) == 0) {
  88. return flags;
  89. }
  90. }
  91. error_setg(errp, "invalid file open mode '%s'", mode_str);
  92. return NULL;
  93. }
  94. static int64_t guest_file_handle_add(HANDLE fh, Error **errp)
  95. {
  96. GuestFileHandle *gfh;
  97. int64_t handle;
  98. handle = ga_get_fd_handle(ga_state, errp);
  99. if (handle < 0) {
  100. return -1;
  101. }
  102. gfh = g_new0(GuestFileHandle, 1);
  103. gfh->id = handle;
  104. gfh->fh = fh;
  105. QTAILQ_INSERT_TAIL(&guest_file_state.filehandles, gfh, next);
  106. return handle;
  107. }
  108. static GuestFileHandle *guest_file_handle_find(int64_t id, Error **errp)
  109. {
  110. GuestFileHandle *gfh;
  111. QTAILQ_FOREACH(gfh, &guest_file_state.filehandles, next) {
  112. if (gfh->id == id) {
  113. return gfh;
  114. }
  115. }
  116. error_setg(errp, "handle '%" PRId64 "' has not been found", id);
  117. return NULL;
  118. }
  119. static void handle_set_nonblocking(HANDLE fh)
  120. {
  121. DWORD file_type, pipe_state;
  122. file_type = GetFileType(fh);
  123. if (file_type != FILE_TYPE_PIPE) {
  124. return;
  125. }
  126. /* If file_type == FILE_TYPE_PIPE, according to MSDN
  127. * the specified file is socket or named pipe */
  128. if (!GetNamedPipeHandleState(fh, &pipe_state, NULL,
  129. NULL, NULL, NULL, 0)) {
  130. return;
  131. }
  132. /* The fd is named pipe fd */
  133. if (pipe_state & PIPE_NOWAIT) {
  134. return;
  135. }
  136. pipe_state |= PIPE_NOWAIT;
  137. SetNamedPipeHandleState(fh, &pipe_state, NULL, NULL);
  138. }
  139. int64_t qmp_guest_file_open(const char *path, bool has_mode,
  140. const char *mode, Error **errp)
  141. {
  142. int64_t fd = -1;
  143. HANDLE fh;
  144. HANDLE templ_file = NULL;
  145. DWORD share_mode = FILE_SHARE_READ;
  146. DWORD flags_and_attr = FILE_ATTRIBUTE_NORMAL;
  147. LPSECURITY_ATTRIBUTES sa_attr = NULL;
  148. OpenFlags *guest_flags;
  149. GError *gerr = NULL;
  150. wchar_t *w_path = NULL;
  151. if (!has_mode) {
  152. mode = "r";
  153. }
  154. slog("guest-file-open called, filepath: %s, mode: %s", path, mode);
  155. guest_flags = find_open_flag(mode);
  156. if (guest_flags == NULL) {
  157. error_setg(errp, "invalid file open mode");
  158. goto done;
  159. }
  160. w_path = g_utf8_to_utf16(path, -1, NULL, NULL, &gerr);
  161. if (!w_path) {
  162. goto done;
  163. }
  164. fh = CreateFileW(w_path, guest_flags->desired_access, share_mode, sa_attr,
  165. guest_flags->creation_disposition, flags_and_attr,
  166. templ_file);
  167. if (fh == INVALID_HANDLE_VALUE) {
  168. error_setg_win32(errp, GetLastError(), "failed to open file '%s'",
  169. path);
  170. goto done;
  171. }
  172. /* set fd non-blocking to avoid common use cases (like reading from a
  173. * named pipe) from hanging the agent
  174. */
  175. handle_set_nonblocking(fh);
  176. fd = guest_file_handle_add(fh, errp);
  177. if (fd < 0) {
  178. CloseHandle(fh);
  179. error_setg(errp, "failed to add handle to qmp handle table");
  180. goto done;
  181. }
  182. slog("guest-file-open, handle: % " PRId64, fd);
  183. done:
  184. if (gerr) {
  185. error_setg(errp, QERR_QGA_COMMAND_FAILED, gerr->message);
  186. g_error_free(gerr);
  187. }
  188. g_free(w_path);
  189. return fd;
  190. }
  191. void qmp_guest_file_close(int64_t handle, Error **errp)
  192. {
  193. bool ret;
  194. GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
  195. slog("guest-file-close called, handle: %" PRId64, handle);
  196. if (gfh == NULL) {
  197. return;
  198. }
  199. ret = CloseHandle(gfh->fh);
  200. if (!ret) {
  201. error_setg_win32(errp, GetLastError(), "failed close handle");
  202. return;
  203. }
  204. QTAILQ_REMOVE(&guest_file_state.filehandles, gfh, next);
  205. g_free(gfh);
  206. }
  207. static void acquire_privilege(const char *name, Error **errp)
  208. {
  209. HANDLE token = NULL;
  210. TOKEN_PRIVILEGES priv;
  211. Error *local_err = NULL;
  212. if (OpenProcessToken(GetCurrentProcess(),
  213. TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY, &token))
  214. {
  215. if (!LookupPrivilegeValue(NULL, name, &priv.Privileges[0].Luid)) {
  216. error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
  217. "no luid for requested privilege");
  218. goto out;
  219. }
  220. priv.PrivilegeCount = 1;
  221. priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  222. if (!AdjustTokenPrivileges(token, FALSE, &priv, 0, NULL, 0)) {
  223. error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
  224. "unable to acquire requested privilege");
  225. goto out;
  226. }
  227. } else {
  228. error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
  229. "failed to open privilege token");
  230. }
  231. out:
  232. if (token) {
  233. CloseHandle(token);
  234. }
  235. error_propagate(errp, local_err);
  236. }
  237. static void execute_async(DWORD WINAPI (*func)(LPVOID), LPVOID opaque,
  238. Error **errp)
  239. {
  240. Error *local_err = NULL;
  241. HANDLE thread = CreateThread(NULL, 0, func, opaque, 0, NULL);
  242. if (!thread) {
  243. error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
  244. "failed to dispatch asynchronous command");
  245. error_propagate(errp, local_err);
  246. }
  247. }
  248. void qmp_guest_shutdown(bool has_mode, const char *mode, Error **errp)
  249. {
  250. Error *local_err = NULL;
  251. UINT shutdown_flag = EWX_FORCE;
  252. slog("guest-shutdown called, mode: %s", mode);
  253. if (!has_mode || strcmp(mode, "powerdown") == 0) {
  254. shutdown_flag |= EWX_POWEROFF;
  255. } else if (strcmp(mode, "halt") == 0) {
  256. shutdown_flag |= EWX_SHUTDOWN;
  257. } else if (strcmp(mode, "reboot") == 0) {
  258. shutdown_flag |= EWX_REBOOT;
  259. } else {
  260. error_setg(errp, QERR_INVALID_PARAMETER_VALUE, "mode",
  261. "halt|powerdown|reboot");
  262. return;
  263. }
  264. /* Request a shutdown privilege, but try to shut down the system
  265. anyway. */
  266. acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
  267. if (local_err) {
  268. error_propagate(errp, local_err);
  269. return;
  270. }
  271. if (!ExitWindowsEx(shutdown_flag, SHTDN_REASON_FLAG_PLANNED)) {
  272. slog("guest-shutdown failed: %lu", GetLastError());
  273. error_setg(errp, QERR_UNDEFINED_ERROR);
  274. }
  275. }
  276. GuestFileRead *qmp_guest_file_read(int64_t handle, bool has_count,
  277. int64_t count, Error **errp)
  278. {
  279. GuestFileRead *read_data = NULL;
  280. guchar *buf;
  281. HANDLE fh;
  282. bool is_ok;
  283. DWORD read_count;
  284. GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
  285. if (!gfh) {
  286. return NULL;
  287. }
  288. if (!has_count) {
  289. count = QGA_READ_COUNT_DEFAULT;
  290. } else if (count < 0 || count >= UINT32_MAX) {
  291. error_setg(errp, "value '%" PRId64
  292. "' is invalid for argument count", count);
  293. return NULL;
  294. }
  295. fh = gfh->fh;
  296. buf = g_malloc0(count+1);
  297. is_ok = ReadFile(fh, buf, count, &read_count, NULL);
  298. if (!is_ok) {
  299. error_setg_win32(errp, GetLastError(), "failed to read file");
  300. slog("guest-file-read failed, handle %" PRId64, handle);
  301. } else {
  302. buf[read_count] = 0;
  303. read_data = g_new0(GuestFileRead, 1);
  304. read_data->count = (size_t)read_count;
  305. read_data->eof = read_count == 0;
  306. if (read_count != 0) {
  307. read_data->buf_b64 = g_base64_encode(buf, read_count);
  308. }
  309. }
  310. g_free(buf);
  311. return read_data;
  312. }
  313. GuestFileWrite *qmp_guest_file_write(int64_t handle, const char *buf_b64,
  314. bool has_count, int64_t count,
  315. Error **errp)
  316. {
  317. GuestFileWrite *write_data = NULL;
  318. guchar *buf;
  319. gsize buf_len;
  320. bool is_ok;
  321. DWORD write_count;
  322. GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
  323. HANDLE fh;
  324. if (!gfh) {
  325. return NULL;
  326. }
  327. fh = gfh->fh;
  328. buf = qbase64_decode(buf_b64, -1, &buf_len, errp);
  329. if (!buf) {
  330. return NULL;
  331. }
  332. if (!has_count) {
  333. count = buf_len;
  334. } else if (count < 0 || count > buf_len) {
  335. error_setg(errp, "value '%" PRId64
  336. "' is invalid for argument count", count);
  337. goto done;
  338. }
  339. is_ok = WriteFile(fh, buf, count, &write_count, NULL);
  340. if (!is_ok) {
  341. error_setg_win32(errp, GetLastError(), "failed to write to file");
  342. slog("guest-file-write-failed, handle: %" PRId64, handle);
  343. } else {
  344. write_data = g_new0(GuestFileWrite, 1);
  345. write_data->count = (size_t) write_count;
  346. }
  347. done:
  348. g_free(buf);
  349. return write_data;
  350. }
  351. GuestFileSeek *qmp_guest_file_seek(int64_t handle, int64_t offset,
  352. GuestFileWhence *whence_code,
  353. Error **errp)
  354. {
  355. GuestFileHandle *gfh;
  356. GuestFileSeek *seek_data;
  357. HANDLE fh;
  358. LARGE_INTEGER new_pos, off_pos;
  359. off_pos.QuadPart = offset;
  360. BOOL res;
  361. int whence;
  362. Error *err = NULL;
  363. gfh = guest_file_handle_find(handle, errp);
  364. if (!gfh) {
  365. return NULL;
  366. }
  367. /* We stupidly exposed 'whence':'int' in our qapi */
  368. whence = ga_parse_whence(whence_code, &err);
  369. if (err) {
  370. error_propagate(errp, err);
  371. return NULL;
  372. }
  373. fh = gfh->fh;
  374. res = SetFilePointerEx(fh, off_pos, &new_pos, whence);
  375. if (!res) {
  376. error_setg_win32(errp, GetLastError(), "failed to seek file");
  377. return NULL;
  378. }
  379. seek_data = g_new0(GuestFileSeek, 1);
  380. seek_data->position = new_pos.QuadPart;
  381. return seek_data;
  382. }
  383. void qmp_guest_file_flush(int64_t handle, Error **errp)
  384. {
  385. HANDLE fh;
  386. GuestFileHandle *gfh = guest_file_handle_find(handle, errp);
  387. if (!gfh) {
  388. return;
  389. }
  390. fh = gfh->fh;
  391. if (!FlushFileBuffers(fh)) {
  392. error_setg_win32(errp, GetLastError(), "failed to flush file");
  393. }
  394. }
  395. #ifdef CONFIG_QGA_NTDDSCSI
  396. static STORAGE_BUS_TYPE win2qemu[] = {
  397. [BusTypeUnknown] = GUEST_DISK_BUS_TYPE_UNKNOWN,
  398. [BusTypeScsi] = GUEST_DISK_BUS_TYPE_SCSI,
  399. [BusTypeAtapi] = GUEST_DISK_BUS_TYPE_IDE,
  400. [BusTypeAta] = GUEST_DISK_BUS_TYPE_IDE,
  401. [BusType1394] = GUEST_DISK_BUS_TYPE_IEEE1394,
  402. [BusTypeSsa] = GUEST_DISK_BUS_TYPE_SSA,
  403. [BusTypeFibre] = GUEST_DISK_BUS_TYPE_SSA,
  404. [BusTypeUsb] = GUEST_DISK_BUS_TYPE_USB,
  405. [BusTypeRAID] = GUEST_DISK_BUS_TYPE_RAID,
  406. #if (_WIN32_WINNT >= 0x0600)
  407. [BusTypeiScsi] = GUEST_DISK_BUS_TYPE_ISCSI,
  408. [BusTypeSas] = GUEST_DISK_BUS_TYPE_SAS,
  409. [BusTypeSata] = GUEST_DISK_BUS_TYPE_SATA,
  410. [BusTypeSd] = GUEST_DISK_BUS_TYPE_SD,
  411. [BusTypeMmc] = GUEST_DISK_BUS_TYPE_MMC,
  412. #endif
  413. #if (_WIN32_WINNT >= 0x0601)
  414. [BusTypeVirtual] = GUEST_DISK_BUS_TYPE_VIRTUAL,
  415. [BusTypeFileBackedVirtual] = GUEST_DISK_BUS_TYPE_FILE_BACKED_VIRTUAL,
  416. #endif
  417. };
  418. static GuestDiskBusType find_bus_type(STORAGE_BUS_TYPE bus)
  419. {
  420. if (bus > ARRAY_SIZE(win2qemu) || (int)bus < 0) {
  421. return GUEST_DISK_BUS_TYPE_UNKNOWN;
  422. }
  423. return win2qemu[(int)bus];
  424. }
  425. DEFINE_GUID(GUID_DEVINTERFACE_VOLUME,
  426. 0x53f5630dL, 0xb6bf, 0x11d0, 0x94, 0xf2,
  427. 0x00, 0xa0, 0xc9, 0x1e, 0xfb, 0x8b);
  428. static GuestPCIAddress *get_pci_info(char *guid, Error **errp)
  429. {
  430. HDEVINFO dev_info;
  431. SP_DEVINFO_DATA dev_info_data;
  432. DWORD size = 0;
  433. int i;
  434. char dev_name[MAX_PATH];
  435. char *buffer = NULL;
  436. GuestPCIAddress *pci = NULL;
  437. char *name = g_strdup(&guid[4]);
  438. if (!QueryDosDevice(name, dev_name, ARRAY_SIZE(dev_name))) {
  439. error_setg_win32(errp, GetLastError(), "failed to get dos device name");
  440. goto out;
  441. }
  442. dev_info = SetupDiGetClassDevs(&GUID_DEVINTERFACE_VOLUME, 0, 0,
  443. DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
  444. if (dev_info == INVALID_HANDLE_VALUE) {
  445. error_setg_win32(errp, GetLastError(), "failed to get devices tree");
  446. goto out;
  447. }
  448. dev_info_data.cbSize = sizeof(SP_DEVINFO_DATA);
  449. for (i = 0; SetupDiEnumDeviceInfo(dev_info, i, &dev_info_data); i++) {
  450. DWORD addr, bus, slot, func, dev, data, size2;
  451. while (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
  452. SPDRP_PHYSICAL_DEVICE_OBJECT_NAME,
  453. &data, (PBYTE)buffer, size,
  454. &size2)) {
  455. size = MAX(size, size2);
  456. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  457. g_free(buffer);
  458. /* Double the size to avoid problems on
  459. * W2k MBCS systems per KB 888609.
  460. * https://support.microsoft.com/en-us/kb/259695 */
  461. buffer = g_malloc(size * 2);
  462. } else {
  463. error_setg_win32(errp, GetLastError(),
  464. "failed to get device name");
  465. goto free_dev_info;
  466. }
  467. }
  468. if (g_strcmp0(buffer, dev_name)) {
  469. continue;
  470. }
  471. /* There is no need to allocate buffer in the next functions. The size
  472. * is known and ULONG according to
  473. * https://support.microsoft.com/en-us/kb/253232
  474. * https://msdn.microsoft.com/en-us/library/windows/hardware/ff543095(v=vs.85).aspx
  475. */
  476. if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
  477. SPDRP_BUSNUMBER, &data, (PBYTE)&bus, size, NULL)) {
  478. break;
  479. }
  480. /* The function retrieves the device's address. This value will be
  481. * transformed into device function and number */
  482. if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
  483. SPDRP_ADDRESS, &data, (PBYTE)&addr, size, NULL)) {
  484. break;
  485. }
  486. /* This call returns UINumber of DEVICE_CAPABILITIES structure.
  487. * This number is typically a user-perceived slot number. */
  488. if (!SetupDiGetDeviceRegistryProperty(dev_info, &dev_info_data,
  489. SPDRP_UI_NUMBER, &data, (PBYTE)&slot, size, NULL)) {
  490. break;
  491. }
  492. /* SetupApi gives us the same information as driver with
  493. * IoGetDeviceProperty. According to Microsoft
  494. * https://support.microsoft.com/en-us/kb/253232
  495. * FunctionNumber = (USHORT)((propertyAddress) & 0x0000FFFF);
  496. * DeviceNumber = (USHORT)(((propertyAddress) >> 16) & 0x0000FFFF);
  497. * SPDRP_ADDRESS is propertyAddress, so we do the same.*/
  498. func = addr & 0x0000FFFF;
  499. dev = (addr >> 16) & 0x0000FFFF;
  500. pci = g_malloc0(sizeof(*pci));
  501. pci->domain = dev;
  502. pci->slot = slot;
  503. pci->function = func;
  504. pci->bus = bus;
  505. break;
  506. }
  507. free_dev_info:
  508. SetupDiDestroyDeviceInfoList(dev_info);
  509. out:
  510. g_free(buffer);
  511. g_free(name);
  512. return pci;
  513. }
  514. static int get_disk_bus_type(HANDLE vol_h, Error **errp)
  515. {
  516. STORAGE_PROPERTY_QUERY query;
  517. STORAGE_DEVICE_DESCRIPTOR *dev_desc, buf;
  518. DWORD received;
  519. dev_desc = &buf;
  520. dev_desc->Size = sizeof(buf);
  521. query.PropertyId = StorageDeviceProperty;
  522. query.QueryType = PropertyStandardQuery;
  523. if (!DeviceIoControl(vol_h, IOCTL_STORAGE_QUERY_PROPERTY, &query,
  524. sizeof(STORAGE_PROPERTY_QUERY), dev_desc,
  525. dev_desc->Size, &received, NULL)) {
  526. error_setg_win32(errp, GetLastError(), "failed to get bus type");
  527. return -1;
  528. }
  529. return dev_desc->BusType;
  530. }
  531. /* VSS provider works with volumes, thus there is no difference if
  532. * the volume consist of spanned disks. Info about the first disk in the
  533. * volume is returned for the spanned disk group (LVM) */
  534. static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
  535. {
  536. GuestDiskAddressList *list = NULL;
  537. GuestDiskAddress *disk;
  538. SCSI_ADDRESS addr, *scsi_ad;
  539. DWORD len;
  540. int bus;
  541. HANDLE vol_h;
  542. scsi_ad = &addr;
  543. char *name = g_strndup(guid, strlen(guid)-1);
  544. vol_h = CreateFile(name, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING,
  545. 0, NULL);
  546. if (vol_h == INVALID_HANDLE_VALUE) {
  547. error_setg_win32(errp, GetLastError(), "failed to open volume");
  548. goto out_free;
  549. }
  550. bus = get_disk_bus_type(vol_h, errp);
  551. if (bus < 0) {
  552. goto out_close;
  553. }
  554. disk = g_malloc0(sizeof(*disk));
  555. disk->bus_type = find_bus_type(bus);
  556. if (bus == BusTypeScsi || bus == BusTypeAta || bus == BusTypeRAID
  557. #if (_WIN32_WINNT >= 0x0600)
  558. /* This bus type is not supported before Windows Server 2003 SP1 */
  559. || bus == BusTypeSas
  560. #endif
  561. ) {
  562. /* We are able to use the same ioctls for different bus types
  563. * according to Microsoft docs
  564. * https://technet.microsoft.com/en-us/library/ee851589(v=ws.10).aspx */
  565. if (DeviceIoControl(vol_h, IOCTL_SCSI_GET_ADDRESS, NULL, 0, scsi_ad,
  566. sizeof(SCSI_ADDRESS), &len, NULL)) {
  567. disk->unit = addr.Lun;
  568. disk->target = addr.TargetId;
  569. disk->bus = addr.PathId;
  570. disk->pci_controller = get_pci_info(name, errp);
  571. }
  572. /* We do not set error in this case, because we still have enough
  573. * information about volume. */
  574. } else {
  575. disk->pci_controller = NULL;
  576. }
  577. list = g_malloc0(sizeof(*list));
  578. list->value = disk;
  579. list->next = NULL;
  580. out_close:
  581. CloseHandle(vol_h);
  582. out_free:
  583. g_free(name);
  584. return list;
  585. }
  586. #else
  587. static GuestDiskAddressList *build_guest_disk_info(char *guid, Error **errp)
  588. {
  589. return NULL;
  590. }
  591. #endif /* CONFIG_QGA_NTDDSCSI */
  592. static GuestFilesystemInfo *build_guest_fsinfo(char *guid, Error **errp)
  593. {
  594. DWORD info_size;
  595. char mnt, *mnt_point;
  596. char fs_name[32];
  597. char vol_info[MAX_PATH+1];
  598. size_t len;
  599. uint64_t i64FreeBytesToCaller, i64TotalBytes, i64FreeBytes;
  600. GuestFilesystemInfo *fs = NULL;
  601. GetVolumePathNamesForVolumeName(guid, (LPCH)&mnt, 0, &info_size);
  602. if (GetLastError() != ERROR_MORE_DATA) {
  603. error_setg_win32(errp, GetLastError(), "failed to get volume name");
  604. return NULL;
  605. }
  606. mnt_point = g_malloc(info_size + 1);
  607. if (!GetVolumePathNamesForVolumeName(guid, mnt_point, info_size,
  608. &info_size)) {
  609. error_setg_win32(errp, GetLastError(), "failed to get volume name");
  610. goto free;
  611. }
  612. len = strlen(mnt_point);
  613. mnt_point[len] = '\\';
  614. mnt_point[len+1] = 0;
  615. if (!GetVolumeInformation(mnt_point, vol_info, sizeof(vol_info), NULL, NULL,
  616. NULL, (LPSTR)&fs_name, sizeof(fs_name))) {
  617. if (GetLastError() != ERROR_NOT_READY) {
  618. error_setg_win32(errp, GetLastError(), "failed to get volume info");
  619. }
  620. goto free;
  621. }
  622. fs_name[sizeof(fs_name) - 1] = 0;
  623. fs = g_malloc(sizeof(*fs));
  624. fs->name = g_strdup(guid);
  625. fs->has_total_bytes = false;
  626. fs->has_used_bytes = false;
  627. if (len == 0) {
  628. fs->mountpoint = g_strdup("System Reserved");
  629. } else {
  630. fs->mountpoint = g_strndup(mnt_point, len);
  631. if (GetDiskFreeSpaceEx(fs->mountpoint,
  632. (PULARGE_INTEGER) & i64FreeBytesToCaller,
  633. (PULARGE_INTEGER) & i64TotalBytes,
  634. (PULARGE_INTEGER) & i64FreeBytes)) {
  635. fs->used_bytes = i64TotalBytes - i64FreeBytes;
  636. fs->total_bytes = i64TotalBytes;
  637. fs->has_total_bytes = true;
  638. fs->has_used_bytes = true;
  639. }
  640. }
  641. fs->type = g_strdup(fs_name);
  642. fs->disk = build_guest_disk_info(guid, errp);
  643. free:
  644. g_free(mnt_point);
  645. return fs;
  646. }
  647. GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
  648. {
  649. HANDLE vol_h;
  650. GuestFilesystemInfoList *new, *ret = NULL;
  651. char guid[256];
  652. vol_h = FindFirstVolume(guid, sizeof(guid));
  653. if (vol_h == INVALID_HANDLE_VALUE) {
  654. error_setg_win32(errp, GetLastError(), "failed to find any volume");
  655. return NULL;
  656. }
  657. do {
  658. GuestFilesystemInfo *info = build_guest_fsinfo(guid, errp);
  659. if (info == NULL) {
  660. continue;
  661. }
  662. new = g_malloc(sizeof(*ret));
  663. new->value = info;
  664. new->next = ret;
  665. ret = new;
  666. } while (FindNextVolume(vol_h, guid, sizeof(guid)));
  667. if (GetLastError() != ERROR_NO_MORE_FILES) {
  668. error_setg_win32(errp, GetLastError(), "failed to find next volume");
  669. }
  670. FindVolumeClose(vol_h);
  671. return ret;
  672. }
  673. /*
  674. * Return status of freeze/thaw
  675. */
  676. GuestFsfreezeStatus qmp_guest_fsfreeze_status(Error **errp)
  677. {
  678. if (!vss_initialized()) {
  679. error_setg(errp, QERR_UNSUPPORTED);
  680. return 0;
  681. }
  682. if (ga_is_frozen(ga_state)) {
  683. return GUEST_FSFREEZE_STATUS_FROZEN;
  684. }
  685. return GUEST_FSFREEZE_STATUS_THAWED;
  686. }
  687. /*
  688. * Freeze local file systems using Volume Shadow-copy Service.
  689. * The frozen state is limited for up to 10 seconds by VSS.
  690. */
  691. int64_t qmp_guest_fsfreeze_freeze(Error **errp)
  692. {
  693. return qmp_guest_fsfreeze_freeze_list(false, NULL, errp);
  694. }
  695. int64_t qmp_guest_fsfreeze_freeze_list(bool has_mountpoints,
  696. strList *mountpoints,
  697. Error **errp)
  698. {
  699. int i;
  700. Error *local_err = NULL;
  701. if (!vss_initialized()) {
  702. error_setg(errp, QERR_UNSUPPORTED);
  703. return 0;
  704. }
  705. slog("guest-fsfreeze called");
  706. /* cannot risk guest agent blocking itself on a write in this state */
  707. ga_set_frozen(ga_state);
  708. qga_vss_fsfreeze(&i, true, mountpoints, &local_err);
  709. if (local_err) {
  710. error_propagate(errp, local_err);
  711. goto error;
  712. }
  713. return i;
  714. error:
  715. local_err = NULL;
  716. qmp_guest_fsfreeze_thaw(&local_err);
  717. if (local_err) {
  718. g_debug("cleanup thaw: %s", error_get_pretty(local_err));
  719. error_free(local_err);
  720. }
  721. return 0;
  722. }
  723. /*
  724. * Thaw local file systems using Volume Shadow-copy Service.
  725. */
  726. int64_t qmp_guest_fsfreeze_thaw(Error **errp)
  727. {
  728. int i;
  729. if (!vss_initialized()) {
  730. error_setg(errp, QERR_UNSUPPORTED);
  731. return 0;
  732. }
  733. qga_vss_fsfreeze(&i, false, NULL, errp);
  734. ga_unset_frozen(ga_state);
  735. return i;
  736. }
  737. static void guest_fsfreeze_cleanup(void)
  738. {
  739. Error *err = NULL;
  740. if (!vss_initialized()) {
  741. return;
  742. }
  743. if (ga_is_frozen(ga_state) == GUEST_FSFREEZE_STATUS_FROZEN) {
  744. qmp_guest_fsfreeze_thaw(&err);
  745. if (err) {
  746. slog("failed to clean up frozen filesystems: %s",
  747. error_get_pretty(err));
  748. error_free(err);
  749. }
  750. }
  751. vss_deinit(true);
  752. }
  753. /*
  754. * Walk list of mounted file systems in the guest, and discard unused
  755. * areas.
  756. */
  757. GuestFilesystemTrimResponse *
  758. qmp_guest_fstrim(bool has_minimum, int64_t minimum, Error **errp)
  759. {
  760. GuestFilesystemTrimResponse *resp;
  761. HANDLE handle;
  762. WCHAR guid[MAX_PATH] = L"";
  763. OSVERSIONINFO osvi;
  764. BOOL win8_or_later;
  765. ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
  766. osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  767. GetVersionEx(&osvi);
  768. win8_or_later = (osvi.dwMajorVersion > 6 ||
  769. ((osvi.dwMajorVersion == 6) &&
  770. (osvi.dwMinorVersion >= 2)));
  771. if (!win8_or_later) {
  772. error_setg(errp, "fstrim is only supported for Win8+");
  773. return NULL;
  774. }
  775. handle = FindFirstVolumeW(guid, ARRAYSIZE(guid));
  776. if (handle == INVALID_HANDLE_VALUE) {
  777. error_setg_win32(errp, GetLastError(), "failed to find any volume");
  778. return NULL;
  779. }
  780. resp = g_new0(GuestFilesystemTrimResponse, 1);
  781. do {
  782. GuestFilesystemTrimResult *res;
  783. GuestFilesystemTrimResultList *list;
  784. PWCHAR uc_path;
  785. DWORD char_count = 0;
  786. char *path, *out;
  787. GError *gerr = NULL;
  788. gchar * argv[4];
  789. GetVolumePathNamesForVolumeNameW(guid, NULL, 0, &char_count);
  790. if (GetLastError() != ERROR_MORE_DATA) {
  791. continue;
  792. }
  793. if (GetDriveTypeW(guid) != DRIVE_FIXED) {
  794. continue;
  795. }
  796. uc_path = g_malloc(sizeof(WCHAR) * char_count);
  797. if (!GetVolumePathNamesForVolumeNameW(guid, uc_path, char_count,
  798. &char_count) || !*uc_path) {
  799. /* strange, but this condition could be faced even with size == 2 */
  800. g_free(uc_path);
  801. continue;
  802. }
  803. res = g_new0(GuestFilesystemTrimResult, 1);
  804. path = g_utf16_to_utf8(uc_path, char_count, NULL, NULL, &gerr);
  805. g_free(uc_path);
  806. if (!path) {
  807. res->has_error = true;
  808. res->error = g_strdup(gerr->message);
  809. g_error_free(gerr);
  810. break;
  811. }
  812. res->path = path;
  813. list = g_new0(GuestFilesystemTrimResultList, 1);
  814. list->value = res;
  815. list->next = resp->paths;
  816. resp->paths = list;
  817. memset(argv, 0, sizeof(argv));
  818. argv[0] = (gchar *)"defrag.exe";
  819. argv[1] = (gchar *)"/L";
  820. argv[2] = path;
  821. if (!g_spawn_sync(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL,
  822. &out /* stdout */, NULL /* stdin */,
  823. NULL, &gerr)) {
  824. res->has_error = true;
  825. res->error = g_strdup(gerr->message);
  826. g_error_free(gerr);
  827. } else {
  828. /* defrag.exe is UGLY. Exit code is ALWAYS zero.
  829. Error is reported in the output with something like
  830. (x89000020) etc code in the stdout */
  831. int i;
  832. gchar **lines = g_strsplit(out, "\r\n", 0);
  833. g_free(out);
  834. for (i = 0; lines[i] != NULL; i++) {
  835. if (g_strstr_len(lines[i], -1, "(0x") == NULL) {
  836. continue;
  837. }
  838. res->has_error = true;
  839. res->error = g_strdup(lines[i]);
  840. break;
  841. }
  842. g_strfreev(lines);
  843. }
  844. } while (FindNextVolumeW(handle, guid, ARRAYSIZE(guid)));
  845. FindVolumeClose(handle);
  846. return resp;
  847. }
  848. typedef enum {
  849. GUEST_SUSPEND_MODE_DISK,
  850. GUEST_SUSPEND_MODE_RAM
  851. } GuestSuspendMode;
  852. static void check_suspend_mode(GuestSuspendMode mode, Error **errp)
  853. {
  854. SYSTEM_POWER_CAPABILITIES sys_pwr_caps;
  855. Error *local_err = NULL;
  856. ZeroMemory(&sys_pwr_caps, sizeof(sys_pwr_caps));
  857. if (!GetPwrCapabilities(&sys_pwr_caps)) {
  858. error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
  859. "failed to determine guest suspend capabilities");
  860. goto out;
  861. }
  862. switch (mode) {
  863. case GUEST_SUSPEND_MODE_DISK:
  864. if (!sys_pwr_caps.SystemS4) {
  865. error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
  866. "suspend-to-disk not supported by OS");
  867. }
  868. break;
  869. case GUEST_SUSPEND_MODE_RAM:
  870. if (!sys_pwr_caps.SystemS3) {
  871. error_setg(&local_err, QERR_QGA_COMMAND_FAILED,
  872. "suspend-to-ram not supported by OS");
  873. }
  874. break;
  875. default:
  876. error_setg(&local_err, QERR_INVALID_PARAMETER_VALUE, "mode",
  877. "GuestSuspendMode");
  878. }
  879. out:
  880. error_propagate(errp, local_err);
  881. }
  882. static DWORD WINAPI do_suspend(LPVOID opaque)
  883. {
  884. GuestSuspendMode *mode = opaque;
  885. DWORD ret = 0;
  886. if (!SetSuspendState(*mode == GUEST_SUSPEND_MODE_DISK, TRUE, TRUE)) {
  887. slog("failed to suspend guest, %lu", GetLastError());
  888. ret = -1;
  889. }
  890. g_free(mode);
  891. return ret;
  892. }
  893. void qmp_guest_suspend_disk(Error **errp)
  894. {
  895. Error *local_err = NULL;
  896. GuestSuspendMode *mode = g_new(GuestSuspendMode, 1);
  897. *mode = GUEST_SUSPEND_MODE_DISK;
  898. check_suspend_mode(*mode, &local_err);
  899. acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
  900. execute_async(do_suspend, mode, &local_err);
  901. if (local_err) {
  902. error_propagate(errp, local_err);
  903. g_free(mode);
  904. }
  905. }
  906. void qmp_guest_suspend_ram(Error **errp)
  907. {
  908. Error *local_err = NULL;
  909. GuestSuspendMode *mode = g_new(GuestSuspendMode, 1);
  910. *mode = GUEST_SUSPEND_MODE_RAM;
  911. check_suspend_mode(*mode, &local_err);
  912. acquire_privilege(SE_SHUTDOWN_NAME, &local_err);
  913. execute_async(do_suspend, mode, &local_err);
  914. if (local_err) {
  915. error_propagate(errp, local_err);
  916. g_free(mode);
  917. }
  918. }
  919. void qmp_guest_suspend_hybrid(Error **errp)
  920. {
  921. error_setg(errp, QERR_UNSUPPORTED);
  922. }
  923. static IP_ADAPTER_ADDRESSES *guest_get_adapters_addresses(Error **errp)
  924. {
  925. IP_ADAPTER_ADDRESSES *adptr_addrs = NULL;
  926. ULONG adptr_addrs_len = 0;
  927. DWORD ret;
  928. /* Call the first time to get the adptr_addrs_len. */
  929. GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
  930. NULL, adptr_addrs, &adptr_addrs_len);
  931. adptr_addrs = g_malloc(adptr_addrs_len);
  932. ret = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX,
  933. NULL, adptr_addrs, &adptr_addrs_len);
  934. if (ret != ERROR_SUCCESS) {
  935. error_setg_win32(errp, ret, "failed to get adapters addresses");
  936. g_free(adptr_addrs);
  937. adptr_addrs = NULL;
  938. }
  939. return adptr_addrs;
  940. }
  941. static char *guest_wctomb_dup(WCHAR *wstr)
  942. {
  943. char *str;
  944. size_t i;
  945. i = wcslen(wstr) + 1;
  946. str = g_malloc(i);
  947. WideCharToMultiByte(CP_ACP, WC_COMPOSITECHECK,
  948. wstr, -1, str, i, NULL, NULL);
  949. return str;
  950. }
  951. static char *guest_addr_to_str(IP_ADAPTER_UNICAST_ADDRESS *ip_addr,
  952. Error **errp)
  953. {
  954. char addr_str[INET6_ADDRSTRLEN + INET_ADDRSTRLEN];
  955. DWORD len;
  956. int ret;
  957. if (ip_addr->Address.lpSockaddr->sa_family == AF_INET ||
  958. ip_addr->Address.lpSockaddr->sa_family == AF_INET6) {
  959. len = sizeof(addr_str);
  960. ret = WSAAddressToString(ip_addr->Address.lpSockaddr,
  961. ip_addr->Address.iSockaddrLength,
  962. NULL,
  963. addr_str,
  964. &len);
  965. if (ret != 0) {
  966. error_setg_win32(errp, WSAGetLastError(),
  967. "failed address presentation form conversion");
  968. return NULL;
  969. }
  970. return g_strdup(addr_str);
  971. }
  972. return NULL;
  973. }
  974. #if (_WIN32_WINNT >= 0x0600)
  975. static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
  976. {
  977. /* For Windows Vista/2008 and newer, use the OnLinkPrefixLength
  978. * field to obtain the prefix.
  979. */
  980. return ip_addr->OnLinkPrefixLength;
  981. }
  982. #else
  983. /* When using the Windows XP and 2003 build environment, do the best we can to
  984. * figure out the prefix.
  985. */
  986. static IP_ADAPTER_INFO *guest_get_adapters_info(void)
  987. {
  988. IP_ADAPTER_INFO *adptr_info = NULL;
  989. ULONG adptr_info_len = 0;
  990. DWORD ret;
  991. /* Call the first time to get the adptr_info_len. */
  992. GetAdaptersInfo(adptr_info, &adptr_info_len);
  993. adptr_info = g_malloc(adptr_info_len);
  994. ret = GetAdaptersInfo(adptr_info, &adptr_info_len);
  995. if (ret != ERROR_SUCCESS) {
  996. g_free(adptr_info);
  997. adptr_info = NULL;
  998. }
  999. return adptr_info;
  1000. }
  1001. static int64_t guest_ip_prefix(IP_ADAPTER_UNICAST_ADDRESS *ip_addr)
  1002. {
  1003. int64_t prefix = -1; /* Use for AF_INET6 and unknown/undetermined values. */
  1004. IP_ADAPTER_INFO *adptr_info, *info;
  1005. IP_ADDR_STRING *ip;
  1006. struct in_addr *p;
  1007. if (ip_addr->Address.lpSockaddr->sa_family != AF_INET) {
  1008. return prefix;
  1009. }
  1010. adptr_info = guest_get_adapters_info();
  1011. if (adptr_info == NULL) {
  1012. return prefix;
  1013. }
  1014. /* Match up the passed in ip_addr with one found in adaptr_info.
  1015. * The matching one in adptr_info will have the netmask.
  1016. */
  1017. p = &((struct sockaddr_in *)ip_addr->Address.lpSockaddr)->sin_addr;
  1018. for (info = adptr_info; info; info = info->Next) {
  1019. for (ip = &info->IpAddressList; ip; ip = ip->Next) {
  1020. if (p->S_un.S_addr == inet_addr(ip->IpAddress.String)) {
  1021. prefix = ctpop32(inet_addr(ip->IpMask.String));
  1022. goto out;
  1023. }
  1024. }
  1025. }
  1026. out:
  1027. g_free(adptr_info);
  1028. return prefix;
  1029. }
  1030. #endif
  1031. #define INTERFACE_PATH_BUF_SZ 512
  1032. static DWORD get_interface_index(const char *guid)
  1033. {
  1034. ULONG index;
  1035. DWORD status;
  1036. wchar_t wbuf[INTERFACE_PATH_BUF_SZ];
  1037. snwprintf(wbuf, INTERFACE_PATH_BUF_SZ, L"\\device\\tcpip_%s", guid);
  1038. wbuf[INTERFACE_PATH_BUF_SZ - 1] = 0;
  1039. status = GetAdapterIndex (wbuf, &index);
  1040. if (status != NO_ERROR) {
  1041. return (DWORD)~0;
  1042. } else {
  1043. return index;
  1044. }
  1045. }
  1046. typedef NETIOAPI_API (WINAPI *GetIfEntry2Func)(PMIB_IF_ROW2 Row);
  1047. static int guest_get_network_stats(const char *name,
  1048. GuestNetworkInterfaceStat *stats)
  1049. {
  1050. OSVERSIONINFO os_ver;
  1051. os_ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  1052. GetVersionEx(&os_ver);
  1053. if (os_ver.dwMajorVersion >= 6) {
  1054. MIB_IF_ROW2 a_mid_ifrow;
  1055. GetIfEntry2Func getifentry2_ex;
  1056. DWORD if_index = 0;
  1057. HMODULE module = GetModuleHandle("iphlpapi");
  1058. PVOID func = GetProcAddress(module, "GetIfEntry2");
  1059. if (func == NULL) {
  1060. return -1;
  1061. }
  1062. getifentry2_ex = (GetIfEntry2Func)func;
  1063. if_index = get_interface_index(name);
  1064. if (if_index == (DWORD)~0) {
  1065. return -1;
  1066. }
  1067. memset(&a_mid_ifrow, 0, sizeof(a_mid_ifrow));
  1068. a_mid_ifrow.InterfaceIndex = if_index;
  1069. if (NO_ERROR == getifentry2_ex(&a_mid_ifrow)) {
  1070. stats->rx_bytes = a_mid_ifrow.InOctets;
  1071. stats->rx_packets = a_mid_ifrow.InUcastPkts;
  1072. stats->rx_errs = a_mid_ifrow.InErrors;
  1073. stats->rx_dropped = a_mid_ifrow.InDiscards;
  1074. stats->tx_bytes = a_mid_ifrow.OutOctets;
  1075. stats->tx_packets = a_mid_ifrow.OutUcastPkts;
  1076. stats->tx_errs = a_mid_ifrow.OutErrors;
  1077. stats->tx_dropped = a_mid_ifrow.OutDiscards;
  1078. return 0;
  1079. }
  1080. }
  1081. return -1;
  1082. }
  1083. GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
  1084. {
  1085. IP_ADAPTER_ADDRESSES *adptr_addrs, *addr;
  1086. IP_ADAPTER_UNICAST_ADDRESS *ip_addr = NULL;
  1087. GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
  1088. GuestIpAddressList *head_addr, *cur_addr;
  1089. GuestNetworkInterfaceList *info;
  1090. GuestNetworkInterfaceStat *interface_stat = NULL;
  1091. GuestIpAddressList *address_item = NULL;
  1092. unsigned char *mac_addr;
  1093. char *addr_str;
  1094. WORD wsa_version;
  1095. WSADATA wsa_data;
  1096. int ret;
  1097. adptr_addrs = guest_get_adapters_addresses(errp);
  1098. if (adptr_addrs == NULL) {
  1099. return NULL;
  1100. }
  1101. /* Make WSA APIs available. */
  1102. wsa_version = MAKEWORD(2, 2);
  1103. ret = WSAStartup(wsa_version, &wsa_data);
  1104. if (ret != 0) {
  1105. error_setg_win32(errp, ret, "failed socket startup");
  1106. goto out;
  1107. }
  1108. for (addr = adptr_addrs; addr; addr = addr->Next) {
  1109. info = g_malloc0(sizeof(*info));
  1110. if (cur_item == NULL) {
  1111. head = cur_item = info;
  1112. } else {
  1113. cur_item->next = info;
  1114. cur_item = info;
  1115. }
  1116. info->value = g_malloc0(sizeof(*info->value));
  1117. info->value->name = guest_wctomb_dup(addr->FriendlyName);
  1118. if (addr->PhysicalAddressLength != 0) {
  1119. mac_addr = addr->PhysicalAddress;
  1120. info->value->hardware_address =
  1121. g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
  1122. (int) mac_addr[0], (int) mac_addr[1],
  1123. (int) mac_addr[2], (int) mac_addr[3],
  1124. (int) mac_addr[4], (int) mac_addr[5]);
  1125. info->value->has_hardware_address = true;
  1126. }
  1127. head_addr = NULL;
  1128. cur_addr = NULL;
  1129. for (ip_addr = addr->FirstUnicastAddress;
  1130. ip_addr;
  1131. ip_addr = ip_addr->Next) {
  1132. addr_str = guest_addr_to_str(ip_addr, errp);
  1133. if (addr_str == NULL) {
  1134. continue;
  1135. }
  1136. address_item = g_malloc0(sizeof(*address_item));
  1137. if (!cur_addr) {
  1138. head_addr = cur_addr = address_item;
  1139. } else {
  1140. cur_addr->next = address_item;
  1141. cur_addr = address_item;
  1142. }
  1143. address_item->value = g_malloc0(sizeof(*address_item->value));
  1144. address_item->value->ip_address = addr_str;
  1145. address_item->value->prefix = guest_ip_prefix(ip_addr);
  1146. if (ip_addr->Address.lpSockaddr->sa_family == AF_INET) {
  1147. address_item->value->ip_address_type =
  1148. GUEST_IP_ADDRESS_TYPE_IPV4;
  1149. } else if (ip_addr->Address.lpSockaddr->sa_family == AF_INET6) {
  1150. address_item->value->ip_address_type =
  1151. GUEST_IP_ADDRESS_TYPE_IPV6;
  1152. }
  1153. }
  1154. if (head_addr) {
  1155. info->value->has_ip_addresses = true;
  1156. info->value->ip_addresses = head_addr;
  1157. }
  1158. if (!info->value->has_statistics) {
  1159. interface_stat = g_malloc0(sizeof(*interface_stat));
  1160. if (guest_get_network_stats(addr->AdapterName,
  1161. interface_stat) == -1) {
  1162. info->value->has_statistics = false;
  1163. g_free(interface_stat);
  1164. } else {
  1165. info->value->statistics = interface_stat;
  1166. info->value->has_statistics = true;
  1167. }
  1168. }
  1169. }
  1170. WSACleanup();
  1171. out:
  1172. g_free(adptr_addrs);
  1173. return head;
  1174. }
  1175. int64_t qmp_guest_get_time(Error **errp)
  1176. {
  1177. SYSTEMTIME ts = {0};
  1178. FILETIME tf;
  1179. GetSystemTime(&ts);
  1180. if (ts.wYear < 1601 || ts.wYear > 30827) {
  1181. error_setg(errp, "Failed to get time");
  1182. return -1;
  1183. }
  1184. if (!SystemTimeToFileTime(&ts, &tf)) {
  1185. error_setg(errp, "Failed to convert system time: %d", (int)GetLastError());
  1186. return -1;
  1187. }
  1188. return ((((int64_t)tf.dwHighDateTime << 32) | tf.dwLowDateTime)
  1189. - W32_FT_OFFSET) * 100;
  1190. }
  1191. void qmp_guest_set_time(bool has_time, int64_t time_ns, Error **errp)
  1192. {
  1193. Error *local_err = NULL;
  1194. SYSTEMTIME ts;
  1195. FILETIME tf;
  1196. LONGLONG time;
  1197. if (!has_time) {
  1198. /* Unfortunately, Windows libraries don't provide an easy way to access
  1199. * RTC yet:
  1200. *
  1201. * https://msdn.microsoft.com/en-us/library/aa908981.aspx
  1202. *
  1203. * Instead, a workaround is to use the Windows win32tm command to
  1204. * resync the time using the Windows Time service.
  1205. */
  1206. LPVOID msg_buffer;
  1207. DWORD ret_flags;
  1208. HRESULT hr = system("w32tm /resync /nowait");
  1209. if (GetLastError() != 0) {
  1210. strerror_s((LPTSTR) & msg_buffer, 0, errno);
  1211. error_setg(errp, "system(...) failed: %s", (LPCTSTR)msg_buffer);
  1212. } else if (hr != 0) {
  1213. if (hr == HRESULT_FROM_WIN32(ERROR_SERVICE_NOT_ACTIVE)) {
  1214. error_setg(errp, "Windows Time service not running on the "
  1215. "guest");
  1216. } else {
  1217. if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1218. FORMAT_MESSAGE_FROM_SYSTEM |
  1219. FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
  1220. (DWORD)hr, MAKELANGID(LANG_NEUTRAL,
  1221. SUBLANG_DEFAULT), (LPTSTR) & msg_buffer, 0,
  1222. NULL)) {
  1223. error_setg(errp, "w32tm failed with error (0x%lx), couldn'"
  1224. "t retrieve error message", hr);
  1225. } else {
  1226. error_setg(errp, "w32tm failed with error (0x%lx): %s", hr,
  1227. (LPCTSTR)msg_buffer);
  1228. LocalFree(msg_buffer);
  1229. }
  1230. }
  1231. } else if (!InternetGetConnectedState(&ret_flags, 0)) {
  1232. error_setg(errp, "No internet connection on guest, sync not "
  1233. "accurate");
  1234. }
  1235. return;
  1236. }
  1237. /* Validate time passed by user. */
  1238. if (time_ns < 0 || time_ns / 100 > INT64_MAX - W32_FT_OFFSET) {
  1239. error_setg(errp, "Time %" PRId64 "is invalid", time_ns);
  1240. return;
  1241. }
  1242. time = time_ns / 100 + W32_FT_OFFSET;
  1243. tf.dwLowDateTime = (DWORD) time;
  1244. tf.dwHighDateTime = (DWORD) (time >> 32);
  1245. if (!FileTimeToSystemTime(&tf, &ts)) {
  1246. error_setg(errp, "Failed to convert system time %d",
  1247. (int)GetLastError());
  1248. return;
  1249. }
  1250. acquire_privilege(SE_SYSTEMTIME_NAME, &local_err);
  1251. if (local_err) {
  1252. error_propagate(errp, local_err);
  1253. return;
  1254. }
  1255. if (!SetSystemTime(&ts)) {
  1256. error_setg(errp, "Failed to set time to guest: %d", (int)GetLastError());
  1257. return;
  1258. }
  1259. }
  1260. GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
  1261. {
  1262. PSYSTEM_LOGICAL_PROCESSOR_INFORMATION pslpi, ptr;
  1263. DWORD length;
  1264. GuestLogicalProcessorList *head, **link;
  1265. Error *local_err = NULL;
  1266. int64_t current;
  1267. ptr = pslpi = NULL;
  1268. length = 0;
  1269. current = 0;
  1270. head = NULL;
  1271. link = &head;
  1272. if ((GetLogicalProcessorInformation(pslpi, &length) == FALSE) &&
  1273. (GetLastError() == ERROR_INSUFFICIENT_BUFFER) &&
  1274. (length > sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION))) {
  1275. ptr = pslpi = g_malloc0(length);
  1276. if (GetLogicalProcessorInformation(pslpi, &length) == FALSE) {
  1277. error_setg(&local_err, "Failed to get processor information: %d",
  1278. (int)GetLastError());
  1279. }
  1280. } else {
  1281. error_setg(&local_err,
  1282. "Failed to get processor information buffer length: %d",
  1283. (int)GetLastError());
  1284. }
  1285. while ((local_err == NULL) && (length > 0)) {
  1286. if (pslpi->Relationship == RelationProcessorCore) {
  1287. ULONG_PTR cpu_bits = pslpi->ProcessorMask;
  1288. while (cpu_bits > 0) {
  1289. if (!!(cpu_bits & 1)) {
  1290. GuestLogicalProcessor *vcpu;
  1291. GuestLogicalProcessorList *entry;
  1292. vcpu = g_malloc0(sizeof *vcpu);
  1293. vcpu->logical_id = current++;
  1294. vcpu->online = true;
  1295. vcpu->has_can_offline = true;
  1296. entry = g_malloc0(sizeof *entry);
  1297. entry->value = vcpu;
  1298. *link = entry;
  1299. link = &entry->next;
  1300. }
  1301. cpu_bits >>= 1;
  1302. }
  1303. }
  1304. length -= sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
  1305. pslpi++; /* next entry */
  1306. }
  1307. g_free(ptr);
  1308. if (local_err == NULL) {
  1309. if (head != NULL) {
  1310. return head;
  1311. }
  1312. /* there's no guest with zero VCPUs */
  1313. error_setg(&local_err, "Guest reported zero VCPUs");
  1314. }
  1315. qapi_free_GuestLogicalProcessorList(head);
  1316. error_propagate(errp, local_err);
  1317. return NULL;
  1318. }
  1319. int64_t qmp_guest_set_vcpus(GuestLogicalProcessorList *vcpus, Error **errp)
  1320. {
  1321. error_setg(errp, QERR_UNSUPPORTED);
  1322. return -1;
  1323. }
  1324. static gchar *
  1325. get_net_error_message(gint error)
  1326. {
  1327. HMODULE module = NULL;
  1328. gchar *retval = NULL;
  1329. wchar_t *msg = NULL;
  1330. int flags;
  1331. size_t nchars;
  1332. flags = FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1333. FORMAT_MESSAGE_IGNORE_INSERTS |
  1334. FORMAT_MESSAGE_FROM_SYSTEM;
  1335. if (error >= NERR_BASE && error <= MAX_NERR) {
  1336. module = LoadLibraryExW(L"netmsg.dll", NULL, LOAD_LIBRARY_AS_DATAFILE);
  1337. if (module != NULL) {
  1338. flags |= FORMAT_MESSAGE_FROM_HMODULE;
  1339. }
  1340. }
  1341. FormatMessageW(flags, module, error, 0, (LPWSTR)&msg, 0, NULL);
  1342. if (msg != NULL) {
  1343. nchars = wcslen(msg);
  1344. if (nchars >= 2 &&
  1345. msg[nchars - 1] == L'\n' &&
  1346. msg[nchars - 2] == L'\r') {
  1347. msg[nchars - 2] = L'\0';
  1348. }
  1349. retval = g_utf16_to_utf8(msg, -1, NULL, NULL, NULL);
  1350. LocalFree(msg);
  1351. }
  1352. if (module != NULL) {
  1353. FreeLibrary(module);
  1354. }
  1355. return retval;
  1356. }
  1357. void qmp_guest_set_user_password(const char *username,
  1358. const char *password,
  1359. bool crypted,
  1360. Error **errp)
  1361. {
  1362. NET_API_STATUS nas;
  1363. char *rawpasswddata = NULL;
  1364. size_t rawpasswdlen;
  1365. wchar_t *user = NULL, *wpass = NULL;
  1366. USER_INFO_1003 pi1003 = { 0, };
  1367. GError *gerr = NULL;
  1368. if (crypted) {
  1369. error_setg(errp, QERR_UNSUPPORTED);
  1370. return;
  1371. }
  1372. rawpasswddata = (char *)qbase64_decode(password, -1, &rawpasswdlen, errp);
  1373. if (!rawpasswddata) {
  1374. return;
  1375. }
  1376. rawpasswddata = g_renew(char, rawpasswddata, rawpasswdlen + 1);
  1377. rawpasswddata[rawpasswdlen] = '\0';
  1378. user = g_utf8_to_utf16(username, -1, NULL, NULL, &gerr);
  1379. if (!user) {
  1380. goto done;
  1381. }
  1382. wpass = g_utf8_to_utf16(rawpasswddata, -1, NULL, NULL, &gerr);
  1383. if (!wpass) {
  1384. goto done;
  1385. }
  1386. pi1003.usri1003_password = wpass;
  1387. nas = NetUserSetInfo(NULL, user,
  1388. 1003, (LPBYTE)&pi1003,
  1389. NULL);
  1390. if (nas != NERR_Success) {
  1391. gchar *msg = get_net_error_message(nas);
  1392. error_setg(errp, "failed to set password: %s", msg);
  1393. g_free(msg);
  1394. }
  1395. done:
  1396. if (gerr) {
  1397. error_setg(errp, QERR_QGA_COMMAND_FAILED, gerr->message);
  1398. g_error_free(gerr);
  1399. }
  1400. g_free(user);
  1401. g_free(wpass);
  1402. g_free(rawpasswddata);
  1403. }
  1404. GuestMemoryBlockList *qmp_guest_get_memory_blocks(Error **errp)
  1405. {
  1406. error_setg(errp, QERR_UNSUPPORTED);
  1407. return NULL;
  1408. }
  1409. GuestMemoryBlockResponseList *
  1410. qmp_guest_set_memory_blocks(GuestMemoryBlockList *mem_blks, Error **errp)
  1411. {
  1412. error_setg(errp, QERR_UNSUPPORTED);
  1413. return NULL;
  1414. }
  1415. GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
  1416. {
  1417. error_setg(errp, QERR_UNSUPPORTED);
  1418. return NULL;
  1419. }
  1420. /* add unsupported commands to the blacklist */
  1421. GList *ga_command_blacklist_init(GList *blacklist)
  1422. {
  1423. const char *list_unsupported[] = {
  1424. "guest-suspend-hybrid",
  1425. "guest-set-vcpus",
  1426. "guest-get-memory-blocks", "guest-set-memory-blocks",
  1427. "guest-get-memory-block-size",
  1428. NULL};
  1429. char **p = (char **)list_unsupported;
  1430. while (*p) {
  1431. blacklist = g_list_append(blacklist, g_strdup(*p++));
  1432. }
  1433. if (!vss_init(true)) {
  1434. g_debug("vss_init failed, vss commands are going to be disabled");
  1435. const char *list[] = {
  1436. "guest-get-fsinfo", "guest-fsfreeze-status",
  1437. "guest-fsfreeze-freeze", "guest-fsfreeze-thaw", NULL};
  1438. p = (char **)list;
  1439. while (*p) {
  1440. blacklist = g_list_append(blacklist, g_strdup(*p++));
  1441. }
  1442. }
  1443. return blacklist;
  1444. }
  1445. /* register init/cleanup routines for stateful command groups */
  1446. void ga_command_state_init(GAState *s, GACommandState *cs)
  1447. {
  1448. if (!vss_initialized()) {
  1449. ga_command_state_add(cs, NULL, guest_fsfreeze_cleanup);
  1450. }
  1451. }
  1452. /* MINGW is missing two fields: IncomingFrames & OutgoingFrames */
  1453. typedef struct _GA_WTSINFOA {
  1454. WTS_CONNECTSTATE_CLASS State;
  1455. DWORD SessionId;
  1456. DWORD IncomingBytes;
  1457. DWORD OutgoingBytes;
  1458. DWORD IncomingFrames;
  1459. DWORD OutgoingFrames;
  1460. DWORD IncomingCompressedBytes;
  1461. DWORD OutgoingCompressedBy;
  1462. CHAR WinStationName[WINSTATIONNAME_LENGTH];
  1463. CHAR Domain[DOMAIN_LENGTH];
  1464. CHAR UserName[USERNAME_LENGTH + 1];
  1465. LARGE_INTEGER ConnectTime;
  1466. LARGE_INTEGER DisconnectTime;
  1467. LARGE_INTEGER LastInputTime;
  1468. LARGE_INTEGER LogonTime;
  1469. LARGE_INTEGER CurrentTime;
  1470. } GA_WTSINFOA;
  1471. GuestUserList *qmp_guest_get_users(Error **err)
  1472. {
  1473. #if (_WIN32_WINNT >= 0x0600)
  1474. #define QGA_NANOSECONDS 10000000
  1475. GHashTable *cache = NULL;
  1476. GuestUserList *head = NULL, *cur_item = NULL;
  1477. DWORD buffer_size = 0, count = 0, i = 0;
  1478. GA_WTSINFOA *info = NULL;
  1479. WTS_SESSION_INFOA *entries = NULL;
  1480. GuestUserList *item = NULL;
  1481. GuestUser *user = NULL;
  1482. gpointer value = NULL;
  1483. INT64 login = 0;
  1484. double login_time = 0;
  1485. cache = g_hash_table_new(g_str_hash, g_str_equal);
  1486. if (WTSEnumerateSessionsA(NULL, 0, 1, &entries, &count)) {
  1487. for (i = 0; i < count; ++i) {
  1488. buffer_size = 0;
  1489. info = NULL;
  1490. if (WTSQuerySessionInformationA(
  1491. NULL,
  1492. entries[i].SessionId,
  1493. WTSSessionInfo,
  1494. (LPSTR *)&info,
  1495. &buffer_size
  1496. )) {
  1497. if (strlen(info->UserName) == 0) {
  1498. WTSFreeMemory(info);
  1499. continue;
  1500. }
  1501. login = info->LogonTime.QuadPart;
  1502. login -= W32_FT_OFFSET;
  1503. login_time = ((double)login) / QGA_NANOSECONDS;
  1504. if (g_hash_table_contains(cache, info->UserName)) {
  1505. value = g_hash_table_lookup(cache, info->UserName);
  1506. user = (GuestUser *)value;
  1507. if (user->login_time > login_time) {
  1508. user->login_time = login_time;
  1509. }
  1510. } else {
  1511. item = g_new0(GuestUserList, 1);
  1512. item->value = g_new0(GuestUser, 1);
  1513. item->value->user = g_strdup(info->UserName);
  1514. item->value->domain = g_strdup(info->Domain);
  1515. item->value->has_domain = true;
  1516. item->value->login_time = login_time;
  1517. g_hash_table_add(cache, item->value->user);
  1518. if (!cur_item) {
  1519. head = cur_item = item;
  1520. } else {
  1521. cur_item->next = item;
  1522. cur_item = item;
  1523. }
  1524. }
  1525. }
  1526. WTSFreeMemory(info);
  1527. }
  1528. WTSFreeMemory(entries);
  1529. }
  1530. g_hash_table_destroy(cache);
  1531. return head;
  1532. #else
  1533. error_setg(err, QERR_UNSUPPORTED);
  1534. return NULL;
  1535. #endif
  1536. }
  1537. typedef struct _ga_matrix_lookup_t {
  1538. int major;
  1539. int minor;
  1540. char const *version;
  1541. char const *version_id;
  1542. } ga_matrix_lookup_t;
  1543. static ga_matrix_lookup_t const WIN_VERSION_MATRIX[2][8] = {
  1544. {
  1545. /* Desktop editions */
  1546. { 5, 0, "Microsoft Windows 2000", "2000"},
  1547. { 5, 1, "Microsoft Windows XP", "xp"},
  1548. { 6, 0, "Microsoft Windows Vista", "vista"},
  1549. { 6, 1, "Microsoft Windows 7" "7"},
  1550. { 6, 2, "Microsoft Windows 8", "8"},
  1551. { 6, 3, "Microsoft Windows 8.1", "8.1"},
  1552. {10, 0, "Microsoft Windows 10", "10"},
  1553. { 0, 0, 0}
  1554. },{
  1555. /* Server editions */
  1556. { 5, 2, "Microsoft Windows Server 2003", "2003"},
  1557. { 6, 0, "Microsoft Windows Server 2008", "2008"},
  1558. { 6, 1, "Microsoft Windows Server 2008 R2", "2008r2"},
  1559. { 6, 2, "Microsoft Windows Server 2012", "2012"},
  1560. { 6, 3, "Microsoft Windows Server 2012 R2", "2012r2"},
  1561. {10, 0, "Microsoft Windows Server 2016", "2016"},
  1562. { 0, 0, 0},
  1563. { 0, 0, 0}
  1564. }
  1565. };
  1566. static void ga_get_win_version(RTL_OSVERSIONINFOEXW *info, Error **errp)
  1567. {
  1568. typedef NTSTATUS(WINAPI * rtl_get_version_t)(
  1569. RTL_OSVERSIONINFOEXW *os_version_info_ex);
  1570. info->dwOSVersionInfoSize = sizeof(RTL_OSVERSIONINFOEXW);
  1571. HMODULE module = GetModuleHandle("ntdll");
  1572. PVOID fun = GetProcAddress(module, "RtlGetVersion");
  1573. if (fun == NULL) {
  1574. error_setg(errp, QERR_QGA_COMMAND_FAILED,
  1575. "Failed to get address of RtlGetVersion");
  1576. return;
  1577. }
  1578. rtl_get_version_t rtl_get_version = (rtl_get_version_t)fun;
  1579. rtl_get_version(info);
  1580. return;
  1581. }
  1582. static char *ga_get_win_name(OSVERSIONINFOEXW const *os_version, bool id)
  1583. {
  1584. DWORD major = os_version->dwMajorVersion;
  1585. DWORD minor = os_version->dwMinorVersion;
  1586. int tbl_idx = (os_version->wProductType != VER_NT_WORKSTATION);
  1587. ga_matrix_lookup_t const *table = WIN_VERSION_MATRIX[tbl_idx];
  1588. while (table->version != NULL) {
  1589. if (major == table->major && minor == table->minor) {
  1590. if (id) {
  1591. return g_strdup(table->version_id);
  1592. } else {
  1593. return g_strdup(table->version);
  1594. }
  1595. }
  1596. ++table;
  1597. }
  1598. slog("failed to lookup Windows version: major=%lu, minor=%lu",
  1599. major, minor);
  1600. return g_strdup("N/A");
  1601. }
  1602. static char *ga_get_win_product_name(Error **errp)
  1603. {
  1604. HKEY key = NULL;
  1605. DWORD size = 128;
  1606. char *result = g_malloc0(size);
  1607. LONG err = ERROR_SUCCESS;
  1608. err = RegOpenKeyA(HKEY_LOCAL_MACHINE,
  1609. "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion",
  1610. &key);
  1611. if (err != ERROR_SUCCESS) {
  1612. error_setg_win32(errp, err, "failed to open registry key");
  1613. goto fail;
  1614. }
  1615. err = RegQueryValueExA(key, "ProductName", NULL, NULL,
  1616. (LPBYTE)result, &size);
  1617. if (err == ERROR_MORE_DATA) {
  1618. slog("ProductName longer than expected (%lu bytes), retrying",
  1619. size);
  1620. g_free(result);
  1621. result = NULL;
  1622. if (size > 0) {
  1623. result = g_malloc0(size);
  1624. err = RegQueryValueExA(key, "ProductName", NULL, NULL,
  1625. (LPBYTE)result, &size);
  1626. }
  1627. }
  1628. if (err != ERROR_SUCCESS) {
  1629. error_setg_win32(errp, err, "failed to retrive ProductName");
  1630. goto fail;
  1631. }
  1632. return result;
  1633. fail:
  1634. g_free(result);
  1635. return NULL;
  1636. }
  1637. static char *ga_get_current_arch(void)
  1638. {
  1639. SYSTEM_INFO info;
  1640. GetNativeSystemInfo(&info);
  1641. char *result = NULL;
  1642. switch (info.wProcessorArchitecture) {
  1643. case PROCESSOR_ARCHITECTURE_AMD64:
  1644. result = g_strdup("x86_64");
  1645. break;
  1646. case PROCESSOR_ARCHITECTURE_ARM:
  1647. result = g_strdup("arm");
  1648. break;
  1649. case PROCESSOR_ARCHITECTURE_IA64:
  1650. result = g_strdup("ia64");
  1651. break;
  1652. case PROCESSOR_ARCHITECTURE_INTEL:
  1653. result = g_strdup("x86");
  1654. break;
  1655. case PROCESSOR_ARCHITECTURE_UNKNOWN:
  1656. default:
  1657. slog("unknown processor architecture 0x%0x",
  1658. info.wProcessorArchitecture);
  1659. result = g_strdup("unknown");
  1660. break;
  1661. }
  1662. return result;
  1663. }
  1664. GuestOSInfo *qmp_guest_get_osinfo(Error **errp)
  1665. {
  1666. Error *local_err = NULL;
  1667. OSVERSIONINFOEXW os_version = {0};
  1668. bool server;
  1669. char *product_name;
  1670. GuestOSInfo *info;
  1671. ga_get_win_version(&os_version, &local_err);
  1672. if (local_err) {
  1673. error_propagate(errp, local_err);
  1674. return NULL;
  1675. }
  1676. server = os_version.wProductType != VER_NT_WORKSTATION;
  1677. product_name = ga_get_win_product_name(&local_err);
  1678. if (product_name == NULL) {
  1679. error_propagate(errp, local_err);
  1680. return NULL;
  1681. }
  1682. info = g_new0(GuestOSInfo, 1);
  1683. info->has_kernel_version = true;
  1684. info->kernel_version = g_strdup_printf("%lu.%lu",
  1685. os_version.dwMajorVersion,
  1686. os_version.dwMinorVersion);
  1687. info->has_kernel_release = true;
  1688. info->kernel_release = g_strdup_printf("%lu",
  1689. os_version.dwBuildNumber);
  1690. info->has_machine = true;
  1691. info->machine = ga_get_current_arch();
  1692. info->has_id = true;
  1693. info->id = g_strdup("mswindows");
  1694. info->has_name = true;
  1695. info->name = g_strdup("Microsoft Windows");
  1696. info->has_pretty_name = true;
  1697. info->pretty_name = product_name;
  1698. info->has_version = true;
  1699. info->version = ga_get_win_name(&os_version, false);
  1700. info->has_version_id = true;
  1701. info->version_id = ga_get_win_name(&os_version, true);
  1702. info->has_variant = true;
  1703. info->variant = g_strdup(server ? "server" : "client");
  1704. info->has_variant_id = true;
  1705. info->variant_id = g_strdup(server ? "server" : "client");
  1706. return info;
  1707. }