VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxControl/VBoxControl.cpp@ 44448

Last change on this file since 44448 was 44328, checked in by vboxsync, 12 years ago

VBoxControl.cpp: Allow unix shell users to use 'unset' instead of 'delete'.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 52.7 KB
Line 
1/* $Id: VBoxControl.cpp 44328 2013-01-22 11:05:09Z vboxsync $ */
2/** @file
3 * VBoxControl - Guest Additions Command Line Management Interface.
4 */
5
6/*
7 * Copyright (C) 2008-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#include <iprt/alloca.h>
22#include <iprt/cpp/autores.h>
23#include <iprt/buildconfig.h>
24#include <iprt/initterm.h>
25#include <iprt/mem.h>
26#include <iprt/message.h>
27#include <iprt/path.h>
28#include <iprt/string.h>
29#include <iprt/stream.h>
30#include <VBox/log.h>
31#include <VBox/version.h>
32#include <VBox/VBoxGuestLib.h>
33#ifdef RT_OS_WINDOWS
34# include <Windows.h>
35#endif
36#ifdef VBOX_WITH_GUEST_PROPS
37# include <VBox/HostServices/GuestPropertySvc.h>
38#endif
39
40/*******************************************************************************
41* Global Variables *
42*******************************************************************************/
43/** The program name (derived from argv[0]). */
44char const *g_pszProgName = "";
45/** The current verbosity level. */
46int g_cVerbosity = 0;
47
48
49/**
50 * Displays the program usage message.
51 *
52 * @param u64Which
53 *
54 * @{
55 */
56
57/** Helper function */
58static void doUsage(char const *line, char const *name = "", char const *command = "")
59{
60 /* Allow for up to 15 characters command name length (VBoxControl.exe) with
61 * perfect column alignment. Beyond that there's at least one space between
62 * the command if there are command line parameters. */
63 RTPrintf("%s %-*s%s%s\n", name, strlen(line) ? 35 - strlen(name) : 1,
64 command, strlen(line) ? " " : "", line);
65}
66
67/** Enumerate the different parts of the usage we might want to print out */
68enum VBoxControlUsage
69{
70#ifdef RT_OS_WINDOWS
71 GET_VIDEO_ACCEL,
72 SET_VIDEO_ACCEL,
73 LIST_CUST_MODES,
74 ADD_CUST_MODE,
75 REMOVE_CUST_MODE,
76 SET_VIDEO_MODE,
77#endif
78#ifdef VBOX_WITH_GUEST_PROPS
79 GUEST_PROP,
80#endif
81#ifdef VBOX_WITH_SHARED_FOLDERS
82 GUEST_SHAREDFOLDERS,
83#endif
84#if !defined(VBOX_CONTROL_TEST)
85 WRITE_CORE_DUMP,
86#endif
87 TAKE_SNAPSHOT,
88 SAVE_STATE,
89 SUSPEND,
90 POWER_OFF,
91 VERSION,
92 HELP,
93 USAGE_ALL = UINT32_MAX
94};
95
96static void usage(enum VBoxControlUsage eWhich = USAGE_ALL)
97{
98 RTPrintf("Usage:\n\n");
99 doUsage("print version number and exit", g_pszProgName, "[-v|--version]");
100 doUsage("suppress the logo", g_pszProgName, "--nologo ...");
101 RTPrintf("\n");
102
103/* Exclude the Windows bits from the test version. Anyone who needs to test
104 * them can fix this. */
105#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
106 if (eWhich == GET_VIDEO_ACCEL || eWhich == USAGE_ALL)
107 doUsage("", g_pszProgName, "getvideoacceleration");
108 if (eWhich == SET_VIDEO_ACCEL || eWhich == USAGE_ALL)
109 doUsage("<on|off>", g_pszProgName, "setvideoacceleration");
110 if (eWhich == LIST_CUST_MODES || eWhich == USAGE_ALL)
111 doUsage("", g_pszProgName, "listcustommodes");
112 if (eWhich == ADD_CUST_MODE || eWhich == USAGE_ALL)
113 doUsage("<width> <height> <bpp>", g_pszProgName, "addcustommode");
114 if (eWhich == REMOVE_CUST_MODE || eWhich == USAGE_ALL)
115 doUsage("<width> <height> <bpp>", g_pszProgName, "removecustommode");
116 if (eWhich == SET_VIDEO_MODE || eWhich == USAGE_ALL)
117 doUsage("<width> <height> <bpp> <screen>", g_pszProgName, "setvideomode");
118#endif
119#ifdef VBOX_WITH_GUEST_PROPS
120 if (eWhich == GUEST_PROP || eWhich == USAGE_ALL)
121 {
122 doUsage("get <property> [--verbose]", g_pszProgName, "guestproperty");
123 doUsage("set <property> [<value> [--flags <flags>]]", g_pszProgName, "guestproperty");
124 doUsage("delete|unset <property>", g_pszProgName, "guestproperty");
125 doUsage("enumerate [--patterns <patterns>]", g_pszProgName, "guestproperty");
126 doUsage("wait <patterns>", g_pszProgName, "guestproperty");
127 doUsage("[--timestamp <last timestamp>]");
128 doUsage("[--timeout <timeout in ms>");
129 }
130#endif
131#ifdef VBOX_WITH_SHARED_FOLDERS
132 if (eWhich == GUEST_SHAREDFOLDERS || eWhich == USAGE_ALL)
133 {
134 doUsage("list [-automount]", g_pszProgName, "sharedfolder");
135 }
136#endif
137
138#if !defined(VBOX_CONTROL_TEST)
139 if (eWhich == WRITE_CORE_DUMP || eWhich == USAGE_ALL)
140 doUsage("", g_pszProgName, "writecoredump");
141#endif
142 if (eWhich == TAKE_SNAPSHOT || eWhich == USAGE_ALL)
143 doUsage("", g_pszProgName, "takesnapshot");
144 if (eWhich == SAVE_STATE || eWhich == USAGE_ALL)
145 doUsage("", g_pszProgName, "savestate");
146 if (eWhich == SUSPEND || eWhich == USAGE_ALL)
147 doUsage("", g_pszProgName, "suspend");
148 if (eWhich == POWER_OFF || eWhich == USAGE_ALL)
149 doUsage("", g_pszProgName, "poweroff");
150 if (eWhich == HELP || eWhich == USAGE_ALL)
151 doUsage("[command]", g_pszProgName, "help");
152 if (eWhich == VERSION || eWhich == USAGE_ALL)
153 doUsage("", g_pszProgName, "version");
154}
155
156/** @} */
157
158/**
159 * Displays an error message.
160 *
161 * @returns RTEXITCODE_FAILURE.
162 * @param pszFormat The message text. No newline.
163 * @param ... Format arguments.
164 */
165static RTEXITCODE VBoxControlError(const char *pszFormat, ...)
166{
167 va_list va;
168 va_start(va, pszFormat);
169 RTMsgErrorV(pszFormat, va);
170 va_end(va);
171 return RTEXITCODE_FAILURE;
172}
173
174
175/**
176 * Displays an syntax error message.
177 *
178 * @returns RTEXITCODE_FAILURE.
179 * @param pszFormat The message text. No newline.
180 * @param ... Format arguments.
181 */
182static RTEXITCODE VBoxControlSyntaxError(const char *pszFormat, ...)
183{
184 va_list va;
185 va_start(va, pszFormat);
186 RTMsgErrorV(pszFormat, va);
187 va_end(va);
188 return RTEXITCODE_FAILURE;
189}
190
191#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
192
193LONG (WINAPI * gpfnChangeDisplaySettingsEx)(LPCTSTR lpszDeviceName, LPDEVMODE lpDevMode, HWND hwnd, DWORD dwflags, LPVOID lParam);
194
195static unsigned nextAdjacentRectXP (RECTL *paRects, unsigned nRects, unsigned iRect)
196{
197 unsigned i;
198 for (i = 0; i < nRects; i++)
199 {
200 if (paRects[iRect].right == paRects[i].left)
201 {
202 return i;
203 }
204 }
205 return ~0;
206}
207
208static unsigned nextAdjacentRectXN (RECTL *paRects, unsigned nRects, unsigned iRect)
209{
210 unsigned i;
211 for (i = 0; i < nRects; i++)
212 {
213 if (paRects[iRect].left == paRects[i].right)
214 {
215 return i;
216 }
217 }
218 return ~0;
219}
220
221static unsigned nextAdjacentRectYP (RECTL *paRects, unsigned nRects, unsigned iRect)
222{
223 unsigned i;
224 for (i = 0; i < nRects; i++)
225 {
226 if (paRects[iRect].bottom == paRects[i].top)
227 {
228 return i;
229 }
230 }
231 return ~0;
232}
233
234unsigned nextAdjacentRectYN (RECTL *paRects, unsigned nRects, unsigned iRect)
235{
236 unsigned i;
237 for (i = 0; i < nRects; i++)
238 {
239 if (paRects[iRect].top == paRects[i].bottom)
240 {
241 return i;
242 }
243 }
244 return ~0;
245}
246
247void resizeRect(RECTL *paRects, unsigned nRects, unsigned iPrimary, unsigned iResized, int NewWidth, int NewHeight)
248{
249 RECTL *paNewRects = (RECTL *)alloca (sizeof (RECTL) * nRects);
250 memcpy (paNewRects, paRects, sizeof (RECTL) * nRects);
251 paNewRects[iResized].right += NewWidth - (paNewRects[iResized].right - paNewRects[iResized].left);
252 paNewRects[iResized].bottom += NewHeight - (paNewRects[iResized].bottom - paNewRects[iResized].top);
253
254 /* Verify all pairs of originally adjacent rectangles for all 4 directions.
255 * If the pair has a "good" delta (that is the first rectangle intersects the second)
256 * at a direction and the second rectangle is not primary one (which can not be moved),
257 * move the second rectangle to make it adjacent to the first one.
258 */
259
260 /* X positive. */
261 unsigned iRect;
262 for (iRect = 0; iRect < nRects; iRect++)
263 {
264 /* Find the next adjacent original rect in x positive direction. */
265 unsigned iNextRect = nextAdjacentRectXP (paRects, nRects, iRect);
266 Log(("next %d -> %d\n", iRect, iNextRect));
267
268 if (iNextRect == ~0 || iNextRect == iPrimary)
269 {
270 continue;
271 }
272
273 /* Check whether there is an X intersection between these adjacent rects in the new rectangles
274 * and fix the intersection if delta is "good".
275 */
276 int delta = paNewRects[iRect].right - paNewRects[iNextRect].left;
277
278 if (delta > 0)
279 {
280 Log(("XP intersection right %d left %d, diff %d\n",
281 paNewRects[iRect].right, paNewRects[iNextRect].left,
282 delta));
283
284 paNewRects[iNextRect].left += delta;
285 paNewRects[iNextRect].right += delta;
286 }
287 }
288
289 /* X negative. */
290 for (iRect = 0; iRect < nRects; iRect++)
291 {
292 /* Find the next adjacent original rect in x negative direction. */
293 unsigned iNextRect = nextAdjacentRectXN (paRects, nRects, iRect);
294 Log(("next %d -> %d\n", iRect, iNextRect));
295
296 if (iNextRect == ~0 || iNextRect == iPrimary)
297 {
298 continue;
299 }
300
301 /* Check whether there is an X intersection between these adjacent rects in the new rectangles
302 * and fix the intersection if delta is "good".
303 */
304 int delta = paNewRects[iRect].left - paNewRects[iNextRect].right;
305
306 if (delta < 0)
307 {
308 Log(("XN intersection left %d right %d, diff %d\n",
309 paNewRects[iRect].left, paNewRects[iNextRect].right,
310 delta));
311
312 paNewRects[iNextRect].left += delta;
313 paNewRects[iNextRect].right += delta;
314 }
315 }
316
317 /* Y positive (in the computer sense, top->down). */
318 for (iRect = 0; iRect < nRects; iRect++)
319 {
320 /* Find the next adjacent original rect in y positive direction. */
321 unsigned iNextRect = nextAdjacentRectYP (paRects, nRects, iRect);
322 Log(("next %d -> %d\n", iRect, iNextRect));
323
324 if (iNextRect == ~0 || iNextRect == iPrimary)
325 {
326 continue;
327 }
328
329 /* Check whether there is an Y intersection between these adjacent rects in the new rectangles
330 * and fix the intersection if delta is "good".
331 */
332 int delta = paNewRects[iRect].bottom - paNewRects[iNextRect].top;
333
334 if (delta > 0)
335 {
336 Log(("YP intersection bottom %d top %d, diff %d\n",
337 paNewRects[iRect].bottom, paNewRects[iNextRect].top,
338 delta));
339
340 paNewRects[iNextRect].top += delta;
341 paNewRects[iNextRect].bottom += delta;
342 }
343 }
344
345 /* Y negative (in the computer sense, down->top). */
346 for (iRect = 0; iRect < nRects; iRect++)
347 {
348 /* Find the next adjacent original rect in x negative direction. */
349 unsigned iNextRect = nextAdjacentRectYN (paRects, nRects, iRect);
350 Log(("next %d -> %d\n", iRect, iNextRect));
351
352 if (iNextRect == ~0 || iNextRect == iPrimary)
353 {
354 continue;
355 }
356
357 /* Check whether there is an Y intersection between these adjacent rects in the new rectangles
358 * and fix the intersection if delta is "good".
359 */
360 int delta = paNewRects[iRect].top - paNewRects[iNextRect].bottom;
361
362 if (delta < 0)
363 {
364 Log(("YN intersection top %d bottom %d, diff %d\n",
365 paNewRects[iRect].top, paNewRects[iNextRect].bottom,
366 delta));
367
368 paNewRects[iNextRect].top += delta;
369 paNewRects[iNextRect].bottom += delta;
370 }
371 }
372
373 memcpy (paRects, paNewRects, sizeof (RECTL) * nRects);
374 return;
375}
376
377/* Returns TRUE to try again. */
378static BOOL ResizeDisplayDevice(ULONG Id, DWORD Width, DWORD Height, DWORD BitsPerPixel)
379{
380 BOOL fModeReset = (Width == 0 && Height == 0 && BitsPerPixel == 0);
381
382 DISPLAY_DEVICE DisplayDevice;
383
384 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
385 DisplayDevice.cb = sizeof(DisplayDevice);
386
387 /* Find out how many display devices the system has */
388 DWORD NumDevices = 0;
389 DWORD i = 0;
390 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
391 {
392 Log(("[%d] %s\n", i, DisplayDevice.DeviceName));
393
394 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
395 {
396 Log(("Found primary device. err %d\n", GetLastError ()));
397 NumDevices++;
398 }
399 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
400 {
401
402 Log(("Found secondary device. err %d\n", GetLastError ()));
403 NumDevices++;
404 }
405
406 ZeroMemory(&DisplayDevice, sizeof(DisplayDevice));
407 DisplayDevice.cb = sizeof(DisplayDevice);
408 i++;
409 }
410
411 Log(("Found total %d devices. err %d\n", NumDevices, GetLastError ()));
412
413 if (NumDevices == 0 || Id >= NumDevices)
414 {
415 Log(("Requested identifier %d is invalid. err %d\n", Id, GetLastError ()));
416 return FALSE;
417 }
418
419 DISPLAY_DEVICE *paDisplayDevices = (DISPLAY_DEVICE *)alloca (sizeof (DISPLAY_DEVICE) * NumDevices);
420 DEVMODE *paDeviceModes = (DEVMODE *)alloca (sizeof (DEVMODE) * NumDevices);
421 RECTL *paRects = (RECTL *)alloca (sizeof (RECTL) * NumDevices);
422
423 /* Fetch information about current devices and modes. */
424 DWORD DevNum = 0;
425 DWORD DevPrimaryNum = 0;
426
427 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
428 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
429
430 i = 0;
431 while (EnumDisplayDevices (NULL, i, &DisplayDevice, 0))
432 {
433 Log(("[%d(%d)] %s\n", i, DevNum, DisplayDevice.DeviceName));
434
435 BOOL bFetchDevice = FALSE;
436
437 if (DisplayDevice.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
438 {
439 Log(("Found primary device. err %d\n", GetLastError ()));
440 DevPrimaryNum = DevNum;
441 bFetchDevice = TRUE;
442 }
443 else if (!(DisplayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER))
444 {
445
446 Log(("Found secondary device. err %d\n", GetLastError ()));
447 bFetchDevice = TRUE;
448 }
449
450 if (bFetchDevice)
451 {
452 if (DevNum >= NumDevices)
453 {
454 Log(("%d >= %d\n", NumDevices, DevNum));
455 return FALSE;
456 }
457
458 paDisplayDevices[DevNum] = DisplayDevice;
459
460 ZeroMemory(&paDeviceModes[DevNum], sizeof(DEVMODE));
461 paDeviceModes[DevNum].dmSize = sizeof(DEVMODE);
462 if (!EnumDisplaySettings((LPSTR)DisplayDevice.DeviceName,
463 ENUM_REGISTRY_SETTINGS, &paDeviceModes[DevNum]))
464 {
465 Log(("EnumDisplaySettings err %d\n", GetLastError ()));
466 return FALSE;
467 }
468
469 Log(("%dx%d at %d,%d\n",
470 paDeviceModes[DevNum].dmPelsWidth,
471 paDeviceModes[DevNum].dmPelsHeight,
472 paDeviceModes[DevNum].dmPosition.x,
473 paDeviceModes[DevNum].dmPosition.y));
474
475 paRects[DevNum].left = paDeviceModes[DevNum].dmPosition.x;
476 paRects[DevNum].top = paDeviceModes[DevNum].dmPosition.y;
477 paRects[DevNum].right = paDeviceModes[DevNum].dmPosition.x + paDeviceModes[DevNum].dmPelsWidth;
478 paRects[DevNum].bottom = paDeviceModes[DevNum].dmPosition.y + paDeviceModes[DevNum].dmPelsHeight;
479 DevNum++;
480 }
481
482 ZeroMemory(&DisplayDevice, sizeof(DISPLAY_DEVICE));
483 DisplayDevice.cb = sizeof(DISPLAY_DEVICE);
484 i++;
485 }
486
487 if (Width == 0)
488 {
489 Width = paRects[Id].right - paRects[Id].left;
490 }
491
492 if (Height == 0)
493 {
494 Height = paRects[Id].bottom - paRects[Id].top;
495 }
496
497 /* Check whether a mode reset or a change is requested. */
498 if ( !fModeReset
499 && paRects[Id].right - paRects[Id].left == Width
500 && paRects[Id].bottom - paRects[Id].top == Height
501 && paDeviceModes[Id].dmBitsPerPel == BitsPerPixel)
502 {
503 Log(("VBoxDisplayThread : already at desired resolution.\n"));
504 return FALSE;
505 }
506
507 resizeRect(paRects, NumDevices, DevPrimaryNum, Id, Width, Height);
508#ifdef Log
509 for (i = 0; i < NumDevices; i++)
510 {
511 Log(("[%d]: %d,%d %dx%d\n",
512 i, paRects[i].left, paRects[i].top,
513 paRects[i].right - paRects[i].left,
514 paRects[i].bottom - paRects[i].top));
515 }
516#endif /* Log */
517
518 /* Without this, Windows will not ask the miniport for its
519 * mode table but uses an internal cache instead.
520 */
521 DEVMODE tempDevMode;
522 ZeroMemory (&tempDevMode, sizeof (tempDevMode));
523 tempDevMode.dmSize = sizeof(DEVMODE);
524 EnumDisplaySettings(NULL, 0xffffff, &tempDevMode);
525
526 /* Assign the new rectangles to displays. */
527 for (i = 0; i < NumDevices; i++)
528 {
529 paDeviceModes[i].dmPosition.x = paRects[i].left;
530 paDeviceModes[i].dmPosition.y = paRects[i].top;
531 paDeviceModes[i].dmPelsWidth = paRects[i].right - paRects[i].left;
532 paDeviceModes[i].dmPelsHeight = paRects[i].bottom - paRects[i].top;
533
534 paDeviceModes[i].dmFields = DM_POSITION | DM_PELSHEIGHT | DM_PELSWIDTH;
535
536 if ( i == Id
537 && BitsPerPixel != 0)
538 {
539 paDeviceModes[i].dmFields |= DM_BITSPERPEL;
540 paDeviceModes[i].dmBitsPerPel = BitsPerPixel;
541 }
542 Log(("calling pfnChangeDisplaySettingsEx %x\n", gpfnChangeDisplaySettingsEx));
543 gpfnChangeDisplaySettingsEx((LPSTR)paDisplayDevices[i].DeviceName,
544 &paDeviceModes[i], NULL, CDS_NORESET | CDS_UPDATEREGISTRY, NULL);
545 Log(("ChangeDisplaySettings position err %d\n", GetLastError ()));
546 }
547
548 /* A second call to ChangeDisplaySettings updates the monitor. */
549 LONG status = ChangeDisplaySettings(NULL, 0);
550 Log(("ChangeDisplaySettings update status %d\n", status));
551 if (status == DISP_CHANGE_SUCCESSFUL || status == DISP_CHANGE_BADMODE)
552 {
553 /* Successfully set new video mode or our driver can not set the requested mode. Stop trying. */
554 return FALSE;
555 }
556
557 /* Retry the request. */
558 return TRUE;
559}
560
561static RTEXITCODE handleSetVideoMode(int argc, char *argv[])
562{
563 if (argc != 3 && argc != 4)
564 {
565 usage(SET_VIDEO_MODE);
566 return RTEXITCODE_FAILURE;
567 }
568
569 DWORD xres = atoi(argv[0]);
570 DWORD yres = atoi(argv[1]);
571 DWORD bpp = atoi(argv[2]);
572 DWORD scr = 0;
573
574 if (argc == 4)
575 {
576 scr = atoi(argv[3]);
577 }
578
579 HMODULE hUser = GetModuleHandle("USER32");
580
581 if (hUser)
582 {
583 *(uintptr_t *)&gpfnChangeDisplaySettingsEx = (uintptr_t)GetProcAddress(hUser, "ChangeDisplaySettingsExA");
584 Log(("VBoxService: pChangeDisplaySettingsEx = %p\n", gpfnChangeDisplaySettingsEx));
585
586 if (gpfnChangeDisplaySettingsEx)
587 {
588 /* The screen index is 0 based in the ResizeDisplayDevice call. */
589 scr = scr > 0? scr - 1: 0;
590
591 /* Horizontal resolution must be a multiple of 8, round down. */
592 xres &= ~0x7;
593
594 RTPrintf("Setting resolution of display %d to %dx%dx%d ...", scr, xres, yres, bpp);
595 ResizeDisplayDevice(scr, xres, yres, bpp);
596 RTPrintf("done.\n");
597 }
598 else
599 VBoxControlError("Error retrieving API for display change!");
600 }
601 else
602 VBoxControlError("Error retrieving handle to user32.dll!");
603
604 return RTEXITCODE_SUCCESS;
605}
606
607HKEY getVideoKey(bool writable)
608{
609 HKEY hkeyDeviceMap = 0;
610 HKEY hkeyVideo = 0;
611 LONG status;
612
613 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "HARDWARE\\DEVICEMAP\\VIDEO", 0, KEY_READ, &hkeyDeviceMap);
614 if ((status != ERROR_SUCCESS) || !hkeyDeviceMap)
615 {
616 VBoxControlError("Error opening video device map registry key!\n");
617 return 0;
618 }
619 char szVideoLocation[256];
620 DWORD dwKeyType;
621 szVideoLocation[0] = 0;
622 DWORD len = sizeof(szVideoLocation);
623 status = RegQueryValueExA(hkeyDeviceMap, "\\Device\\Video0", NULL, &dwKeyType, (LPBYTE)szVideoLocation, &len);
624 /*
625 * This value will start with a weird value: \REGISTRY\Machine
626 * Make sure this is true.
627 */
628 if ( (status == ERROR_SUCCESS)
629 && (dwKeyType == REG_SZ)
630 && (_strnicmp(szVideoLocation, "\\REGISTRY\\Machine", 17) == 0))
631 {
632 /* open that branch */
633 status = RegOpenKeyExA(HKEY_LOCAL_MACHINE, &szVideoLocation[18], 0, KEY_READ | (writable ? KEY_WRITE : 0), &hkeyVideo);
634 }
635 else
636 {
637 VBoxControlError("Error opening registry key '%s'\n", &szVideoLocation[18]);
638 }
639 RegCloseKey(hkeyDeviceMap);
640 return hkeyVideo;
641}
642
643static RTEXITCODE handleGetVideoAcceleration(int argc, char *argv[])
644{
645 ULONG status;
646 HKEY hkeyVideo = getVideoKey(false);
647
648 if (hkeyVideo)
649 {
650 /* query the actual value */
651 DWORD fAcceleration = 1;
652 DWORD len = sizeof(fAcceleration);
653 DWORD dwKeyType;
654 status = RegQueryValueExA(hkeyVideo, "EnableVideoAccel", NULL, &dwKeyType, (LPBYTE)&fAcceleration, &len);
655 if (status != ERROR_SUCCESS)
656 RTPrintf("Video acceleration: default\n");
657 else
658 RTPrintf("Video acceleration: %s\n", fAcceleration ? "on" : "off");
659 RegCloseKey(hkeyVideo);
660 }
661 return RTEXITCODE_SUCCESS;
662}
663
664static RTEXITCODE handleSetVideoAcceleration(int argc, char *argv[])
665{
666 ULONG status;
667 HKEY hkeyVideo;
668
669 /* must have exactly one argument: the new offset */
670 if ( (argc != 1)
671 || ( RTStrICmp(argv[0], "on")
672 && RTStrICmp(argv[0], "off")))
673 {
674 usage(SET_VIDEO_ACCEL);
675 return RTEXITCODE_FAILURE;
676 }
677
678 hkeyVideo = getVideoKey(true);
679
680 if (hkeyVideo)
681 {
682 int fAccel = 0;
683 if (RTStrICmp(argv[0], "on") == 0)
684 fAccel = 1;
685 /* set a new value */
686 status = RegSetValueExA(hkeyVideo, "EnableVideoAccel", 0, REG_DWORD, (LPBYTE)&fAccel, sizeof(fAccel));
687 if (status != ERROR_SUCCESS)
688 {
689 VBoxControlError("Error %d writing video acceleration status!\n", status);
690 }
691 RegCloseKey(hkeyVideo);
692 }
693 return RTEXITCODE_SUCCESS;
694}
695
696#define MAX_CUSTOM_MODES 128
697
698/* the table of custom modes */
699struct
700{
701 DWORD xres;
702 DWORD yres;
703 DWORD bpp;
704} customModes[MAX_CUSTOM_MODES] = {0};
705
706void getCustomModes(HKEY hkeyVideo)
707{
708 ULONG status;
709 int curMode = 0;
710
711 /* null out the table */
712 RT_ZERO(customModes);
713
714 do
715 {
716 char valueName[20];
717 DWORD xres, yres, bpp = 0;
718 DWORD dwType;
719 DWORD dwLen = sizeof(DWORD);
720
721 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dWidth", curMode);
722 status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&xres, &dwLen);
723 if (status != ERROR_SUCCESS)
724 break;
725 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dHeight", curMode);
726 status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&yres, &dwLen);
727 if (status != ERROR_SUCCESS)
728 break;
729 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dBPP", curMode);
730 status = RegQueryValueExA(hkeyVideo, valueName, NULL, &dwType, (LPBYTE)&bpp, &dwLen);
731 if (status != ERROR_SUCCESS)
732 break;
733
734 /* check if the mode is OK */
735 if ( (xres > (1 << 16))
736 && (yres > (1 << 16))
737 && ( (bpp != 16)
738 || (bpp != 24)
739 || (bpp != 32)))
740 break;
741
742 /* add mode to table */
743 customModes[curMode].xres = xres;
744 customModes[curMode].yres = yres;
745 customModes[curMode].bpp = bpp;
746
747 ++curMode;
748
749 if (curMode >= MAX_CUSTOM_MODES)
750 break;
751 } while(1);
752}
753
754void writeCustomModes(HKEY hkeyVideo)
755{
756 ULONG status;
757 int tableIndex = 0;
758 int modeIndex = 0;
759
760 /* first remove all values */
761 for (int i = 0; i < MAX_CUSTOM_MODES; i++)
762 {
763 char valueName[20];
764 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dWidth", i);
765 RegDeleteValueA(hkeyVideo, valueName);
766 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dHeight", i);
767 RegDeleteValueA(hkeyVideo, valueName);
768 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dBPP", i);
769 RegDeleteValueA(hkeyVideo, valueName);
770 }
771
772 do
773 {
774 if (tableIndex >= MAX_CUSTOM_MODES)
775 break;
776
777 /* is the table entry present? */
778 if ( (!customModes[tableIndex].xres)
779 || (!customModes[tableIndex].yres)
780 || (!customModes[tableIndex].bpp))
781 {
782 tableIndex++;
783 continue;
784 }
785
786 RTPrintf("writing mode %d (%dx%dx%d)\n", modeIndex, customModes[tableIndex].xres, customModes[tableIndex].yres, customModes[tableIndex].bpp);
787 char valueName[20];
788 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dWidth", modeIndex);
789 status = RegSetValueExA(hkeyVideo, valueName, 0, REG_DWORD, (LPBYTE)&customModes[tableIndex].xres,
790 sizeof(customModes[tableIndex].xres));
791 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dHeight", modeIndex);
792 RegSetValueExA(hkeyVideo, valueName, 0, REG_DWORD, (LPBYTE)&customModes[tableIndex].yres,
793 sizeof(customModes[tableIndex].yres));
794 RTStrPrintf(valueName, sizeof(valueName), "CustomMode%dBPP", modeIndex);
795 RegSetValueExA(hkeyVideo, valueName, 0, REG_DWORD, (LPBYTE)&customModes[tableIndex].bpp,
796 sizeof(customModes[tableIndex].bpp));
797
798 modeIndex++;
799 tableIndex++;
800
801 } while(1);
802
803}
804
805static RTEXITCODE handleListCustomModes(int argc, char *argv[])
806{
807 if (argc != 0)
808 {
809 usage(LIST_CUST_MODES);
810 return RTEXITCODE_FAILURE;
811 }
812
813 HKEY hkeyVideo = getVideoKey(false);
814
815 if (hkeyVideo)
816 {
817 getCustomModes(hkeyVideo);
818 for (int i = 0; i < (sizeof(customModes) / sizeof(customModes[0])); i++)
819 {
820 if ( !customModes[i].xres
821 || !customModes[i].yres
822 || !customModes[i].bpp)
823 continue;
824
825 RTPrintf("Mode: %d x %d x %d\n",
826 customModes[i].xres, customModes[i].yres, customModes[i].bpp);
827 }
828 RegCloseKey(hkeyVideo);
829 }
830 return RTEXITCODE_SUCCESS;
831}
832
833static RTEXITCODE handleAddCustomMode(int argc, char *argv[])
834{
835 if (argc != 3)
836 {
837 usage(ADD_CUST_MODE);
838 return RTEXITCODE_FAILURE;
839 }
840
841 DWORD xres = atoi(argv[0]);
842 DWORD yres = atoi(argv[1]);
843 DWORD bpp = atoi(argv[2]);
844
845 /** @todo better check including xres mod 8 = 0! */
846 if ( (xres > (1 << 16))
847 && (yres > (1 << 16))
848 && ( (bpp != 16)
849 || (bpp != 24)
850 || (bpp != 32)))
851 {
852 VBoxControlError("invalid mode specified!\n");
853 return RTEXITCODE_FAILURE;
854 }
855
856 HKEY hkeyVideo = getVideoKey(true);
857
858 if (hkeyVideo)
859 {
860 int i;
861 int fModeExists = 0;
862 getCustomModes(hkeyVideo);
863 for (i = 0; i < MAX_CUSTOM_MODES; i++)
864 {
865 /* mode exists? */
866 if ( customModes[i].xres == xres
867 && customModes[i].yres == yres
868 && customModes[i].bpp == bpp
869 )
870 {
871 fModeExists = 1;
872 }
873 }
874 if (!fModeExists)
875 {
876 for (i = 0; i < MAX_CUSTOM_MODES; i++)
877 {
878 /* item free? */
879 if (!customModes[i].xres)
880 {
881 customModes[i].xres = xres;
882 customModes[i].yres = yres;
883 customModes[i].bpp = bpp;
884 break;
885 }
886 }
887 writeCustomModes(hkeyVideo);
888 }
889 RegCloseKey(hkeyVideo);
890 }
891 return RTEXITCODE_SUCCESS;
892}
893
894static RTEXITCODE handleRemoveCustomMode(int argc, char *argv[])
895{
896 if (argc != 3)
897 {
898 usage(REMOVE_CUST_MODE);
899 return RTEXITCODE_FAILURE;
900 }
901
902 DWORD xres = atoi(argv[0]);
903 DWORD yres = atoi(argv[1]);
904 DWORD bpp = atoi(argv[2]);
905
906 HKEY hkeyVideo = getVideoKey(true);
907
908 if (hkeyVideo)
909 {
910 getCustomModes(hkeyVideo);
911 for (int i = 0; i < MAX_CUSTOM_MODES; i++)
912 {
913 /* correct item? */
914 if ( (customModes[i].xres == xres)
915 && (customModes[i].yres == yres)
916 && (customModes[i].bpp == bpp))
917 {
918 RTPrintf("found mode at index %d\n", i);
919 RT_ZERO(customModes[i]);
920 break;
921 }
922 }
923 writeCustomModes(hkeyVideo);
924 RegCloseKey(hkeyVideo);
925 }
926
927 return RTEXITCODE_SUCCESS;
928}
929
930#endif /* RT_OS_WINDOWS */
931
932#ifdef VBOX_WITH_GUEST_PROPS
933/**
934 * Retrieves a value from the guest property store.
935 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
936 *
937 * @returns Command exit code.
938 * @note see the command line API description for parameters
939 */
940static RTEXITCODE getGuestProperty(int argc, char **argv)
941{
942 using namespace guestProp;
943
944 bool fVerbose = false;
945 if ( 2 == argc
946 && ( strcmp(argv[1], "-verbose") == 0
947 || strcmp(argv[1], "--verbose") == 0)
948 )
949 fVerbose = true;
950 else if (argc != 1)
951 {
952 usage(GUEST_PROP);
953 return RTEXITCODE_FAILURE;
954 }
955
956 uint32_t u32ClientId = 0;
957 int rc = VINF_SUCCESS;
958
959 rc = VbglR3GuestPropConnect(&u32ClientId);
960 if (!RT_SUCCESS(rc))
961 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
962
963 /*
964 * Here we actually retrieve the value from the host.
965 */
966 const char *pszName = argv[0];
967 char *pszValue = NULL;
968 uint64_t u64Timestamp = 0;
969 char *pszFlags = NULL;
970 /* The buffer for storing the data and its initial size. We leave a bit
971 * of space here in case the maximum values are raised. */
972 void *pvBuf = NULL;
973 uint32_t cbBuf = MAX_VALUE_LEN + MAX_FLAGS_LEN + 1024;
974 if (RT_SUCCESS(rc))
975 {
976 /* Because there is a race condition between our reading the size of a
977 * property and the guest updating it, we loop a few times here and
978 * hope. Actually this should never go wrong, as we are generous
979 * enough with buffer space. */
980 bool finish = false;
981 for (unsigned i = 0; (i < 10) && !finish; ++i)
982 {
983 void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
984 if (NULL == pvTmpBuf)
985 {
986 rc = VERR_NO_MEMORY;
987 VBoxControlError("Out of memory\n");
988 }
989 else
990 {
991 pvBuf = pvTmpBuf;
992 rc = VbglR3GuestPropRead(u32ClientId, pszName, pvBuf, cbBuf,
993 &pszValue, &u64Timestamp, &pszFlags,
994 &cbBuf);
995 }
996 if (VERR_BUFFER_OVERFLOW == rc)
997 /* Leave a bit of extra space to be safe */
998 cbBuf += 1024;
999 else
1000 finish = true;
1001 }
1002 if (VERR_TOO_MUCH_DATA == rc)
1003 VBoxControlError("Temporarily unable to retrieve the property\n");
1004 else if (!RT_SUCCESS(rc) && (rc != VERR_NOT_FOUND))
1005 VBoxControlError("Failed to retrieve the property value, error %Rrc\n", rc);
1006 }
1007
1008 /*
1009 * And display it on the guest console.
1010 */
1011 if (VERR_NOT_FOUND == rc)
1012 RTPrintf("No value set!\n");
1013 else if (RT_SUCCESS(rc))
1014 {
1015 RTPrintf("Value: %s\n", pszValue);
1016 if (fVerbose)
1017 {
1018 RTPrintf("Timestamp: %lld ns\n", u64Timestamp);
1019 RTPrintf("Flags: %s\n", pszFlags);
1020 }
1021 }
1022
1023 if (u32ClientId != 0)
1024 VbglR3GuestPropDisconnect(u32ClientId);
1025 RTMemFree(pvBuf);
1026 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1027}
1028
1029
1030/**
1031 * Writes a value to the guest property store.
1032 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
1033 *
1034 * @returns Command exit code.
1035 * @note see the command line API description for parameters
1036 */
1037static RTEXITCODE setGuestProperty(int argc, char *argv[])
1038{
1039 /*
1040 * Check the syntax. We can deduce the correct syntax from the number of
1041 * arguments.
1042 */
1043 bool usageOK = true;
1044 const char *pszName = NULL;
1045 const char *pszValue = NULL;
1046 const char *pszFlags = NULL;
1047 if (2 == argc)
1048 {
1049 pszValue = argv[1];
1050 }
1051 else if (3 == argc)
1052 usageOK = false;
1053 else if (4 == argc)
1054 {
1055 pszValue = argv[1];
1056 if ( strcmp(argv[2], "-flags") != 0
1057 && strcmp(argv[2], "--flags") != 0)
1058 usageOK = false;
1059 pszFlags = argv[3];
1060 }
1061 else if (argc != 1)
1062 usageOK = false;
1063 if (!usageOK)
1064 {
1065 usage(GUEST_PROP);
1066 return RTEXITCODE_FAILURE;
1067 }
1068 /* This is always needed. */
1069 pszName = argv[0];
1070
1071 /*
1072 * Do the actual setting.
1073 */
1074 uint32_t u32ClientId = 0;
1075 int rc = VINF_SUCCESS;
1076 rc = VbglR3GuestPropConnect(&u32ClientId);
1077 if (!RT_SUCCESS(rc))
1078 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
1079 if (RT_SUCCESS(rc))
1080 {
1081 if (pszFlags != NULL)
1082 rc = VbglR3GuestPropWrite(u32ClientId, pszName, pszValue, pszFlags);
1083 else
1084 rc = VbglR3GuestPropWriteValue(u32ClientId, pszName, pszValue);
1085 if (!RT_SUCCESS(rc))
1086 VBoxControlError("Failed to store the property value, error %Rrc\n", rc);
1087 }
1088
1089 if (u32ClientId != 0)
1090 VbglR3GuestPropDisconnect(u32ClientId);
1091 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1092}
1093
1094
1095/**
1096 * Deletes a guest property from the guest property store.
1097 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
1098 *
1099 * @returns Command exit code.
1100 * @note see the command line API description for parameters
1101 */
1102static RTEXITCODE deleteGuestProperty(int argc, char *argv[])
1103{
1104 /*
1105 * Check the syntax. We can deduce the correct syntax from the number of
1106 * arguments.
1107 */
1108 bool usageOK = true;
1109 const char *pszName = NULL;
1110 if (argc < 1)
1111 usageOK = false;
1112 if (!usageOK)
1113 {
1114 usage(GUEST_PROP);
1115 return RTEXITCODE_FAILURE;
1116 }
1117 /* This is always needed. */
1118 pszName = argv[0];
1119
1120 /*
1121 * Do the actual setting.
1122 */
1123 uint32_t u32ClientId = 0;
1124 int rc = VbglR3GuestPropConnect(&u32ClientId);
1125 if (!RT_SUCCESS(rc))
1126 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
1127 if (RT_SUCCESS(rc))
1128 {
1129 rc = VbglR3GuestPropDelete(u32ClientId, pszName);
1130 if (!RT_SUCCESS(rc))
1131 VBoxControlError("Failed to delete the property value, error %Rrc\n", rc);
1132 }
1133
1134 if (u32ClientId != 0)
1135 VbglR3GuestPropDisconnect(u32ClientId);
1136 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1137}
1138
1139
1140/**
1141 * Enumerates the properties in the guest property store.
1142 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
1143 *
1144 * @returns Command exit code.
1145 * @note see the command line API description for parameters
1146 */
1147static RTEXITCODE enumGuestProperty(int argc, char *argv[])
1148{
1149 /*
1150 * Check the syntax. We can deduce the correct syntax from the number of
1151 * arguments.
1152 */
1153 char const * const *papszPatterns = NULL;
1154 uint32_t cPatterns = 0;
1155 if ( argc > 1
1156 && ( strcmp(argv[0], "-patterns") == 0
1157 || strcmp(argv[0], "--patterns") == 0))
1158 {
1159 papszPatterns = (char const * const *)&argv[1];
1160 cPatterns = argc - 1;
1161 }
1162 else if (argc != 0)
1163 {
1164 usage(GUEST_PROP);
1165 return RTEXITCODE_FAILURE;
1166 }
1167
1168 /*
1169 * Do the actual enumeration.
1170 */
1171 uint32_t u32ClientId = 0;
1172 int rc = VbglR3GuestPropConnect(&u32ClientId);
1173 if (RT_SUCCESS(rc))
1174 {
1175 PVBGLR3GUESTPROPENUM pHandle;
1176 const char *pszName, *pszValue, *pszFlags;
1177 uint64_t u64Timestamp;
1178
1179 rc = VbglR3GuestPropEnum(u32ClientId, papszPatterns, cPatterns, &pHandle,
1180 &pszName, &pszValue, &u64Timestamp, &pszFlags);
1181 if (RT_SUCCESS(rc))
1182 {
1183 while (RT_SUCCESS(rc) && pszName)
1184 {
1185 RTPrintf("Name: %s, value: %s, timestamp: %lld, flags: %s\n",
1186 pszName, pszValue, u64Timestamp, pszFlags);
1187
1188 rc = VbglR3GuestPropEnumNext(pHandle, &pszName, &pszValue, &u64Timestamp, &pszFlags);
1189 if (RT_FAILURE(rc))
1190 VBoxControlError("Error while enumerating guest properties: %Rrc\n", rc);
1191 }
1192
1193 VbglR3GuestPropEnumFree(pHandle);
1194 }
1195 else if (VERR_NOT_FOUND == rc)
1196 RTPrintf("No properties found.\n");
1197 else
1198 VBoxControlError("Failed to enumerate the guest properties! Error: %Rrc\n", rc);
1199 VbglR3GuestPropDisconnect(u32ClientId);
1200 }
1201 else
1202 VBoxControlError("Failed to connect to the guest property service! Error: %Rrc\n", rc);
1203 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1204}
1205
1206
1207/**
1208 * Waits for notifications of changes to guest properties.
1209 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
1210 *
1211 * @returns Command exit code.
1212 * @note see the command line API description for parameters
1213 */
1214static RTEXITCODE waitGuestProperty(int argc, char **argv)
1215{
1216 using namespace guestProp;
1217
1218 /*
1219 * Handle arguments
1220 */
1221 const char *pszPatterns = NULL;
1222 uint64_t u64TimestampIn = 0;
1223 uint32_t u32Timeout = RT_INDEFINITE_WAIT;
1224 bool usageOK = true;
1225 if (argc < 1)
1226 usageOK = false;
1227 pszPatterns = argv[0];
1228 for (int i = 1; usageOK && i < argc; ++i)
1229 {
1230 if ( strcmp(argv[i], "-timeout") == 0
1231 || strcmp(argv[i], "--timeout") == 0)
1232 {
1233 if ( i + 1 >= argc
1234 || RTStrToUInt32Full(argv[i + 1], 10, &u32Timeout)
1235 != VINF_SUCCESS
1236 )
1237 usageOK = false;
1238 else
1239 ++i;
1240 }
1241 else if ( strcmp(argv[i], "-timestamp") == 0
1242 || strcmp(argv[i], "--timestamp") == 0)
1243 {
1244 if ( i + 1 >= argc
1245 || RTStrToUInt64Full(argv[i + 1], 10, &u64TimestampIn)
1246 != VINF_SUCCESS
1247 )
1248 usageOK = false;
1249 else
1250 ++i;
1251 }
1252 else
1253 usageOK = false;
1254 }
1255 if (!usageOK)
1256 {
1257 usage(GUEST_PROP);
1258 return RTEXITCODE_FAILURE;
1259 }
1260
1261 /*
1262 * Connect to the service
1263 */
1264 uint32_t u32ClientId = 0;
1265 int rc = VINF_SUCCESS;
1266
1267 rc = VbglR3GuestPropConnect(&u32ClientId);
1268 if (!RT_SUCCESS(rc))
1269 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
1270
1271 /*
1272 * Retrieve the notification from the host
1273 */
1274 char *pszName = NULL;
1275 char *pszValue = NULL;
1276 uint64_t u64TimestampOut = 0;
1277 char *pszFlags = NULL;
1278 /* The buffer for storing the data and its initial size. We leave a bit
1279 * of space here in case the maximum values are raised. */
1280 void *pvBuf = NULL;
1281 uint32_t cbBuf = MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 1024;
1282 /* Because there is a race condition between our reading the size of a
1283 * property and the guest updating it, we loop a few times here and
1284 * hope. Actually this should never go wrong, as we are generous
1285 * enough with buffer space. */
1286 bool finish = false;
1287 for (unsigned i = 0;
1288 (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) && !finish && (i < 10);
1289 ++i)
1290 {
1291 void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
1292 if (NULL == pvTmpBuf)
1293 {
1294 rc = VERR_NO_MEMORY;
1295 VBoxControlError("Out of memory\n");
1296 }
1297 else
1298 {
1299 pvBuf = pvTmpBuf;
1300 rc = VbglR3GuestPropWait(u32ClientId, pszPatterns, pvBuf, cbBuf,
1301 u64TimestampIn, u32Timeout,
1302 &pszName, &pszValue, &u64TimestampOut,
1303 &pszFlags, &cbBuf);
1304 }
1305 if (VERR_BUFFER_OVERFLOW == rc)
1306 /* Leave a bit of extra space to be safe */
1307 cbBuf += 1024;
1308 else
1309 finish = true;
1310 if (rc == VERR_TOO_MUCH_DATA)
1311 VBoxControlError("Temporarily unable to get a notification\n");
1312 else if (rc == VERR_INTERRUPTED)
1313 VBoxControlError("The request timed out or was interrupted\n");
1314#ifndef RT_OS_WINDOWS /* Windows guests do not do this right */
1315 else if (!RT_SUCCESS(rc) && (rc != VERR_NOT_FOUND))
1316 VBoxControlError("Failed to get a notification, error %Rrc\n", rc);
1317#endif
1318 }
1319
1320 /*
1321 * And display it on the guest console.
1322 */
1323 if (VERR_NOT_FOUND == rc)
1324 RTPrintf("No value set!\n");
1325 else if (rc == VERR_BUFFER_OVERFLOW)
1326 RTPrintf("Internal error: unable to determine the size of the data!\n");
1327 else if (RT_SUCCESS(rc))
1328 {
1329 RTPrintf("Name: %s\n", pszName);
1330 RTPrintf("Value: %s\n", pszValue);
1331 RTPrintf("Timestamp: %lld ns\n", u64TimestampOut);
1332 RTPrintf("Flags: %s\n", pszFlags);
1333 }
1334
1335 if (u32ClientId != 0)
1336 VbglR3GuestPropDisconnect(u32ClientId);
1337 RTMemFree(pvBuf);
1338 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1339}
1340
1341
1342/**
1343 * Access the guest property store through the "VBoxGuestPropSvc" HGCM
1344 * service.
1345 *
1346 * @returns 0 on success, 1 on failure
1347 * @note see the command line API description for parameters
1348 */
1349static RTEXITCODE handleGuestProperty(int argc, char *argv[])
1350{
1351 if (0 == argc)
1352 {
1353 usage(GUEST_PROP);
1354 return RTEXITCODE_FAILURE;
1355 }
1356 if (!strcmp(argv[0], "get"))
1357 return getGuestProperty(argc - 1, argv + 1);
1358 else if (!strcmp(argv[0], "set"))
1359 return setGuestProperty(argc - 1, argv + 1);
1360 else if (!strcmp(argv[0], "delete") || !strcmp(argv[0], "unset"))
1361 return deleteGuestProperty(argc - 1, argv + 1);
1362 else if (!strcmp(argv[0], "enumerate"))
1363 return enumGuestProperty(argc - 1, argv + 1);
1364 else if (!strcmp(argv[0], "wait"))
1365 return waitGuestProperty(argc - 1, argv + 1);
1366 /* else */
1367 usage(GUEST_PROP);
1368 return RTEXITCODE_FAILURE;
1369}
1370#endif
1371
1372#ifdef VBOX_WITH_SHARED_FOLDERS
1373/**
1374 * Lists the Shared Folders provided by the host.
1375 */
1376static RTEXITCODE listSharedFolders(int argc, char **argv)
1377{
1378 bool usageOK = true;
1379 bool fOnlyShowAutoMount = false;
1380 if (argc == 1)
1381 {
1382 if ( !strcmp(argv[0], "-automount")
1383 || !strcmp(argv[0], "--automount"))
1384 fOnlyShowAutoMount = true;
1385 else
1386 usageOK = false;
1387 }
1388 else if (argc > 1)
1389 usageOK = false;
1390
1391 if (!usageOK)
1392 {
1393 usage(GUEST_SHAREDFOLDERS);
1394 return RTEXITCODE_FAILURE;
1395 }
1396
1397 uint32_t u32ClientId;
1398 int rc = VbglR3SharedFolderConnect(&u32ClientId);
1399 if (!RT_SUCCESS(rc))
1400 VBoxControlError("Failed to connect to the shared folder service, error %Rrc\n", rc);
1401 else
1402 {
1403 PVBGLR3SHAREDFOLDERMAPPING paMappings;
1404 uint32_t cMappings;
1405 rc = VbglR3SharedFolderGetMappings(u32ClientId, fOnlyShowAutoMount,
1406 &paMappings, &cMappings);
1407 if (RT_SUCCESS(rc))
1408 {
1409 if (fOnlyShowAutoMount)
1410 RTPrintf("Auto-mounted Shared Folder mappings (%u):\n\n", cMappings);
1411 else
1412 RTPrintf("Shared Folder mappings (%u):\n\n", cMappings);
1413
1414 for (uint32_t i = 0; i < cMappings; i++)
1415 {
1416 char *pszName;
1417 rc = VbglR3SharedFolderGetName(u32ClientId, paMappings[i].u32Root, &pszName);
1418 if (RT_SUCCESS(rc))
1419 {
1420 RTPrintf("%02u - %s\n", i + 1, pszName);
1421 RTStrFree(pszName);
1422 }
1423 else
1424 VBoxControlError("Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
1425 paMappings[i].u32Root, rc);
1426 }
1427 if (!cMappings)
1428 RTPrintf("No Shared Folders available.\n");
1429 VbglR3SharedFolderFreeMappings(paMappings);
1430 }
1431 else
1432 VBoxControlError("Error while getting the shared folder mappings, rc = %Rrc\n", rc);
1433 VbglR3SharedFolderDisconnect(u32ClientId);
1434 }
1435 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1436}
1437
1438/**
1439 * Handles Shared Folders control.
1440 *
1441 * @returns 0 on success, 1 on failure
1442 * @note see the command line API description for parameters
1443 * (r=bird: yeah, right. The API description contains nil about params)
1444 */
1445static RTEXITCODE handleSharedFolder(int argc, char *argv[])
1446{
1447 if (0 == argc)
1448 {
1449 usage(GUEST_SHAREDFOLDERS);
1450 return RTEXITCODE_FAILURE;
1451 }
1452 if (!strcmp(argv[0], "list"))
1453 return listSharedFolders(argc - 1, argv + 1);
1454 /* else */
1455 usage(GUEST_SHAREDFOLDERS);
1456 return RTEXITCODE_FAILURE;
1457}
1458#endif
1459
1460#if !defined(VBOX_CONTROL_TEST)
1461/**
1462 * @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: writecoredump}
1463 */
1464static RTEXITCODE handleWriteCoreDump(int argc, char *argv[])
1465{
1466 int rc = VbglR3WriteCoreDump();
1467 if (RT_SUCCESS(rc))
1468 {
1469 RTPrintf("Guest core dump successful.\n");
1470 return RTEXITCODE_SUCCESS;
1471 }
1472 else
1473 {
1474 VBoxControlError("Error while taking guest core dump. rc=%Rrc\n", rc);
1475 return RTEXITCODE_FAILURE;
1476 }
1477}
1478#endif
1479
1480/**
1481 * @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: takesnapshot}
1482 */
1483static RTEXITCODE handleTakeSnapshot(int argc, char *argv[])
1484{
1485 //VbglR3VmTakeSnapshot(argv[0], argv[1]);
1486 return VBoxControlError("not implemented");
1487}
1488
1489/**
1490 * @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: savestate}
1491 */
1492static RTEXITCODE handleSaveState(int argc, char *argv[])
1493{
1494 //VbglR3VmSaveState();
1495 return VBoxControlError("not implemented");
1496}
1497
1498/**
1499 * @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: suspend|pause}
1500 */
1501static RTEXITCODE handleSuspend(int argc, char *argv[])
1502{
1503 //VbglR3VmSuspend();
1504 return VBoxControlError("not implemented");
1505}
1506
1507/**
1508 * @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: poweroff|powerdown}
1509 */
1510static RTEXITCODE handlePowerOff(int argc, char *argv[])
1511{
1512 //VbglR3VmPowerOff();
1513 return VBoxControlError("not implemented");
1514}
1515
1516/**
1517 * @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: version}
1518 */
1519static RTEXITCODE handleVersion(int argc, char *argv[])
1520{
1521 if (argc)
1522 return VBoxControlSyntaxError("getversion does not take any arguments");
1523 RTPrintf("%sr%u\n", VBOX_VERSION_STRING, RTBldCfgRevision());
1524 return RTEXITCODE_SUCCESS;
1525}
1526
1527/**
1528 * @callback_method_impl{FNVBOXCTRLCMDHANDLER, Command: help}
1529 */
1530static RTEXITCODE handleHelp(int argc, char *argv[])
1531{
1532 /* ignore arguments for now. */
1533 usage();
1534 return RTEXITCODE_SUCCESS;
1535}
1536
1537#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
1538#include "..\VBoxGuestLib\VBGLR3Internal.h"
1539
1540static RTEXITCODE handleDpc(int argc, char *argv[])
1541{
1542#ifndef VBOX_CONTROL_TEST
1543 int rc = VINF_SUCCESS;
1544 int i;
1545 for (i = 0; i < 30; i++)
1546 {
1547 rc = vbglR3DoIOCtl(VBOXGUEST_IOCTL_DPC, NULL, 0);
1548 if (RT_FAILURE(rc))
1549 {
1550 break;
1551 }
1552 RTPrintf("%d\n", i);
1553 }
1554#else
1555 int rc = VERR_NOT_IMPLEMENTED;
1556#endif
1557 if (RT_SUCCESS(rc))
1558 {
1559 RTPrintf("Samples collection completed.\n");
1560 return RTEXITCODE_SUCCESS;
1561 }
1562 else
1563 {
1564 VBoxControlError("Error. rc=%Rrc\n", rc);
1565 return RTEXITCODE_FAILURE;
1566 }
1567}
1568#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
1569
1570/** command handler type */
1571typedef DECLCALLBACK(RTEXITCODE) FNVBOXCTRLCMDHANDLER(int argc, char *argv[]);
1572typedef FNVBOXCTRLCMDHANDLER *PFNVBOXCTRLCMDHANDLER;
1573
1574/** The table of all registered command handlers. */
1575struct COMMANDHANDLER
1576{
1577 const char *pszCommand;
1578 PFNVBOXCTRLCMDHANDLER pfnHandler;
1579} g_aCommandHandlers[] =
1580{
1581#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
1582 { "getvideoacceleration", handleGetVideoAcceleration },
1583 { "setvideoacceleration", handleSetVideoAcceleration },
1584 { "listcustommodes", handleListCustomModes },
1585 { "addcustommode", handleAddCustomMode },
1586 { "removecustommode", handleRemoveCustomMode },
1587 { "setvideomode", handleSetVideoMode },
1588#endif
1589#ifdef VBOX_WITH_GUEST_PROPS
1590 { "guestproperty", handleGuestProperty },
1591#endif
1592#ifdef VBOX_WITH_SHARED_FOLDERS
1593 { "sharedfolder", handleSharedFolder },
1594#endif
1595#if !defined(VBOX_CONTROL_TEST)
1596 { "writecoredump", handleWriteCoreDump },
1597#endif
1598 { "takesnapshot", handleTakeSnapshot },
1599 { "savestate", handleSaveState },
1600 { "suspend", handleSuspend },
1601 { "pause", handleSuspend },
1602 { "poweroff", handlePowerOff },
1603 { "powerdown", handlePowerOff },
1604 { "getversion", handleVersion },
1605 { "version", handleVersion },
1606#ifdef VBOX_WITH_DPC_LATENCY_CHECKER
1607 { "dpc", handleDpc },
1608#endif /* VBOX_WITH_DPC_LATENCY_CHECKER */
1609 { "help", handleHelp }
1610};
1611
1612/** Main function */
1613int main(int argc, char **argv)
1614{
1615 /** The application's global return code */
1616 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
1617 /** An IPRT return code for local use */
1618 int rrc = VINF_SUCCESS;
1619 /** The index of the command line argument we are currently processing */
1620 int iArg = 1;
1621 /** Should we show the logo text? */
1622 bool fShowLogo = true;
1623 /** Should we print the usage after the logo? For the -help switch. */
1624 bool fDoHelp = false;
1625 /** Will we be executing a command or just printing information? */
1626 bool fOnlyInfo = false;
1627
1628 rrc = RTR3InitExe(argc, &argv, 0);
1629 if (RT_FAILURE(rrc))
1630 return RTMsgInitFailure(rrc);
1631
1632 /*
1633 * Start by handling command line switches
1634 */
1635 /** @todo RTGetOpt conversion of the whole file. */
1636 bool done = false; /**< Are we finished with handling switches? */
1637 while (!done && (iArg < argc))
1638 {
1639 if ( !strcmp(argv[iArg], "-V")
1640 || !strcmp(argv[iArg], "-v")
1641 || !strcmp(argv[iArg], "--version")
1642 || !strcmp(argv[iArg], "-version")
1643 )
1644 {
1645 /* Print version number, and do nothing else. */
1646 RTPrintf("%sr%u\n", VBOX_VERSION_STRING, RTBldCfgRevision());
1647 fOnlyInfo = true;
1648 fShowLogo = false;
1649 done = true;
1650 }
1651 else if ( !strcmp(argv[iArg], "-nologo")
1652 || !strcmp(argv[iArg], "--nologo"))
1653 fShowLogo = false;
1654 else if ( !strcmp(argv[iArg], "-help")
1655 || !strcmp(argv[iArg], "--help"))
1656 {
1657 fOnlyInfo = true;
1658 fDoHelp = true;
1659 done = true;
1660 }
1661 else
1662 /* We have found an argument which isn't a switch. Exit to the
1663 * command processing bit. */
1664 done = true;
1665 if (!done)
1666 ++iArg;
1667 }
1668
1669 /*
1670 * Find the application name, show our logo if the user hasn't suppressed it,
1671 * and show the usage if the user asked us to
1672 */
1673 g_pszProgName = RTPathFilename(argv[0]);
1674 if (fShowLogo)
1675 RTPrintf(VBOX_PRODUCT " Guest Additions Command Line Management Interface Version "
1676 VBOX_VERSION_STRING "\n"
1677 "(C) 2008-" VBOX_C_YEAR " " VBOX_VENDOR "\n"
1678 "All rights reserved.\n\n");
1679 if (fDoHelp)
1680 usage();
1681
1682 /*
1683 * Do global initialisation for the programme if we will be handling a command
1684 */
1685 if (!fOnlyInfo)
1686 {
1687 rrc = VbglR3Init();
1688 if (RT_FAILURE(rrc))
1689 {
1690 VBoxControlError("Could not contact the host system. Make sure that you are running this\n"
1691 "application inside a VirtualBox guest system, and that you have sufficient\n"
1692 "user permissions.\n");
1693 rcExit = RTEXITCODE_FAILURE;
1694 }
1695 }
1696
1697 /*
1698 * Now look for an actual command in the argument list and handle it.
1699 */
1700
1701 if (!fOnlyInfo && rcExit == RTEXITCODE_SUCCESS)
1702 {
1703 if (argc > iArg)
1704 {
1705 /*
1706 * Try locate the command and execute it, complain if not found.
1707 */
1708 unsigned i;
1709 for (i = 0; i < RT_ELEMENTS(g_aCommandHandlers); i++)
1710 if (!strcmp(argv[iArg], g_aCommandHandlers[i].pszCommand))
1711 {
1712 rcExit = g_aCommandHandlers[i].pfnHandler(argc - iArg - 1, argv + iArg + 1);
1713 break;
1714 }
1715 if (i >= RT_ELEMENTS(g_aCommandHandlers))
1716 {
1717 rcExit = RTEXITCODE_FAILURE;
1718 usage();
1719 }
1720 }
1721 else
1722 {
1723 /* The user didn't specify a command. */
1724 rcExit = RTEXITCODE_FAILURE;
1725 usage();
1726 }
1727 }
1728
1729 /*
1730 * And exit, returning the status
1731 */
1732 return rcExit;
1733}
1734
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette