VirtualBox

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

Last change on this file since 40673 was 39793, checked in by vboxsync, 13 years ago

VBoxManage: Comment.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.8 KB
Line 
1/* $Id: VBoxManage.cpp 39793 2012-01-18 12:53:33Z 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 /*
103 * Note: Outputting the progress info to stderr (g_pStdErr) is intentional
104 * to not get intermixed with other (raw) stdout data which might get
105 * written in the meanwhile.
106 */
107
108 if (!g_fDetailedProgress)
109 {
110 RTStrmPrintf(g_pStdErr, "0%%...");
111 RTStrmFlush(g_pStdErr);
112 }
113
114 /* setup signal handling if cancelable */
115 bool fCanceledAlready = false;
116 BOOL fCancelable;
117 hrc = progress->COMGETTER(Cancelable)(&fCancelable);
118 if (FAILED(hrc))
119 fCancelable = FALSE;
120 if (fCancelable)
121 {
122 signal(SIGINT, showProgressSignalHandler);
123#ifdef SIGBREAK
124 signal(SIGBREAK, showProgressSignalHandler);
125#endif
126 }
127
128 hrc = progress->COMGETTER(Completed(&fCompleted));
129 while (SUCCEEDED(hrc))
130 {
131 progress->COMGETTER(Percent(&ulCurrentPercent));
132
133 if (g_fDetailedProgress)
134 {
135 ULONG ulOperation = 1;
136 hrc = progress->COMGETTER(Operation)(&ulOperation);
137 if (FAILED(hrc))
138 break;
139 ULONG ulCurrentOperationPercent = 0;
140 hrc = progress->COMGETTER(OperationPercent(&ulCurrentOperationPercent));
141 if (FAILED(hrc))
142 break;
143
144 if (ulLastOperation != ulOperation)
145 {
146 hrc = progress->COMGETTER(OperationDescription(bstrOperationDescription.asOutParam()));
147 if (FAILED(hrc))
148 break;
149 ulLastPercent = (ULONG)-1; // force print
150 ulLastOperation = ulOperation;
151 }
152
153 if ( ulCurrentPercent != ulLastPercent
154 || ulCurrentOperationPercent != ulLastOperationPercent
155 )
156 {
157 LONG lSecsRem = 0;
158 progress->COMGETTER(TimeRemaining)(&lSecsRem);
159
160 RTStrmPrintf(g_pStdErr, "(%u/%u) %ls %02u%% => %02u%% (%d s remaining)\n", ulOperation + 1, cOperations, bstrOperationDescription.raw(), ulCurrentOperationPercent, ulCurrentPercent, lSecsRem);
161 ulLastPercent = ulCurrentPercent;
162 ulLastOperationPercent = ulCurrentOperationPercent;
163 }
164 }
165 else
166 {
167 /* did we cross a 10% mark? */
168 if (ulCurrentPercent / 10 > ulLastPercent / 10)
169 {
170 /* make sure to also print out missed steps */
171 for (ULONG curVal = (ulLastPercent / 10) * 10 + 10; curVal <= (ulCurrentPercent / 10) * 10; curVal += 10)
172 {
173 if (curVal < 100)
174 {
175 RTStrmPrintf(g_pStdErr, "%u%%...", curVal);
176 RTStrmFlush(g_pStdErr);
177 }
178 }
179 ulLastPercent = (ulCurrentPercent / 10) * 10;
180 }
181 }
182 if (fCompleted)
183 break;
184
185 /* process async cancelation */
186 if (g_fCanceled && !fCanceledAlready)
187 {
188 hrc = progress->Cancel();
189 if (SUCCEEDED(hrc))
190 fCanceledAlready = true;
191 else
192 g_fCanceled = false;
193 }
194
195 /* make sure the loop is not too tight */
196 progress->WaitForCompletion(100);
197
198 EventQueue::getMainEventQueue()->processEventQueue(0);
199 hrc = progress->COMGETTER(Completed(&fCompleted));
200 }
201
202 /* undo signal handling */
203 if (fCancelable)
204 {
205 signal(SIGINT, SIG_DFL);
206#ifdef SIGBREAK
207 signal(SIGBREAK, SIG_DFL);
208#endif
209 }
210
211 /* complete the line. */
212 LONG iRc = E_FAIL;
213 hrc = progress->COMGETTER(ResultCode)(&iRc);
214 if (SUCCEEDED(hrc))
215 {
216 if (SUCCEEDED(iRc))
217 RTStrmPrintf(g_pStdErr, "100%%\n");
218 else if (g_fCanceled)
219 RTStrmPrintf(g_pStdErr, "CANCELED\n");
220 else
221 {
222 if (!g_fDetailedProgress)
223 RTStrmPrintf(g_pStdErr, "\n");
224 RTStrmPrintf(g_pStdErr, "Progress state: %Rhrc\n", iRc);
225 }
226 hrc = iRc;
227 }
228 else
229 {
230 if (!g_fDetailedProgress)
231 RTStrmPrintf(g_pStdErr, "\n");
232 RTStrmPrintf(g_pStdErr, "Progress object failure: %Rhrc\n", hrc);
233 }
234 RTStrmFlush(g_pStdErr);
235 return hrc;
236}
237
238#ifdef RT_OS_WINDOWS
239// Required for ATL
240static CComModule _Module;
241#endif
242
243#endif /* !VBOX_ONLY_DOCS */
244
245
246int main(int argc, char *argv[])
247{
248 /*
249 * Before we do anything, init the runtime without loading
250 * the support driver.
251 */
252 RTR3InitExe(argc, &argv, 0);
253
254 /*
255 * Parse the global options
256 */
257 bool fShowLogo = false;
258 bool fShowHelp = false;
259 int iCmd = 1;
260 int iCmdArg;
261
262 for (int i = 1; i < argc || argc <= iCmd; i++)
263 {
264 if ( argc <= iCmd
265 || !strcmp(argv[i], "help")
266 || !strcmp(argv[i], "-?")
267 || !strcmp(argv[i], "-h")
268 || !strcmp(argv[i], "-help")
269 || !strcmp(argv[i], "--help"))
270 {
271 if (i >= argc - 1)
272 {
273 showLogo(g_pStdOut);
274 printUsage(USAGE_ALL, g_pStdOut);
275 return 0;
276 }
277 fShowLogo = true;
278 fShowHelp = true;
279 iCmd++;
280 continue;
281 }
282
283 if ( !strcmp(argv[i], "-v")
284 || !strcmp(argv[i], "-version")
285 || !strcmp(argv[i], "-Version")
286 || !strcmp(argv[i], "--version"))
287 {
288 /* Print version number, and do nothing else. */
289 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
290 return 0;
291 }
292
293 if ( !strcmp(argv[i], "--dumpopts")
294 || !strcmp(argv[i], "-dumpopts"))
295 {
296 /* Special option to dump really all commands,
297 * even the ones not understood on this platform. */
298 printUsage(USAGE_DUMPOPTS, g_pStdOut);
299 return 0;
300 }
301
302 if ( !strcmp(argv[i], "--nologo")
303 || !strcmp(argv[i], "-nologo")
304 || !strcmp(argv[i], "-q"))
305 {
306 /* suppress the logo */
307 fShowLogo = false;
308 iCmd++;
309 }
310 else if ( !strcmp(argv[i], "--detailed-progress")
311 || !strcmp(argv[i], "-d"))
312 {
313 /* detailed progress report */
314 g_fDetailedProgress = true;
315 iCmd++;
316 }
317 else
318 {
319 break;
320 }
321 }
322
323 iCmdArg = iCmd + 1;
324
325 if (fShowLogo)
326 showLogo(g_pStdOut);
327
328
329#ifndef VBOX_ONLY_DOCS
330 /*
331 * Initialize COM.
332 */
333 using namespace com;
334 HRESULT hrc = com::Initialize();
335 if (FAILED(hrc))
336 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to initialize COM!");
337
338 RTEXITCODE rcExit = RTEXITCODE_FAILURE;
339 do
340 {
341 ///////////////////////////////////////////////////////////////////////////
342 // scopes all the stuff till shutdown
343 /*
344 * convertfromraw: does not need a VirtualBox instantiation.
345 */
346 if (argc >= iCmdArg && ( !strcmp(argv[iCmd], "convertfromraw")
347 || !strcmp(argv[iCmd], "convertdd")))
348 {
349 rcExit = handleConvertFromRaw(argc - iCmdArg, argv + iCmdArg);
350 break;
351 }
352
353 /*
354 * Get the remote VirtualBox object and create a local session object.
355 */
356 ComPtr<IVirtualBox> virtualBox;
357 ComPtr<ISession> session;
358
359 hrc = virtualBox.createLocalObject(CLSID_VirtualBox);
360 if (FAILED(hrc))
361 RTMsgError("Failed to create the VirtualBox object!");
362 else
363 {
364 hrc = session.createInprocObject(CLSID_Session);
365 if (FAILED(hrc))
366 RTMsgError("Failed to create a session object!");
367 }
368 if (FAILED(hrc))
369 {
370 com::ErrorInfo info;
371 if (!info.isFullAvailable() && !info.isBasicAvailable())
372 {
373 com::GluePrintRCMessage(hrc);
374 RTMsgError("Most likely, the VirtualBox COM server is not running or failed to start.");
375 }
376 else
377 com::GluePrintErrorInfo(info);
378 break;
379 }
380
381 /*
382 * All registered command handlers
383 */
384 static const struct
385 {
386 const char *command;
387 USAGECATEGORY help;
388 int (*handler)(HandlerArg *a);
389 } s_commandHandlers[] =
390 {
391 { "internalcommands", 0, handleInternalCommands },
392 { "list", USAGE_LIST, handleList },
393 { "showvminfo", USAGE_SHOWVMINFO, handleShowVMInfo },
394 { "registervm", USAGE_REGISTERVM, handleRegisterVM },
395 { "unregistervm", USAGE_UNREGISTERVM, handleUnregisterVM },
396 { "clonevm", USAGE_CLONEVM, handleCloneVM },
397 { "createhd", USAGE_CREATEHD, handleCreateHardDisk },
398 { "createvdi", USAGE_CREATEHD, handleCreateHardDisk }, /* backward compatibility */
399 { "modifyhd", USAGE_MODIFYHD, handleModifyHardDisk },
400 { "modifyvdi", USAGE_MODIFYHD, handleModifyHardDisk }, /* backward compatibility */
401 { "clonehd", USAGE_CLONEHD, handleCloneHardDisk },
402 { "clonevdi", USAGE_CLONEHD, handleCloneHardDisk }, /* backward compatibility */
403 { "createvm", USAGE_CREATEVM, handleCreateVM },
404 { "modifyvm", USAGE_MODIFYVM, handleModifyVM },
405 { "startvm", USAGE_STARTVM, handleStartVM },
406 { "controlvm", USAGE_CONTROLVM, handleControlVM },
407 { "discardstate", USAGE_DISCARDSTATE, handleDiscardState },
408 { "adoptstate", USAGE_ADOPTSTATE, handleAdoptState },
409 { "snapshot", USAGE_SNAPSHOT, handleSnapshot },
410 { "closemedium", USAGE_CLOSEMEDIUM, handleCloseMedium },
411 { "storageattach", USAGE_STORAGEATTACH, handleStorageAttach },
412 { "storagectl", USAGE_STORAGECONTROLLER, handleStorageController },
413 { "showhdinfo", USAGE_SHOWHDINFO, handleShowHardDiskInfo },
414 { "showvdiinfo", USAGE_SHOWHDINFO, handleShowHardDiskInfo }, /* backward compatibility */
415 { "getextradata", USAGE_GETEXTRADATA, handleGetExtraData },
416 { "setextradata", USAGE_SETEXTRADATA, handleSetExtraData },
417 { "setproperty", USAGE_SETPROPERTY, handleSetProperty },
418 { "usbfilter", USAGE_USBFILTER, handleUSBFilter },
419 { "sharedfolder", USAGE_SHAREDFOLDER, handleSharedFolder },
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 { "debugvm", USAGE_DEBUGVM, handleDebugVM},
436 { NULL, 0, NULL }
437 };
438
439 HandlerArg handlerArg = { 0, NULL, virtualBox, session };
440 int commandIndex;
441 for (commandIndex = 0; s_commandHandlers[commandIndex].command != NULL; commandIndex++)
442 {
443 if (!strcmp(s_commandHandlers[commandIndex].command, argv[iCmd]))
444 {
445 handlerArg.argc = argc - iCmdArg;
446 handlerArg.argv = &argv[iCmdArg];
447
448 if ( fShowHelp
449 || ( argc - iCmdArg == 0
450 && s_commandHandlers[commandIndex].help))
451 {
452 printUsage(s_commandHandlers[commandIndex].help, g_pStdOut);
453 rcExit = RTEXITCODE_FAILURE; /* error */
454 }
455 else
456 rcExit = (RTEXITCODE)s_commandHandlers[commandIndex].handler(&handlerArg); /** @todo Change to return RTEXITCODE. */
457 break;
458 }
459 }
460 if (!s_commandHandlers[commandIndex].command)
461 {
462 /* Help topics. */
463 if (fShowHelp && !strcmp(argv[iCmd], "commands"))
464 {
465 RTPrintf("commands:\n");
466 for (unsigned i = 0; i < RT_ELEMENTS(s_commandHandlers) - 1; i++)
467 if ( i == 0 /* skip backwards compatibility entries */
468 || s_commandHandlers[i].help != s_commandHandlers[i - 1].help)
469 RTPrintf(" %s\n", s_commandHandlers[i].command);
470 }
471 else
472 rcExit = errorSyntax(USAGE_ALL, "Invalid command '%s'", Utf8Str(argv[iCmd]).c_str());
473 }
474
475 /* Although all handlers should always close the session if they open it,
476 * we do it here just in case if some of the handlers contains a bug --
477 * leaving the direct session not closed will turn the machine state to
478 * Aborted which may have unwanted side effects like killing the saved
479 * state file (if the machine was in the Saved state before). */
480 session->UnlockMachine();
481
482 EventQueue::getMainEventQueue()->processEventQueue(0);
483
484 // end "all-stuff" scope
485 ///////////////////////////////////////////////////////////////////////////
486 } while (0);
487
488 com::Shutdown();
489
490 return rcExit;
491#else /* VBOX_ONLY_DOCS */
492 return RTEXITCODE_SUCCESS;
493#endif /* VBOX_ONLY_DOCS */
494}
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