VirtualBox

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

Last change on this file since 32201 was 32201, checked in by vboxsync, 14 years ago

VBoxControl: More cleanup.

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

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