VirtualBox

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

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

gcc rulez

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 46.9 KB
Line 
1/* $Id: VBoxControl.cpp 32026 2010-08-27 09:16:39Z 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 && ( RTStrICmp(argv[1], "-verbose") == 0
899 || RTStrICmp(argv[1], "--verbose") == 0))
900 {
901 fVerbose = true;
902 }
903 else if (argc != 1)
904 {
905 usage(GUEST_PROP);
906 return 1;
907 }
908
909 uint32_t u32ClientId = 0;
910 int rc = VINF_SUCCESS;
911
912 rc = VbglR3GuestPropConnect(&u32ClientId);
913 if (!RT_SUCCESS(rc))
914 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
915
916 /*
917 * Here we actually retrieve the value from the host.
918 */
919 const char *pszName = argv[0];
920 char *pszValue = NULL;
921 uint64_t u64Timestamp = 0;
922 char *pszFlags = NULL;
923 /* The buffer for storing the data and its initial size. We leave a bit
924 * of space here in case the maximum values are raised. */
925 void *pvBuf = NULL;
926 uint32_t cbBuf = MAX_VALUE_LEN + MAX_FLAGS_LEN + 1024;
927 if (RT_SUCCESS(rc))
928 {
929 /* Because there is a race condition between our reading the size of a
930 * property and the guest updating it, we loop a few times here and
931 * hope. Actually this should never go wrong, as we are generous
932 * enough with buffer space. */
933 bool finish = false;
934 for (unsigned i = 0; (i < 10) && !finish; ++i)
935 {
936 void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
937 if (NULL == pvTmpBuf)
938 {
939 rc = VERR_NO_MEMORY;
940 VBoxControlError("Out of memory\n");
941 }
942 else
943 {
944 pvBuf = pvTmpBuf;
945 rc = VbglR3GuestPropRead(u32ClientId, pszName, pvBuf, cbBuf,
946 &pszValue, &u64Timestamp, &pszFlags,
947 &cbBuf);
948 }
949 if (VERR_BUFFER_OVERFLOW == rc)
950 /* Leave a bit of extra space to be safe */
951 cbBuf += 1024;
952 else
953 finish = true;
954 }
955 if (VERR_TOO_MUCH_DATA == rc)
956 VBoxControlError("Temporarily unable to retrieve the property\n");
957 else if (!RT_SUCCESS(rc) && (rc != VERR_NOT_FOUND))
958 VBoxControlError("Failed to retrieve the property value, error %Rrc\n", rc);
959 }
960
961 /*
962 * And display it on the guest console.
963 */
964 if (VERR_NOT_FOUND == rc)
965 RTPrintf("No value set!\n");
966 else if (RT_SUCCESS(rc))
967 {
968 RTPrintf("Value: %S\n", pszValue);
969 if (fVerbose)
970 {
971 RTPrintf("Timestamp: %lld ns\n", u64Timestamp);
972 RTPrintf("Flags: %S\n", pszFlags);
973 }
974 }
975
976 if (u32ClientId != 0)
977 VbglR3GuestPropDisconnect(u32ClientId);
978 RTMemFree(pvBuf);
979 return RT_SUCCESS(rc) ? 0 : 1;
980}
981
982
983/**
984 * Writes a value to the guest property store.
985 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
986 *
987 * @returns 0 on success, 1 on failure
988 * @note see the command line API description for parameters
989 */
990static int setGuestProperty(int argc, char *argv[])
991{
992 /*
993 * Check the syntax. We can deduce the correct syntax from the number of
994 * arguments.
995 */
996 bool usageOK = true;
997 const char *pszName = NULL;
998 const char *pszValue = NULL;
999 const char *pszFlags = NULL;
1000 if (2 == argc)
1001 {
1002 pszValue = argv[1];
1003 }
1004 else if (3 == argc)
1005 usageOK = false;
1006 else if (4 == argc)
1007 {
1008 pszValue = argv[1];
1009 if ( RTStrICmp(argv[2], "-flags") != 0
1010 && RTStrICmp(argv[2], "--flags") != 0)
1011 usageOK = false;
1012 pszFlags = argv[3];
1013 }
1014 else if (argc != 1)
1015 usageOK = false;
1016 if (!usageOK)
1017 {
1018 usage(GUEST_PROP);
1019 return 1;
1020 }
1021 /* This is always needed. */
1022 pszName = argv[0];
1023
1024 /*
1025 * Do the actual setting.
1026 */
1027 uint32_t u32ClientId = 0;
1028 int rc = VINF_SUCCESS;
1029 rc = VbglR3GuestPropConnect(&u32ClientId);
1030 if (!RT_SUCCESS(rc))
1031 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
1032 if (RT_SUCCESS(rc))
1033 {
1034 if (pszFlags != NULL)
1035 rc = VbglR3GuestPropWrite(u32ClientId, pszName, pszValue, pszFlags);
1036 else
1037 rc = VbglR3GuestPropWriteValue(u32ClientId, pszName, pszValue);
1038 if (!RT_SUCCESS(rc))
1039 VBoxControlError("Failed to store the property value, error %Rrc\n", rc);
1040 }
1041
1042 if (u32ClientId != 0)
1043 VbglR3GuestPropDisconnect(u32ClientId);
1044 return RT_SUCCESS(rc) ? 0 : 1;
1045}
1046
1047
1048/**
1049 * Enumerates the properties in the guest property store.
1050 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
1051 *
1052 * @returns 0 on success, 1 on failure
1053 * @note see the command line API description for parameters
1054 */
1055static int enumGuestProperty(int argc, char *argv[])
1056{
1057 /*
1058 * Check the syntax. We can deduce the correct syntax from the number of
1059 * arguments.
1060 */
1061 char const * const *papszPatterns = NULL;
1062 uint32_t cPatterns = 0;
1063 if ( argc > 1
1064 && ( RTStrICmp(argv[0], "-patterns") == 0
1065 || RTStrICmp(argv[0], "--patterns") == 0))
1066 {
1067 papszPatterns = (char const * const *)&argv[1];
1068 cPatterns = argc - 1;
1069 }
1070 else if (argc != 0)
1071 {
1072 usage(GUEST_PROP);
1073 return 1;
1074 }
1075
1076 /*
1077 * Do the actual enumeration.
1078 */
1079 uint32_t u32ClientId = 0;
1080 int rc = VbglR3GuestPropConnect(&u32ClientId);
1081 if (RT_SUCCESS(rc))
1082 {
1083 PVBGLR3GUESTPROPENUM pHandle;
1084 const char *pszName, *pszValue, *pszFlags;
1085 uint64_t u64Timestamp;
1086
1087 rc = VbglR3GuestPropEnum(u32ClientId, papszPatterns, cPatterns, &pHandle,
1088 &pszName, &pszValue, &u64Timestamp, &pszFlags);
1089 if (RT_SUCCESS(rc))
1090 {
1091 while (RT_SUCCESS(rc) && pszName)
1092 {
1093 RTPrintf("Name: %s, value: %s, timestamp: %lld, flags: %s\n",
1094 pszName, pszValue, u64Timestamp, pszFlags);
1095
1096 rc = VbglR3GuestPropEnumNext(pHandle, &pszName, &pszValue, &u64Timestamp, &pszFlags);
1097 if (RT_FAILURE(rc))
1098 VBoxControlError("Error while enumerating guest properties: %Rrc\n", rc);
1099 }
1100
1101 VbglR3GuestPropEnumFree(pHandle);
1102 }
1103 else if (VERR_NOT_FOUND == rc)
1104 RTPrintf("No properties found.\n");
1105 else
1106 VBoxControlError("Failed to enumerate the guest properties! Error: %Rrc\n", rc);
1107 VbglR3GuestPropDisconnect(u32ClientId);
1108 }
1109 else
1110 VBoxControlError("Failed to connect to the guest property service! Error: %Rrc\n", rc);
1111 return RT_SUCCESS(rc) ? 0 : 1;
1112}
1113
1114
1115/**
1116 * Waits for notifications of changes to guest properties.
1117 * This is accessed through the "VBoxGuestPropSvc" HGCM service.
1118 *
1119 * @returns 0 on success, 1 on failure
1120 * @note see the command line API description for parameters
1121 */
1122int waitGuestProperty(int argc, char **argv)
1123{
1124 using namespace guestProp;
1125
1126 /*
1127 * Handle arguments
1128 */
1129 const char *pszPatterns = NULL;
1130 uint64_t u64TimestampIn = 0;
1131 uint32_t u32Timeout = RT_INDEFINITE_WAIT;
1132 bool usageOK = true;
1133 if (argc < 1)
1134 usageOK = false;
1135 pszPatterns = argv[0];
1136 for (int i = 1; usageOK && i < argc; ++i)
1137 {
1138 if ( RTStrICmp(argv[i], "-timeout") == 0
1139 || RTStrICmp(argv[i], "--timeout") == 0)
1140 {
1141 if ( i + 1 >= argc
1142 || RTStrToUInt32Full(argv[i + 1], 10, &u32Timeout)
1143 != VINF_SUCCESS
1144 )
1145 usageOK = false;
1146 else
1147 ++i;
1148 }
1149 else if ( RTStrICmp(argv[i], "-timestamp") == 0
1150 || RTStrICmp(argv[i], "--timestamp") == 0)
1151 {
1152 if ( i + 1 >= argc
1153 || RTStrToUInt64Full(argv[i + 1], 10, &u64TimestampIn)
1154 != VINF_SUCCESS
1155 )
1156 usageOK = false;
1157 else
1158 ++i;
1159 }
1160 else
1161 usageOK = false;
1162 }
1163 if (!usageOK)
1164 {
1165 usage(GUEST_PROP);
1166 return 1;
1167 }
1168
1169 /*
1170 * Connect to the service
1171 */
1172 uint32_t u32ClientId = 0;
1173 int rc = VINF_SUCCESS;
1174
1175 rc = VbglR3GuestPropConnect(&u32ClientId);
1176 if (!RT_SUCCESS(rc))
1177 VBoxControlError("Failed to connect to the guest property service, error %Rrc\n", rc);
1178
1179 /*
1180 * Retrieve the notification from the host
1181 */
1182 char *pszName = NULL;
1183 char *pszValue = NULL;
1184 uint64_t u64TimestampOut = 0;
1185 char *pszFlags = NULL;
1186 /* The buffer for storing the data and its initial size. We leave a bit
1187 * of space here in case the maximum values are raised. */
1188 void *pvBuf = NULL;
1189 uint32_t cbBuf = MAX_NAME_LEN + MAX_VALUE_LEN + MAX_FLAGS_LEN + 1024;
1190 /* Because there is a race condition between our reading the size of a
1191 * property and the guest updating it, we loop a few times here and
1192 * hope. Actually this should never go wrong, as we are generous
1193 * enough with buffer space. */
1194 bool finish = false;
1195 for (unsigned i = 0;
1196 (RT_SUCCESS(rc) || rc == VERR_BUFFER_OVERFLOW) && !finish && (i < 10);
1197 ++i)
1198 {
1199 void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
1200 if (NULL == pvTmpBuf)
1201 {
1202 rc = VERR_NO_MEMORY;
1203 VBoxControlError("Out of memory\n");
1204 }
1205 else
1206 {
1207 pvBuf = pvTmpBuf;
1208 rc = VbglR3GuestPropWait(u32ClientId, pszPatterns, pvBuf, cbBuf,
1209 u64TimestampIn, u32Timeout,
1210 &pszName, &pszValue, &u64TimestampOut,
1211 &pszFlags, &cbBuf);
1212 }
1213 if (VERR_BUFFER_OVERFLOW == rc)
1214 /* Leave a bit of extra space to be safe */
1215 cbBuf += 1024;
1216 else
1217 finish = true;
1218 if (rc == VERR_TOO_MUCH_DATA)
1219 VBoxControlError("Temporarily unable to get a notification\n");
1220 else if (rc == VERR_INTERRUPTED)
1221 VBoxControlError("The request timed out or was interrupted\n");
1222#ifndef RT_OS_WINDOWS /* Windows guests do not do this right */
1223 else if (!RT_SUCCESS(rc) && (rc != VERR_NOT_FOUND))
1224 VBoxControlError("Failed to get a notification, error %Rrc\n", rc);
1225#endif
1226 }
1227
1228 /*
1229 * And display it on the guest console.
1230 */
1231 if (VERR_NOT_FOUND == rc)
1232 RTPrintf("No value set!\n");
1233 else if (rc == VERR_BUFFER_OVERFLOW)
1234 RTPrintf("Internal error: unable to determine the size of the data!\n");
1235 else if (RT_SUCCESS(rc))
1236 {
1237 RTPrintf("Name: %s\n", pszName);
1238 RTPrintf("Value: %s\n", pszValue);
1239 RTPrintf("Timestamp: %lld ns\n", u64TimestampOut);
1240 RTPrintf("Flags: %s\n", pszFlags);
1241 }
1242
1243 if (u32ClientId != 0)
1244 VbglR3GuestPropDisconnect(u32ClientId);
1245 RTMemFree(pvBuf);
1246 return RT_SUCCESS(rc) ? 0 : 1;
1247}
1248
1249
1250/**
1251 * Access the guest property store through the "VBoxGuestPropSvc" HGCM
1252 * service.
1253 *
1254 * @returns 0 on success, 1 on failure
1255 * @note see the command line API description for parameters
1256 */
1257static int handleGuestProperty(int argc, char *argv[])
1258{
1259 if (0 == argc)
1260 {
1261 usage(GUEST_PROP);
1262 return 1;
1263 }
1264 if (0 == RTStrICmp(argv[0], "get"))
1265 return getGuestProperty(argc - 1, argv + 1);
1266 else if (0 == RTStrICmp(argv[0], "set"))
1267 return setGuestProperty(argc - 1, argv + 1);
1268 else if (0 == RTStrICmp(argv[0], "enumerate"))
1269 return enumGuestProperty(argc - 1, argv + 1);
1270 else if (0 == RTStrICmp(argv[0], "wait"))
1271 return waitGuestProperty(argc - 1, argv + 1);
1272 /* else */
1273 usage(GUEST_PROP);
1274 return 1;
1275}
1276#endif
1277
1278#ifdef VBOX_WITH_SHARED_FOLDERS
1279/**
1280 * Lists the Shared Folders provided by the host.
1281 */
1282int listSharedFolders(int argc, char **argv)
1283{
1284 bool usageOK = true;
1285 bool fOnlyShowAutoMount = false;
1286 if (argc == 1)
1287 {
1288 if ( RTStrICmp(argv[0], "-automount") == 0
1289 || RTStrICmp(argv[0], "--automount") == 0
1290 )
1291 {
1292 fOnlyShowAutoMount = true;
1293 }
1294 else
1295 usageOK = false;
1296 }
1297 else if (argc > 1)
1298 usageOK = false;
1299
1300 if (!usageOK)
1301 {
1302 usage(GUEST_SHAREDFOLDERS);
1303 return 1;
1304 }
1305
1306 uint32_t u32ClientId;
1307 int rc = VbglR3SharedFolderConnect(&u32ClientId);
1308 if (!RT_SUCCESS(rc))
1309 VBoxControlError("Failed to connect to the shared folder service, error %Rrc\n", rc);
1310 else
1311 {
1312 PVBGLR3SHAREDFOLDERMAPPING paMappings;
1313 uint32_t cMappings;
1314 rc = VbglR3SharedFolderGetMappings(u32ClientId, fOnlyShowAutoMount,
1315 &paMappings, &cMappings);
1316 if (RT_SUCCESS(rc))
1317 {
1318 if (fOnlyShowAutoMount)
1319 RTPrintf("Auto-mounted Shared Folder mappings (%u):\n\n", cMappings);
1320 else
1321 RTPrintf("Shared Folder mappings (%u):\n\n", cMappings);
1322
1323 for (uint32_t i = 0; i < cMappings; i++)
1324 {
1325 char *pszName;
1326 rc = VbglR3SharedFolderGetName(u32ClientId, paMappings[i].u32Root, &pszName);
1327 if (RT_SUCCESS(rc))
1328 {
1329 RTPrintf("%02u - %s\n", i + 1, pszName);
1330 RTStrFree(pszName);
1331 }
1332 else
1333 VBoxControlError("Error while getting the shared folder name for root node = %u, rc = %Rrc\n",
1334 paMappings[i].u32Root, rc);
1335 }
1336 if (cMappings == 0)
1337 RTPrintf("No Shared Folders available.\n");
1338 VbglR3SharedFolderFreeMappings(paMappings);
1339 }
1340 else
1341 VBoxControlError("Error while getting the shared folder mappings, rc = %Rrc\n", rc);
1342 VbglR3SharedFolderDisconnect(u32ClientId);
1343 }
1344 return RT_SUCCESS(rc) ? 0 : 1;
1345}
1346
1347/**
1348 * Handles Shared Folders control.
1349 *
1350 * @returns 0 on success, 1 on failure
1351 * @note see the command line API description for parameters
1352 */
1353static int handleSharedFolder(int argc, char *argv[])
1354{
1355 if (0 == argc)
1356 {
1357 usage(GUEST_SHAREDFOLDERS);
1358 return 1;
1359 }
1360 if (0 == RTStrICmp(argv[0], "list"))
1361 return listSharedFolders(argc - 1, argv + 1);
1362 /* else */
1363 usage(GUEST_SHAREDFOLDERS);
1364 return 1;
1365}
1366#endif
1367
1368/** command handler type */
1369typedef DECLCALLBACK(int) FNHANDLER(int argc, char *argv[]);
1370typedef FNHANDLER *PFNHANDLER;
1371
1372/** The table of all registered command handlers. */
1373struct COMMANDHANDLER
1374{
1375 const char *command;
1376 PFNHANDLER handler;
1377} g_commandHandlers[] =
1378{
1379#if defined(RT_OS_WINDOWS) && !defined(VBOX_CONTROL_TEST)
1380 { "getvideoacceleration", handleGetVideoAcceleration },
1381 { "setvideoacceleration", handleSetVideoAcceleration },
1382 { "listcustommodes", handleListCustomModes },
1383 { "addcustommode", handleAddCustomMode },
1384 { "removecustommode", handleRemoveCustomMode },
1385 { "setvideomode", handleSetVideoMode },
1386#endif
1387#ifdef VBOX_WITH_GUEST_PROPS
1388 { "guestproperty", handleGuestProperty },
1389#endif
1390#ifdef VBOX_WITH_SHARED_FOLDERS
1391 { "sharedfolder", handleSharedFolder },
1392#endif
1393 { NULL, NULL } /* terminator */
1394};
1395
1396/** Main function */
1397int main(int argc, char **argv)
1398{
1399 /** The application's global return code */
1400 int rc = 0;
1401 /** An IPRT return code for local use */
1402 int rrc = VINF_SUCCESS;
1403 /** The index of the command line argument we are currently processing */
1404 int iArg = 1;
1405 /** Should we show the logo text? */
1406 bool fShowLogo = true;
1407 /** Should we print the usage after the logo? For the -help switch. */
1408 bool fDoHelp = false;
1409 /** Will we be executing a command or just printing information? */
1410 bool fOnlyInfo = false;
1411
1412 /*
1413 * Start by handling command line switches
1414 */
1415
1416 /** Are we finished with handling switches? */
1417 bool done = false;
1418 while (!done && (iArg < argc))
1419 {
1420 if ( 0 == RTStrICmp(argv[iArg], "-v")
1421 || 0 == RTStrICmp(argv[iArg], "--version")
1422 || 0 == RTStrICmp(argv[iArg], "-version")
1423 || 0 == RTStrICmp(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 == RTStrICmp(argv[iArg], "-nologo")
1433 || 0 == RTStrICmp(argv[iArg], "--nologo"))
1434 fShowLogo = false;
1435 else if ( 0 == RTStrICmp(argv[iArg], "-help")
1436 || 0 == RTStrICmp(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 == RTStrICmp(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