VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManage.cpp@ 34587

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

Main: Bandwidth groups for disks (and later network)

This introduces two new interfaces. The first one named IBandwidthGroup
represents one I/O limit and can be assigned to several mediums which
share this limit (which works only for harddisk images with the disabled
host cache).
The second one IBandwdithControl manages the groups and can create new ones
and destroy them if not required anymore.

VBoxManage: commands to access the bandwidth groups

Syntax:
VBoxManage storageattach <uuid|vmname>

...
--bandwidthgroup <name>

--bandwidthgroup assigns the specified device to the given group.

VBoxManage bandwidthctl <uuid|vmname>

--name <name>
--add disk|network
--limit <megabytes per second>
--delete

The --name parameter gives the name of the bandwidth group.
--add creates a new group of the given type (only disk is implemented so far)

with the given name.

--limit sets the limit to the given amount of MB/s

Note that limit can be changed while the VM is running. The VM
will immediately pick up the new limit for the given group name.

--delete deletes the group with the given name if it isn't used anymore.

Trying to delete a still used group will result in an error.

Example:

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 20
Creates a group named Test having a 20 MB/s limit.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup Limit
Adds a new disk to the SATA controller and assigns the bandwidth group Limit to it.

VBoxManage storageattach "Test VM" --storagectl "SATA Controller" --port 0 --device 0 --type hdd --medium test.vdi --bandwidthgroup none
Removes the bandwidth limit from the disk.

