VirtualBox

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

Last change on this file since 32198 was 32198, checked in by vboxsync, 15 years ago

VBoxControl: Backed out the parts of r65276 that concerned strcmp->RTStrICmp, only on/off should be handled case insensitively. This is for VBoxManage and RTGetOpt compatibility.

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