VirtualBox

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

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

VBoxManage: Implemented cancelation in showProgress for cancelable progress objects.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.1 KB
Line 
1/* $Id: VBoxManage.cpp 24915 2009-11-24 15:09:43Z vboxsync $ */
2/** @file
3 * VBoxManage - VirtualBox's command-line interface.
4 */
5
6/*
7 * Copyright (C) 2006-2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23/*******************************************************************************
24* Header Files *
25*******************************************************************************/
26#ifndef VBOX_ONLY_DOCS
27# include <VBox/com/com.h>
28# include <VBox/com/string.h>
29# include <VBox/com/Guid.h>
30# include <VBox/com/array.h>
31# include <VBox/com/ErrorInfo.h>
32# include <VBox/com/errorprint.h>
33# include <VBox/com/EventQueue.h>
34
35# include <VBox/com/VirtualBox.h>
36
37# include <vector>
38# include <list>
39#endif /* !VBOX_ONLY_DOCS */
40
41#include <VBox/err.h>
42#include <VBox/version.h>
43
44#include <iprt/asm.h>
45#include <iprt/buildconfig.h>
46#include <iprt/initterm.h>
47#include <iprt/stream.h>
48#include <iprt/string.h>
49
50#include <signal.h>
51
52#include "VBoxManage.h"
53
54
55/*******************************************************************************
56* Global Variables *
57*******************************************************************************/
58/*extern*/ bool g_fDetailedProgress = false;
59
60#ifndef VBOX_ONLY_DOCS
61/** Set by the signal handler. */
62static volatile bool g_fCanceled = false;
63
64
65/**
66 * Signal handler that sets g_fCanceled.
67 *
68 * This can be executed on any thread in the process, on Windows it may even be
69 * a thread dedicated to delivering this signal. Do not doing anything
70 * unnecessary here.
71 */
72static void showProgressSignalHandler(int iSignal)
73{
74 NOREF(iSignal);
75 ASMAtomicWriteBool(&g_fCanceled, true);
76}
77
78
79/**
80 * Print out progress on the console
81 */
82HRESULT showProgress(ComPtr<IProgress> progress)
83{
84 using namespace com;
85
86 BOOL fCompleted;
87 ULONG ulCurrentPercent;
88 ULONG ulLastPercent = 0;
89
90 ULONG ulCurrentOperationPercent;
91 ULONG ulLastOperationPercent = (ULONG)-1;
92
93 ULONG ulLastOperation = (ULONG)-1;
94 Bstr bstrOperationDescription;
95
96 ULONG cOperations;
97 progress->COMGETTER(OperationCount)(&cOperations);
98
99 if (!g_fDetailedProgress)
100 {
101 RTPrintf("0%%...");
102 RTStrmFlush(g_pStdOut);
103 }
104
105 /* setup signal handling if cancelable */
106 bool fCanceledAlready = false;
107 BOOL fCancelable;
108 HRESULT hrc = progress->COMGETTER(Cancelable)(&fCancelable);
109 if (FAILED(hrc))
110 fCancelable = FALSE;
111 if (fCancelable)
112 {
113 signal(SIGINT, showProgressSignalHandler);
114#ifdef SIGBREAK
115 signal(SIGBREAK, showProgressSignalHandler);
116#endif
117 }
118
119 while (SUCCEEDED(progress->COMGETTER(Completed(&fCompleted))))
120 {
121 ULONG ulOperation;
122 progress->COMGETTER(Operation)(&ulOperation);
123
124 progress->COMGETTER(Percent(&ulCurrentPercent));
125 progress->COMGETTER(OperationPercent(&ulCurrentOperationPercent));
126
127 if (g_fDetailedProgress)
128 {
129 if (ulLastOperation != ulOperation)
130 {
131 progress->COMGETTER(OperationDescription(bstrOperationDescription.asOutParam()));
132 ulLastPercent = (ULONG)-1; // force print
133 ulLastOperation = ulOperation;
134 }
135
136 if ( ulCurrentPercent != ulLastPercent
137 || ulCurrentOperationPercent != ulLastOperationPercent
138 )
139 {
140 LONG lSecsRem;
141 progress->COMGETTER(TimeRemaining)(&lSecsRem);
142
143 RTPrintf("(%ld/%ld) %ls %ld%% => %ld%% (%d s remaining)\n", ulOperation + 1, cOperations, bstrOperationDescription.raw(), ulCurrentOperationPercent, ulCurrentPercent, lSecsRem);
144 ulLastPercent = ulCurrentPercent;
145 ulLastOperationPercent = ulCurrentOperationPercent;
146 }
147 }
148 else
149 {
150 /* did we cross a 10% mark? */
151 if (ulCurrentPercent / 10 > ulLastPercent / 10)
152 {
153 /* make sure to also print out missed steps */
154 for (ULONG curVal = (ulLastPercent / 10) * 10 + 10; curVal <= (ulCurrentPercent / 10) * 10; curVal += 10)
155 {
156 if (curVal < 100)
157 {
158 RTPrintf("%ld%%...", curVal);
159 RTStrmFlush(g_pStdOut);
160 }
161 }
162 ulLastPercent = (ulCurrentPercent / 10) * 10;
163 }
164 }
165 if (fCompleted)
166 break;
167
168 /* process async cancelation */
169 if (g_fCanceled && !fCanceledAlready)
170 {
171 hrc = progress->Cancel();
172 if (SUCCEEDED(hrc))
173 fCanceledAlready = true;
174 else
175 g_fCanceled = false;
176 }
177
178 /* make sure the loop is not too tight */
179 progress->WaitForCompletion(100);
180 }
181
182 /* undo signal handling */
183 if (fCancelable)
184 {
185 signal(SIGINT, SIG_DFL);
186#ifdef SIGBREAK
187 signal(SIGBREAK, SIG_DFL);
188#endif
189 }
190
191 /* complete the line. */
192 LONG iRc = E_FAIL;
193 if (SUCCEEDED(progress->COMGETTER(ResultCode)(&iRc)))
194 {
195 if (SUCCEEDED(iRc))
196 RTPrintf("100%%\n");
197 else if (g_fCanceled)
198 RTPrintf("CANCELED\n");
199 else
200 RTPrintf("FAILED\n");
201 }
202 else
203 RTPrintf("\n");
204 RTStrmFlush(g_pStdOut);
205 return iRc;
206}
207
208#endif /* !VBOX_ONLY_DOCS */
209
210int main(int argc, char *argv[])
211{
212 /*
213 * Before we do anything, init the runtime without loading
214 * the support driver.
215 */
216 RTR3Init();
217
218 bool fShowLogo = true;
219 int iCmd = 1;
220 int iCmdArg;
221
222 /* global options */
223 for (int i = 1; i < argc || argc <= iCmd; i++)
224 {
225 if ( argc <= iCmd
226 || !strcmp(argv[i], "help")
227 || !strcmp(argv[i], "-?")
228 || !strcmp(argv[i], "-h")
229 || !strcmp(argv[i], "-help")
230 || !strcmp(argv[i], "--help"))
231 {
232 showLogo();
233 printUsage(USAGE_ALL);
234 return 0;
235 }
236
237 if ( !strcmp(argv[i], "-v")
238 || !strcmp(argv[i], "-version")
239 || !strcmp(argv[i], "-Version")
240 || !strcmp(argv[i], "--version"))
241 {
242 /* Print version number, and do nothing else. */
243 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
244 return 0;
245 }
246
247 if ( !strcmp(argv[i], "--dumpopts")
248 || !strcmp(argv[i], "-dumpopts"))
249 {
250 /* Special option to dump really all commands,
251 * even the ones not understood on this platform. */
252 printUsage(USAGE_DUMPOPTS);
253 return 0;
254 }
255
256 if ( !strcmp(argv[i], "--nologo")
257 || !strcmp(argv[i], "-nologo")
258 || !strcmp(argv[i], "-q"))
259 {
260 /* suppress the logo */
261 fShowLogo = false;
262 iCmd++;
263 }
264 else
265 {
266 break;
267 }
268 }
269
270 iCmdArg = iCmd + 1;
271
272 if (fShowLogo)
273 showLogo();
274
275
276#ifdef VBOX_ONLY_DOCS
277 int rc = 0;
278#else /* !VBOX_ONLY_DOCS */
279 using namespace com;
280 HRESULT rc = 0;
281
282 rc = com::Initialize();
283 if (FAILED(rc))
284 {
285 RTPrintf("ERROR: failed to initialize COM!\n");
286 return rc;
287 }
288
289 /*
290 * The input is in the host OS'es codepage (NT guarantees ACP).
291 * For VBox we use UTF-8 and convert to UCS-2 when calling (XP)COM APIs.
292 * For simplicity, just convert the argv[] array here.
293 */
294 for (int i = iCmdArg; i < argc; i++)
295 {
296 char *converted;
297 RTStrCurrentCPToUtf8(&converted, argv[i]);
298 argv[i] = converted;
299 }
300
301 do
302 {
303 // scopes all the stuff till shutdown
304 ////////////////////////////////////////////////////////////////////////////
305
306 /* convertfromraw: does not need a VirtualBox instantiation. */
307 if (argc >= iCmdArg && ( !strcmp(argv[iCmd], "convertfromraw")
308 || !strcmp(argv[iCmd], "convertdd")))
309 {
310 rc = handleConvertFromRaw(argc - iCmdArg, argv + iCmdArg);
311 break;
312 }
313
314 ComPtr<IVirtualBox> virtualBox;
315 ComPtr<ISession> session;
316
317 rc = virtualBox.createLocalObject(CLSID_VirtualBox);
318 if (FAILED(rc))
319 RTPrintf("ERROR: failed to create the VirtualBox object!\n");
320 else
321 {
322 rc = session.createInprocObject(CLSID_Session);
323 if (FAILED(rc))
324 RTPrintf("ERROR: failed to create a session object!\n");
325 }
326
327 if (FAILED(rc))
328 {
329 com::ErrorInfo info;
330 if (!info.isFullAvailable() && !info.isBasicAvailable())
331 {
332 com::GluePrintRCMessage(rc);
333 RTPrintf("Most likely, the VirtualBox COM server is not running or failed to start.\n");
334 }
335 else
336 com::GluePrintErrorInfo(info);
337 break;
338 }
339
340 HandlerArg handlerArg = { 0, NULL, virtualBox, session };
341
342 /*
343 * All registered command handlers
344 */
345 static const struct
346 {
347 const char *command;
348 int (*handler)(HandlerArg *a);
349 } s_commandHandlers[] =
350 {
351 { "internalcommands", handleInternalCommands },
352 { "list", handleList },
353 { "showvminfo", handleShowVMInfo },
354 { "registervm", handleRegisterVM },
355 { "unregistervm", handleUnregisterVM },
356 { "createhd", handleCreateHardDisk },
357 { "createvdi", handleCreateHardDisk }, /* backward compatiblity */
358 { "modifyhd", handleModifyHardDisk },
359 { "modifyvdi", handleModifyHardDisk }, /* backward compatiblity */
360 { "clonehd", handleCloneHardDisk },
361 { "clonevdi", handleCloneHardDisk }, /* backward compatiblity */
362 { "addiscsidisk", handleAddiSCSIDisk },
363 { "createvm", handleCreateVM },
364 { "modifyvm", handleModifyVM },
365 { "startvm", handleStartVM },
366 { "controlvm", handleControlVM },
367 { "discardstate", handleDiscardState },
368 { "adoptstate", handleAdoptdState },
369 { "snapshot", handleSnapshot },
370 { "openmedium", handleOpenMedium },
371 { "registerimage", handleOpenMedium }, /* backward compatiblity */
372 { "closemedium", handleCloseMedium },
373 { "unregisterimage", handleCloseMedium }, /* backward compatiblity */
374 { "storageattach", handleStorageAttach },
375 { "storagectl", handleStorageController },
376 { "showhdinfo", handleShowHardDiskInfo },
377 { "showvdiinfo", handleShowHardDiskInfo }, /* backward compatiblity */
378 { "getextradata", handleGetExtraData },
379 { "setextradata", handleSetExtraData },
380 { "setproperty", handleSetProperty },
381 { "usbfilter", handleUSBFilter },
382 { "sharedfolder", handleSharedFolder },
383 { "vmstatistics", handleVMStatistics },
384#ifdef VBOX_WITH_GUEST_PROPS
385 { "guestproperty", handleGuestProperty },
386#endif
387 { "metrics", handleMetrics },
388 { "import", handleImportAppliance },
389 { "export", handleExportAppliance },
390#ifdef VBOX_WITH_NETFLT
391 { "hostonlyif", handleHostonlyIf },
392#endif
393 { "dhcpserver", handleDHCPServer},
394 { NULL, NULL }
395 };
396
397 int commandIndex;
398 for (commandIndex = 0; s_commandHandlers[commandIndex].command != NULL; commandIndex++)
399 {
400 if (!strcmp(s_commandHandlers[commandIndex].command, argv[iCmd]))
401 {
402 handlerArg.argc = argc - iCmdArg;
403 handlerArg.argv = &argv[iCmdArg];
404
405 rc = s_commandHandlers[commandIndex].handler(&handlerArg);
406 break;
407 }
408 }
409 if (!s_commandHandlers[commandIndex].command)
410 {
411 rc = errorSyntax(USAGE_ALL, "Invalid command '%s'", Utf8Str(argv[iCmd]).raw());
412 }
413
414 /* Although all handlers should always close the session if they open it,
415 * we do it here just in case if some of the handlers contains a bug --
416 * leaving the direct session not closed will turn the machine state to
417 * Aborted which may have unwanted side effects like killing the saved
418 * state file (if the machine was in the Saved state before). */
419 session->Close();
420
421 EventQueue::getMainEventQueue()->processEventQueue(0);
422 // end "all-stuff" scope
423 ////////////////////////////////////////////////////////////////////////////
424 } while (0);
425
426 com::Shutdown();
427#endif /* !VBOX_ONLY_DOCS */
428
429 /*
430 * Free converted argument vector
431 */
432 for (int i = iCmdArg; i < argc; i++)
433 RTStrFree(argv[i]);
434
435 return rc != 0;
436}
437
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use