VirtualBox

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

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

Shared Folders/AutoMount: Update.

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