VBoxManage bandwidthctl "Test VM" --name Limit --add disk --limit 10
Changes the limit of bandwidth group Limit to 10 MB/s. If the VM is running the limit will be picked up
immediately.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.7 KB
Line 
1/* $Id: VBoxManage.cpp 34587 2010-12-01 20:30:02Z vboxsync $ */
2/** @file
3 * VBoxManage - VirtualBox's command-line interface.
4 */
5
6/*
7 * Copyright (C) 2006-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/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#ifndef VBOX_ONLY_DOCS
23# include <VBox/com/com.h>
24# include <VBox/com/string.h>
25# include <VBox/com/Guid.h>
26# include <VBox/com/array.h>
27# include <VBox/com/ErrorInfo.h>
28# include <VBox/com/errorprint.h>
29# include <VBox/com/EventQueue.h>
30
31# include <VBox/com/VirtualBox.h>
32#endif /* !VBOX_ONLY_DOCS */
33
34#include <VBox/err.h>
35#include <VBox/version.h>
36
37#include <iprt/asm.h>
38#include <iprt/buildconfig.h>
39#include <iprt/initterm.h>
40#include <iprt/stream.h>
41#include <iprt/string.h>
42
43#include <signal.h>
44
45#include "VBoxManage.h"
46
47
48/*******************************************************************************
49* Global Variables *
50*******************************************************************************/
51/*extern*/ bool g_fDetailedProgress = false;
52
53#ifndef VBOX_ONLY_DOCS
54/** Set by the signal handler. */
55static volatile bool g_fCanceled = false;
56
57
58/**
59 * Signal handler that sets g_fCanceled.
60 *
61 * This can be executed on any thread in the process, on Windows it may even be
62 * a thread dedicated to delivering this signal. Do not doing anything
63 * unnecessary here.
64 */
65static void showProgressSignalHandler(int iSignal)
66{
67 NOREF(iSignal);
68 ASMAtomicWriteBool(&g_fCanceled, true);
69}
70
71/**
72 * Print out progress on the console.
73 *
74 * This runs the main event queue every now and then to prevent piling up
75 * unhandled things (which doesn't cause real problems, just makes things
76 * react a little slower than in the ideal case).
77 */
78HRESULT showProgress(ComPtr<IProgress> progress)
79{
80 using namespace com;
81
82 BOOL fCompleted = FALSE;
83 ULONG ulCurrentPercent = 0;
84 ULONG ulLastPercent = 0;
85
86 ULONG ulLastOperationPercent = (ULONG)-1;
87
88 ULONG ulLastOperation = (ULONG)-1;
89 Bstr bstrOperationDescription;
90
91 EventQueue::getMainEventQueue()->processEventQueue(0);
92
93 ULONG cOperations = 1;
94 HRESULT hrc = progress->COMGETTER(OperationCount)(&cOperations);
95 if (FAILED(hrc))
96 {
97 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
98 RTStrmFlush(g_pStdErr);
99 return hrc;
100 }
101
102 if (!g_fDetailedProgress)
103 {
104 RTStrmPrintf(g_pStdErr, "0%%...");
105 RTStrmFlush(g_pStdErr);
106 }
107
108 /* setup signal handling if cancelable */
109 bool fCanceledAlready = false;
110 BOOL fCancelable;
111 hrc = progress->COMGETTER(Cancelable)(&fCancelable);
112 if (FAILED(hrc))
113 fCancelable = FALSE;
114 if (fCancelable)
115 {
116 signal(SIGINT, showProgressSignalHandler);
117#ifdef SIGBREAK
118 signal(SIGBREAK, showProgressSignalHandler);
119#endif
120 }
121
122 hrc = progress->COMGETTER(Completed(&fCompleted));
123 while (SUCCEEDED(hrc))
124 {
125 progress->COMGETTER(Percent(&ulCurrentPercent));
126
127 if (g_fDetailedProgress)
128 {
129 ULONG ulOperation = 1;
130 hrc = progress->COMGETTER(Operation)(&ulOperation);
131 if (FAILED(hrc))
132 break;
133 ULONG ulCurrentOperationPercent = 0;
134 hrc = progress->COMGETTER(OperationPercent(&ulCurrentOperationPercent));
135 if (FAILED(hrc))
136 break;
137
138 if (ulLastOperation != ulOperation)
139 {
140 hrc = progress->COMGETTER(OperationDescription(bstrOperationDescription.asOutParam()));
141 if (FAILED(hrc))
142 break;
143 ulLastPercent = (ULONG)-1; // force print
144 ulLastOperation = ulOperation;
145 }
146
147 if ( ulCurrentPercent != ulLastPercent
148 || ulCurrentOperationPercent != ulLastOperationPercent
149 )
150 {
151 LONG lSecsRem = 0;
152 progress->COMGETTER(TimeRemaining)(&lSecsRem);
153
154 RTStrmPrintf(g_pStdErr, "(%ld/%ld) %ls %ld%% => %ld%% (%d s remaining)\n", ulOperation + 1, cOperations, bstrOperationDescription.raw(), ulCurrentOperationPercent, ulCurrentPercent, lSecsRem);
155 ulLastPercent = ulCurrentPercent;
156 ulLastOperationPercent = ulCurrentOperationPercent;
157 }
158 }
159 else
160 {
161 /* did we cross a 10% mark? */
162 if (ulCurrentPercent / 10 > ulLastPercent / 10)
163 {
164 /* make sure to also print out missed steps */
165 for (ULONG curVal = (ulLastPercent / 10) * 10 + 10; curVal <= (ulCurrentPercent / 10) * 10; curVal += 10)
166 {
167 if (curVal < 100)
168 {
169 RTStrmPrintf(g_pStdErr, "%ld%%...", curVal);
170 RTStrmFlush(g_pStdErr);
171 }
172 }
173 ulLastPercent = (ulCurrentPercent / 10) * 10;
174 }
175 }
176 if (fCompleted)
177 break;
178
179 /* process async cancelation */
180 if (g_fCanceled && !fCanceledAlready)
181 {
182 hrc = progress->Cancel();
183 if (SUCCEEDED(hrc))
184 fCanceledAlready = true;
185 else
186 g_fCanceled = false;
187 }
188
189 /* make sure the loop is not too tight */
190 progress->WaitForCompletion(100);
191
192 EventQueue::getMainEventQueue()->processEventQueue(0);
193 hrc = progress->COMGETTER(Completed(&fCompleted));
194 }
195
196 /* undo signal handling */
197 if (fCancelable)
198 {
199 signal(SIGINT, SIG_DFL);
200#ifdef SIGBREAK
201 signal(SIGBREAK, SIG_DFL);
202#endif
203 }
204
205 /* complete the line. */
206 LONG iRc = E_FAIL;
207 hrc = progress->COMGETTER(ResultCode)(&iRc);
208 if (SUCCEEDED(hrc))
209 {
210 if (SUCCEEDED(iRc))
211 RTStrmPrintf(g_pStdErr, "100%%\n");
212 else if (g_fCanceled)
213 RTStrmPrintf(g_pStdErr, "CANCELED\n");
214 else
215 {
216 if (!g_fDetailedProgress)
217 RTStrmPrintf(g_pStdErr, "\n");
218 RTStrmPrintf(g_pStdErr, "Progress state: %Rhrc\n", iRc);
219 }
220 hrc = iRc;
221 }
222 else
223 {
224 if (!g_fDetailedProgress)
225 RTStrmPrintf(g_pStdErr, "\n");
226 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
227 }
228 RTStrmFlush(g_pStdErr);
229 return hrc;
230}
231
232#endif /* !VBOX_ONLY_DOCS */
233
234int main(int argc, char *argv[])
235{
236 /*
237 * Before we do anything, init the runtime without loading
238 * the support driver.
239 */
240 RTR3Init();
241
242 /*
243 * Parse the global options
244 */
245 bool fShowLogo = false;
246 bool fShowHelp = false;
247 int iCmd = 1;
248 int iCmdArg;
249
250 for (int i = 1; i < argc || argc <= iCmd; i++)
251 {
252 if ( argc <= iCmd
253 || !strcmp(argv[i], "help")
254 || !strcmp(argv[i], "-?")
255 || !strcmp(argv[i], "-h")
256 || !strcmp(argv[i], "-help")
257 || !strcmp(argv[i], "--help"))
258 {
259 if (i >= argc - 1)
260 {
261 showLogo(g_pStdOut);
262 printUsage(USAGE_ALL, g_pStdOut);
263 return 0;
264 }
265 fShowLogo = true;
266 fShowHelp = true;
267 iCmd++;
268 continue;
269 }
270
271 if ( !strcmp(argv[i], "-v")
272 || !strcmp(argv[i], "-version")
273 || !strcmp(argv[i], "-Version")
274 || !strcmp(argv[i], "--version"))
275 {
276 /* Print version number, and do nothing else. */
277 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
278 return 0;
279 }
280
281 if ( !strcmp(argv[i], "--dumpopts")
282 || !strcmp(argv[i], "-dumpopts"))
283 {
284 /* Special option to dump really all commands,
285 * even the ones not understood on this platform. */
286 printUsage(USAGE_DUMPOPTS, g_pStdOut);
287 return 0;
288 }
289
290 if ( !strcmp(argv[i], "--nologo")
291 || !strcmp(argv[i], "-nologo")
292 || !strcmp(argv[i], "-q"))
293 {
294 /* suppress the logo */
295 fShowLogo = false;
296 iCmd++;
297 }
298 else
299 {
300 break;
301 }
302 }
303
304 iCmdArg = iCmd + 1;
305
306 if (fShowLogo)
307 showLogo(g_pStdOut);
308
309
310#ifndef VBOX_ONLY_DOCS
311 /*
312 * Initialize COM.
313 */
314 using namespace com;
315 HRESULT hrc = com::Initialize();
316 if (FAILED(hrc))
317 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM!");
318
319 /*
320 * The input is ASSUMED to be in the current process codeset (NT guarantees
321 * ACP, unixy systems doesn't guarantee anything). This loop converts all
322 * the argv[*] strings to UTF-8, which is a tad ugly but who cares.
323 * (As a rule all strings in VirtualBox are UTF-8.)
324 */
325 for (int i = iCmdArg; i < argc; i++)
326 {
327 char *pszConverted;
328 int rc = RTStrCurrentCPToUtf8(&pszConverted, argv[i]);
329 if (RT_SUCCESS(rc))
330 argv[i] = pszConverted;
331 else
332 /* Conversion was not possible,probably due to invalid characters.
333 * Keep in mind that we do RTStrFree on the whole array below. */
334 argv[i] = RTStrDup(argv[i]);
335 }
336
337 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
338 do
339 {
340 ///////////////////////////////////////////////////////////////////////////
341 // scopes all the stuff till shutdown
342 /*
343 * convertfromraw: does not need a VirtualBox instantiation.
344 */
345 if (argc >= iCmdArg && ( !strcmp(argv[iCmd], "convertfromraw")
346 || !strcmp(argv[iCmd], "convertdd")))
347 {
348 rcExit = handleConvertFromRaw(argc - iCmdArg, argv + iCmdArg);
349 break;
350 }
351
352 /*
353 * Get the remote VirtualBox object and create a local session object.
354 */
355 ComPtr<IVirtualBox> virtualBox;
356 ComPtr<ISession> session;
357
358 hrc = virtualBox.createLocalObject(CLSID_VirtualBox);
359 if (FAILED(hrc))
360 RTMsgError("Failed to create the VirtualBox object!");
361 else
362 {
363 hrc = session.createInprocObject(CLSID_Session);
364 if (FAILED(hrc))
365 RTMsgError("Failed to create a session object!");
366 }
367 if (FAILED(hrc))
368 {
369 com::ErrorInfo info;
370 if (!info.isFullAvailable() && !info.isBasicAvailable())
371 {
372 com::GluePrintRCMessage(hrc);
373 RTMsgError("Most likely, the VirtualBox COM server is not running or failed to start.");
374 }
375 else
376 com::GluePrintErrorInfo(info);
377 break;
378 }
379
380 /*
381 * All registered command handlers
382 */
383 static const struct
384 {
385 const char *command;
386 USAGECATEGORY help;
387 int (*handler)(HandlerArg *a);
388 } s_commandHandlers[] =
389 {
390 { "internalcommands", 0, handleInternalCommands },
391 { "list", USAGE_LIST, handleList },
392 { "showvminfo", USAGE_SHOWVMINFO, handleShowVMInfo },
393 { "registervm", USAGE_REGISTERVM, handleRegisterVM },
394 { "unregistervm", USAGE_UNREGISTERVM, handleUnregisterVM },
395 { "createhd", USAGE_CREATEHD, handleCreateHardDisk },
396 { "createvdi", USAGE_CREATEHD, handleCreateHardDisk }, /* backward compatibility */
397 { "modifyhd", USAGE_MODIFYHD, handleModifyHardDisk },
398 { "modifyvdi", USAGE_MODIFYHD, handleModifyHardDisk }, /* backward compatibility */
399 { "clonehd", USAGE_CLONEHD, handleCloneHardDisk },
400 { "clonevdi", USAGE_CLONEHD, handleCloneHardDisk }, /* backward compatibility */
401 { "addiscsidisk", USAGE_ADDISCSIDISK, handleAddiSCSIDisk },
402 { "createvm", USAGE_CREATEVM, handleCreateVM },
403 { "modifyvm", USAGE_MODIFYVM, handleModifyVM },
404 { "startvm", USAGE_STARTVM, handleStartVM },
405 { "controlvm", USAGE_CONTROLVM, handleControlVM },
406 { "discardstate", USAGE_DISCARDSTATE, handleDiscardState },
407 { "adoptstate", USAGE_ADOPTSTATE, handleAdoptState },
408 { "snapshot", USAGE_SNAPSHOT, handleSnapshot },
409 { "closemedium", USAGE_CLOSEMEDIUM, handleCloseMedium },
410 { "storageattach", USAGE_STORAGEATTACH, handleStorageAttach },
411 { "storagectl", USAGE_STORAGECONTROLLER, handleStorageController },
412 { "showhdinfo", USAGE_SHOWHDINFO, handleShowHardDiskInfo },
413 { "showvdiinfo", USAGE_SHOWHDINFO, handleShowHardDiskInfo }, /* backward compatibility */
414 { "getextradata", USAGE_GETEXTRADATA, handleGetExtraData },
415 { "setextradata", USAGE_SETEXTRADATA, handleSetExtraData },
416 { "setproperty", USAGE_SETPROPERTY, handleSetProperty },
417 { "usbfilter", USAGE_USBFILTER, handleUSBFilter },
418 { "sharedfolder", USAGE_SHAREDFOLDER, handleSharedFolder },
419 { "vmstatistics", USAGE_VM_STATISTICS, handleVMStatistics },
420#ifdef VBOX_WITH_GUEST_PROPS
421 { "guestproperty", USAGE_GUESTPROPERTY, handleGuestProperty },
422#endif
423#ifdef VBOX_WITH_GUEST_CONTROL
424 { "guestcontrol", USAGE_GUESTCONTROL, handleGuestControl },
425#endif
426 { "metrics", USAGE_METRICS, handleMetrics },
427 { "import", USAGE_IMPORTAPPLIANCE, handleImportAppliance },
428 { "export", USAGE_EXPORTAPPLIANCE, handleExportAppliance },
429#ifdef VBOX_WITH_NETFLT
430 { "hostonlyif", USAGE_HOSTONLYIFS, handleHostonlyIf },
431#endif
432 { "dhcpserver", USAGE_DHCPSERVER, handleDHCPServer},
433 { "extpack", USAGE_EXTPACK, handleExtPack},
434 { "bandwidthctl", USAGE_BANDWIDTHCONTROL, handleBandwidthControl},
435 { NULL, 0, NULL }
436 };
437
438 HandlerArg handlerArg = { 0, NULL, virtualBox, session };
439 int commandIndex;
440 for (commandIndex = 0; s_commandHandlers[commandIndex].command != NULL; commandIndex++)
441 {
442 if (!strcmp(s_commandHandlers[commandIndex].command, argv[iCmd]))
443 {
444 handlerArg.argc = argc - iCmdArg;
445 handlerArg.argv = &argv[iCmdArg];
446
447 if ( fShowHelp
448 || ( argc - iCmdArg == 0
449 && s_commandHandlers[commandIndex].help))
450 {
451 printUsage(s_commandHandlers[commandIndex].help, g_pStdOut);
452 rcExit = RTEXITCODE_FAILURE; /* error */
453 }
454 else
455 rcExit = (RTEXITCODE)s_commandHandlers[commandIndex].handler(&handlerArg); /** @todo Change to return RTEXITCODE. */
456 break;
457 }
458 }
459 if (!s_commandHandlers[commandIndex].command)
460 rcExit = errorSyntax(USAGE_ALL, "Invalid command '%s'", Utf8Str(argv[iCmd]).c_str());
461
462 /* Although all handlers should always close the session if they open it,
463 * we do it here just in case if some of the handlers contains a bug --
464 * leaving the direct session not closed will turn the machine state to
465 * Aborted which may have unwanted side effects like killing the saved
466 * state file (if the machine was in the Saved state before). */
467 session->UnlockMachine();
468
469 EventQueue::getMainEventQueue()->processEventQueue(0);
470
471 // end "all-stuff" scope
472 ///////////////////////////////////////////////////////////////////////////
473 } while (0);
474
475 com::Shutdown();
476
477 /*
478 * Free converted argument vector
479 */
480 for (int i = iCmdArg; i < argc; i++)
481 {
482 RTStrFree(argv[i]);
483 argv[i] = NULL;
484 }
485
486 return rcExit;
487#else /* VBOX_ONLY_DOCS */
488 return RTEXITCODE_SUCCESS;
489#endif /* VBOX_ONLY_DOCS */
490}
Note: See TracBrowser for help on using the repository browser.

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