VirtualBox

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

Last change on this file since 47991 was 47991, checked in by vboxsync, 12 years ago

Main: Made the exclusive HW virtualization use setting global rather than per-VM.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.2 KB
Line 
1/* $Id: VBoxManageMisc.cpp 47991 2013-08-22 14:31:52Z vboxsync $ */
2/** @file
3 * VBoxManage - VirtualBox's command-line interface.
4 */
5
6/*
7 * Copyright (C) 2006-2013 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/VirtualBox.h>
30#endif /* !VBOX_ONLY_DOCS */
31
32#include <iprt/asm.h>
33#include <iprt/buildconfig.h>
34#include <iprt/cidr.h>
35#include <iprt/ctype.h>
36#include <iprt/dir.h>
37#include <iprt/env.h>
38#include <VBox/err.h>
39#include <iprt/file.h>
40#include <iprt/initterm.h>
41#include <iprt/param.h>
42#include <iprt/path.h>
43#include <iprt/stream.h>
44#include <iprt/string.h>
45#include <iprt/stdarg.h>
46#include <iprt/thread.h>
47#include <iprt/uuid.h>
48#include <iprt/getopt.h>
49#include <iprt/ctype.h>
50#include <VBox/version.h>
51#include <VBox/log.h>
52
53#include "VBoxManage.h"
54
55#include <list>
56
57using namespace com;
58
59
60
61int handleRegisterVM(HandlerArg *a)
62{
63 HRESULT rc;
64
65 if (a->argc != 1)
66 return errorSyntax(USAGE_REGISTERVM, "Incorrect number of parameters");
67
68 ComPtr<IMachine> machine;
69 /** @todo Ugly hack to get both the API interpretation of relative paths
70 * and the client's interpretation of relative paths. Remove after the API
71 * has been redesigned. */
72 rc = a->virtualBox->OpenMachine(Bstr(a->argv[0]).raw(),
73 machine.asOutParam());
74 if (rc == VBOX_E_FILE_ERROR)
75 {
76 char szVMFileAbs[RTPATH_MAX] = "";
77 int vrc = RTPathAbs(a->argv[0], szVMFileAbs, sizeof(szVMFileAbs));
78 if (RT_FAILURE(vrc))
79 {
80 RTMsgError("Cannot convert filename \"%s\" to absolute path", a->argv[0]);
81 return 1;
82 }
83 CHECK_ERROR(a->virtualBox, OpenMachine(Bstr(szVMFileAbs).raw(),
84 machine.asOutParam()));
85 }
86 else if (FAILED(rc))
87 CHECK_ERROR(a->virtualBox, OpenMachine(Bstr(a->argv[0]).raw(),
88 machine.asOutParam()));
89 if (SUCCEEDED(rc))
90 {
91 ASSERT(machine);
92 CHECK_ERROR(a->virtualBox, RegisterMachine(machine));
93 }
94 return SUCCEEDED(rc) ? 0 : 1;
95}
96
97static const RTGETOPTDEF g_aUnregisterVMOptions[] =
98{
99 { "--delete", 'd', RTGETOPT_REQ_NOTHING },
100 { "-delete", 'd', RTGETOPT_REQ_NOTHING }, // deprecated
101};
102
103int handleUnregisterVM(HandlerArg *a)
104{
105 HRESULT rc;
106 const char *VMName = NULL;
107 bool fDelete = false;
108
109 int c;
110 RTGETOPTUNION ValueUnion;
111 RTGETOPTSTATE GetState;
112 // start at 0 because main() has hacked both the argc and argv given to us
113 RTGetOptInit(&GetState, a->argc, a->argv, g_aUnregisterVMOptions, RT_ELEMENTS(g_aUnregisterVMOptions),
114 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
115 while ((c = RTGetOpt(&GetState, &ValueUnion)))
116 {
117 switch (c)
118 {
119 case 'd': // --delete
120 fDelete = true;
121 break;
122
123 case VINF_GETOPT_NOT_OPTION:
124 if (!VMName)
125 VMName = ValueUnion.psz;
126 else
127 return errorSyntax(USAGE_UNREGISTERVM, "Invalid parameter '%s'", ValueUnion.psz);
128 break;
129
130 default:
131 if (c > 0)
132 {
133 if (RT_C_IS_PRINT(c))
134 return errorSyntax(USAGE_UNREGISTERVM, "Invalid option -%c", c);
135 else
136 return errorSyntax(USAGE_UNREGISTERVM, "Invalid option case %i", c);
137 }
138 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
139 return errorSyntax(USAGE_UNREGISTERVM, "unknown option: %s\n", ValueUnion.psz);
140 else if (ValueUnion.pDef)
141 return errorSyntax(USAGE_UNREGISTERVM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
142 else
143 return errorSyntax(USAGE_UNREGISTERVM, "error: %Rrs", c);
144 }
145 }
146
147 /* check for required options */
148 if (!VMName)
149 return errorSyntax(USAGE_UNREGISTERVM, "VM name required");
150
151 ComPtr<IMachine> machine;
152 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(VMName).raw(),
153 machine.asOutParam()),
154 RTEXITCODE_FAILURE);
155 SafeIfaceArray<IMedium> aMedia;
156 CHECK_ERROR_RET(machine, Unregister(fDelete ? (CleanupMode_T)CleanupMode_DetachAllReturnHardDisksOnly : (CleanupMode_T)CleanupMode_DetachAllReturnNone,
157 ComSafeArrayAsOutParam(aMedia)),
158 RTEXITCODE_FAILURE);
159 if (fDelete)
160 {
161 ComPtr<IProgress> pProgress;
162 CHECK_ERROR_RET(machine, DeleteConfig(ComSafeArrayAsInParam(aMedia), pProgress.asOutParam()),
163 RTEXITCODE_FAILURE);
164
165 rc = showProgress(pProgress);
166 CHECK_PROGRESS_ERROR_RET(pProgress, ("Machine delete failed"), RTEXITCODE_FAILURE);
167 }
168 return RTEXITCODE_SUCCESS;
169}
170
171static const RTGETOPTDEF g_aCreateVMOptions[] =
172{
173 { "--name", 'n', RTGETOPT_REQ_STRING },
174 { "-name", 'n', RTGETOPT_REQ_STRING },
175 { "--groups", 'g', RTGETOPT_REQ_STRING },
176 { "--basefolder", 'p', RTGETOPT_REQ_STRING },
177 { "-basefolder", 'p', RTGETOPT_REQ_STRING },
178 { "--ostype", 'o', RTGETOPT_REQ_STRING },
179 { "-ostype", 'o', RTGETOPT_REQ_STRING },
180 { "--uuid", 'u', RTGETOPT_REQ_UUID },
181 { "-uuid", 'u', RTGETOPT_REQ_UUID },
182 { "--register", 'r', RTGETOPT_REQ_NOTHING },
183 { "-register", 'r', RTGETOPT_REQ_NOTHING },
184};
185
186int handleCreateVM(HandlerArg *a)
187{
188 HRESULT rc;
189 Bstr bstrBaseFolder;
190 Bstr bstrName;
191 Bstr bstrOsTypeId;
192 Bstr bstrUuid;
193 bool fRegister = false;
194 com::SafeArray<BSTR> groups;
195
196 int c;
197 RTGETOPTUNION ValueUnion;
198 RTGETOPTSTATE GetState;
199 // start at 0 because main() has hacked both the argc and argv given to us
200 RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateVMOptions, RT_ELEMENTS(g_aCreateVMOptions),
201 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
202 while ((c = RTGetOpt(&GetState, &ValueUnion)))
203 {
204 switch (c)
205 {
206 case 'n': // --name
207 bstrName = ValueUnion.psz;
208 break;
209
210 case 'g': // --groups
211 parseGroups(ValueUnion.psz, &groups);
212 break;
213
214 case 'p': // --basefolder
215 bstrBaseFolder = ValueUnion.psz;
216 break;
217
218 case 'o': // --ostype
219 bstrOsTypeId = ValueUnion.psz;
220 break;
221
222 case 'u': // --uuid
223 bstrUuid = Guid(ValueUnion.Uuid).toUtf16().raw();
224 break;
225
226 case 'r': // --register
227 fRegister = true;
228 break;
229
230 default:
231 return errorGetOpt(USAGE_CREATEVM, c, &ValueUnion);
232 }
233 }
234
235 /* check for required options */
236 if (bstrName.isEmpty())
237 return errorSyntax(USAGE_CREATEVM, "Parameter --name is required");
238
239 do
240 {
241 Bstr createFlags;
242 if (!bstrUuid.isEmpty())
243 createFlags = BstrFmt("UUID=%ls", bstrUuid.raw());
244 Bstr bstrPrimaryGroup;
245 if (groups.size())
246 bstrPrimaryGroup = groups[0];
247 Bstr bstrSettingsFile;
248 CHECK_ERROR_BREAK(a->virtualBox,
249 ComposeMachineFilename(bstrName.raw(),
250 bstrPrimaryGroup.raw(),
251 createFlags.raw(),
252 bstrBaseFolder.raw(),
253 bstrSettingsFile.asOutParam()));
254 ComPtr<IMachine> machine;
255 CHECK_ERROR_BREAK(a->virtualBox,
256 CreateMachine(bstrSettingsFile.raw(),
257 bstrName.raw(),
258 ComSafeArrayAsInParam(groups),
259 bstrOsTypeId.raw(),
260 createFlags.raw(),
261 machine.asOutParam()));
262
263 CHECK_ERROR_BREAK(machine, SaveSettings());
264 if (fRegister)
265 {
266 CHECK_ERROR_BREAK(a->virtualBox, RegisterMachine(machine));
267 }
268 Bstr uuid;
269 CHECK_ERROR_BREAK(machine, COMGETTER(Id)(uuid.asOutParam()));
270 Bstr settingsFile;
271 CHECK_ERROR_BREAK(machine, COMGETTER(SettingsFilePath)(settingsFile.asOutParam()));
272 RTPrintf("Virtual machine '%ls' is created%s.\n"
273 "UUID: %s\n"
274 "Settings file: '%ls'\n",
275 bstrName.raw(), fRegister ? " and registered" : "",
276 Utf8Str(uuid).c_str(), settingsFile.raw());
277 }
278 while (0);
279
280 return SUCCEEDED(rc) ? 0 : 1;
281}
282
283static const RTGETOPTDEF g_aCloneVMOptions[] =
284{
285 { "--snapshot", 's', RTGETOPT_REQ_STRING },
286 { "--name", 'n', RTGETOPT_REQ_STRING },
287 { "--groups", 'g', RTGETOPT_REQ_STRING },
288 { "--mode", 'm', RTGETOPT_REQ_STRING },
289 { "--options", 'o', RTGETOPT_REQ_STRING },
290 { "--register", 'r', RTGETOPT_REQ_NOTHING },
291 { "--basefolder", 'p', RTGETOPT_REQ_STRING },
292 { "--uuid", 'u', RTGETOPT_REQ_UUID },
293};
294
295static int parseCloneMode(const char *psz, CloneMode_T *pMode)
296{
297 if (!RTStrICmp(psz, "machine"))
298 *pMode = CloneMode_MachineState;
299 else if (!RTStrICmp(psz, "machineandchildren"))
300 *pMode = CloneMode_MachineAndChildStates;
301 else if (!RTStrICmp(psz, "all"))
302 *pMode = CloneMode_AllStates;
303 else
304 return VERR_PARSE_ERROR;
305
306 return VINF_SUCCESS;
307}
308
309static int parseCloneOptions(const char *psz, com::SafeArray<CloneOptions_T> *options)
310{
311 int rc = VINF_SUCCESS;
312 while (psz && *psz && RT_SUCCESS(rc))
313 {
314 size_t len;
315 const char *pszComma = strchr(psz, ',');
316 if (pszComma)
317 len = pszComma - psz;
318 else
319 len = strlen(psz);
320 if (len > 0)
321 {
322 if (!RTStrNICmp(psz, "KeepAllMACs", len))
323 options->push_back(CloneOptions_KeepAllMACs);
324 else if (!RTStrNICmp(psz, "KeepNATMACs", len))
325 options->push_back(CloneOptions_KeepNATMACs);
326 else if (!RTStrNICmp(psz, "KeepDiskNames", len))
327 options->push_back(CloneOptions_KeepDiskNames);
328 else if ( !RTStrNICmp(psz, "Link", len)
329 || !RTStrNICmp(psz, "Linked", len))
330 options->push_back(CloneOptions_Link);
331 else
332 rc = VERR_PARSE_ERROR;
333 }
334 if (pszComma)
335 psz += len + 1;
336 else
337 psz += len;
338 }
339
340 return rc;
341}
342
343int handleCloneVM(HandlerArg *a)
344{
345 HRESULT rc;
346 const char *pszSrcName = NULL;
347 const char *pszSnapshotName = NULL;
348 CloneMode_T mode = CloneMode_MachineState;
349 com::SafeArray<CloneOptions_T> options;
350 const char *pszTrgName = NULL;
351 const char *pszTrgBaseFolder = NULL;
352 bool fRegister = false;
353 Bstr bstrUuid;
354 com::SafeArray<BSTR> groups;
355
356 int c;
357 RTGETOPTUNION ValueUnion;
358 RTGETOPTSTATE GetState;
359 // start at 0 because main() has hacked both the argc and argv given to us
360 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneVMOptions, RT_ELEMENTS(g_aCloneVMOptions),
361 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
362 while ((c = RTGetOpt(&GetState, &ValueUnion)))
363 {
364 switch (c)
365 {
366 case 's': // --snapshot
367 pszSnapshotName = ValueUnion.psz;
368 break;
369
370 case 'n': // --name
371 pszTrgName = ValueUnion.psz;
372 break;
373
374 case 'g': // --groups
375 parseGroups(ValueUnion.psz, &groups);
376 break;
377
378 case 'p': // --basefolder
379 pszTrgBaseFolder = ValueUnion.psz;
380 break;
381
382 case 'm': // --mode
383 if (RT_FAILURE(parseCloneMode(ValueUnion.psz, &mode)))
384 return errorArgument("Invalid clone mode '%s'\n", ValueUnion.psz);
385 break;
386
387 case 'o': // --options
388 if (RT_FAILURE(parseCloneOptions(ValueUnion.psz, &options)))
389 return errorArgument("Invalid clone options '%s'\n", ValueUnion.psz);
390 break;
391
392 case 'u': // --uuid
393 bstrUuid = Guid(ValueUnion.Uuid).toUtf16().raw();
394 break;
395
396 case 'r': // --register
397 fRegister = true;
398 break;
399
400 case VINF_GETOPT_NOT_OPTION:
401 if (!pszSrcName)
402 pszSrcName = ValueUnion.psz;
403 else
404 return errorSyntax(USAGE_CLONEVM, "Invalid parameter '%s'", ValueUnion.psz);
405 break;
406
407 default:
408 return errorGetOpt(USAGE_CLONEVM, c, &ValueUnion);
409 }
410 }
411
412 /* Check for required options */
413 if (!pszSrcName)
414 return errorSyntax(USAGE_CLONEVM, "VM name required");
415
416 /* Get the machine object */
417 ComPtr<IMachine> srcMachine;
418 CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(pszSrcName).raw(),
419 srcMachine.asOutParam()),
420 RTEXITCODE_FAILURE);
421
422 /* If a snapshot name/uuid was given, get the particular machine of this
423 * snapshot. */
424 if (pszSnapshotName)
425 {
426 ComPtr<ISnapshot> srcSnapshot;
427 CHECK_ERROR_RET(srcMachine, FindSnapshot(Bstr(pszSnapshotName).raw(),
428 srcSnapshot.asOutParam()),
429 RTEXITCODE_FAILURE);
430 CHECK_ERROR_RET(srcSnapshot, COMGETTER(Machine)(srcMachine.asOutParam()),
431 RTEXITCODE_FAILURE);
432 }
433
434 /* Default name necessary? */
435 if (!pszTrgName)
436 pszTrgName = RTStrAPrintf2("%s Clone", pszSrcName);
437
438 Bstr createFlags;
439 if (!bstrUuid.isEmpty())
440 createFlags = BstrFmt("UUID=%ls", bstrUuid.raw());
441 Bstr bstrPrimaryGroup;
442 if (groups.size())
443 bstrPrimaryGroup = groups[0];
444 Bstr bstrSettingsFile;
445 CHECK_ERROR_RET(a->virtualBox,
446 ComposeMachineFilename(Bstr(pszTrgName).raw(),
447 bstrPrimaryGroup.raw(),
448 createFlags.raw(),
449 Bstr(pszTrgBaseFolder).raw(),
450 bstrSettingsFile.asOutParam()),
451 RTEXITCODE_FAILURE);
452
453 ComPtr<IMachine> trgMachine;
454 CHECK_ERROR_RET(a->virtualBox, CreateMachine(bstrSettingsFile.raw(),
455 Bstr(pszTrgName).raw(),
456 ComSafeArrayAsInParam(groups),
457 NULL,
458 createFlags.raw(),
459 trgMachine.asOutParam()),
460 RTEXITCODE_FAILURE);
461
462 /* Start the cloning */
463 ComPtr<IProgress> progress;
464 CHECK_ERROR_RET(srcMachine, CloneTo(trgMachine,
465 mode,
466 ComSafeArrayAsInParam(options),
467 progress.asOutParam()),
468 RTEXITCODE_FAILURE);
469 rc = showProgress(progress);
470 CHECK_PROGRESS_ERROR_RET(progress, ("Clone VM failed"), RTEXITCODE_FAILURE);
471
472 if (fRegister)
473 CHECK_ERROR_RET(a->virtualBox, RegisterMachine(trgMachine), RTEXITCODE_FAILURE);
474
475 Bstr bstrNewName;
476 CHECK_ERROR_RET(trgMachine, COMGETTER(Name)(bstrNewName.asOutParam()), RTEXITCODE_FAILURE);
477 RTPrintf("Machine has been successfully cloned as \"%ls\"\n", bstrNewName.raw());
478
479 return RTEXITCODE_SUCCESS;
480}
481
482int handleStartVM(HandlerArg *a)
483{
484 HRESULT rc = S_OK;
485 std::list<const char *> VMs;
486 Bstr sessionType;
487
488 static const RTGETOPTDEF s_aStartVMOptions[] =
489 {
490 { "--type", 't', RTGETOPT_REQ_STRING },
491 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
492 };
493 int c;
494 RTGETOPTUNION ValueUnion;
495 RTGETOPTSTATE GetState;
496 // start at 0 because main() has hacked both the argc and argv given to us
497 RTGetOptInit(&GetState, a->argc, a->argv, s_aStartVMOptions, RT_ELEMENTS(s_aStartVMOptions),
498 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
499 while ((c = RTGetOpt(&GetState, &ValueUnion)))
500 {
501 switch (c)
502 {
503 case 't': // --type
504 if (!RTStrICmp(ValueUnion.psz, "gui"))
505 {
506 sessionType = "gui";
507 }
508#ifdef VBOX_WITH_VBOXSDL
509 else if (!RTStrICmp(ValueUnion.psz, "sdl"))
510 {
511 sessionType = "sdl";
512 }
513#endif
514#ifdef VBOX_WITH_HEADLESS
515 else if (!RTStrICmp(ValueUnion.psz, "capture"))
516 {
517 sessionType = "capture";
518 }
519 else if (!RTStrICmp(ValueUnion.psz, "headless"))
520 {
521 sessionType = "headless";
522 }
523#endif
524 else
525 sessionType = ValueUnion.psz;
526 break;
527
528 case VINF_GETOPT_NOT_OPTION:
529 VMs.push_back(ValueUnion.psz);
530 break;
531
532 default:
533 if (c > 0)
534 {
535 if (RT_C_IS_PRINT(c))
536 return errorSyntax(USAGE_STARTVM, "Invalid option -%c", c);
537 else
538 return errorSyntax(USAGE_STARTVM, "Invalid option case %i", c);
539 }
540 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
541 return errorSyntax(USAGE_STARTVM, "unknown option: %s\n", ValueUnion.psz);
542 else if (ValueUnion.pDef)
543 return errorSyntax(USAGE_STARTVM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
544 else
545 return errorSyntax(USAGE_STARTVM, "error: %Rrs", c);
546 }
547 }
548
549 /* check for required options */
550 if (VMs.empty())
551 return errorSyntax(USAGE_STARTVM, "at least one VM name or uuid required");
552
553 for (std::list<const char *>::const_iterator it = VMs.begin();
554 it != VMs.end();
555 ++it)
556 {
557 HRESULT rc2 = rc;
558 const char *pszVM = *it;
559 ComPtr<IMachine> machine;
560 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(pszVM).raw(),
561 machine.asOutParam()));
562 if (machine)
563 {
564 Bstr env;
565#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
566 /* make sure the VM process will start on the same display as VBoxManage */
567 Utf8Str str;
568 const char *pszDisplay = RTEnvGet("DISPLAY");
569 if (pszDisplay)
570 str = Utf8StrFmt("DISPLAY=%s\n", pszDisplay);
571 const char *pszXAuth = RTEnvGet("XAUTHORITY");
572 if (pszXAuth)
573 str.append(Utf8StrFmt("XAUTHORITY=%s\n", pszXAuth));
574 env = str;
575#endif
576 ComPtr<IProgress> progress;
577 CHECK_ERROR(machine, LaunchVMProcess(a->session, sessionType.raw(),
578 env.raw(), progress.asOutParam()));
579 if (SUCCEEDED(rc) && !progress.isNull())
580 {
581 RTPrintf("Waiting for VM \"%s\" to power on...\n", pszVM);
582 CHECK_ERROR(progress, WaitForCompletion(-1));
583 if (SUCCEEDED(rc))
584 {
585 BOOL completed = true;
586 CHECK_ERROR(progress, COMGETTER(Completed)(&completed));
587 if (SUCCEEDED(rc))
588 {
589 ASSERT(completed);
590
591 LONG iRc;
592 CHECK_ERROR(progress, COMGETTER(ResultCode)(&iRc));
593 if (SUCCEEDED(rc))
594 {
595 if (FAILED(iRc))
596 {
597 ProgressErrorInfo info(progress);
598 com::GluePrintErrorInfo(info);
599 }
600 else
601 {
602 RTPrintf("VM \"%s\" has been successfully started.\n", pszVM);
603 }
604 }
605 }
606 }
607 }
608 }
609
610 /* it's important to always close sessions */
611 a->session->UnlockMachine();
612
613 /* make sure that we remember the failed state */
614 if (FAILED(rc2))
615 rc = rc2;
616 }
617
618 return SUCCEEDED(rc) ? 0 : 1;
619}
620
621int handleDiscardState(HandlerArg *a)
622{
623 HRESULT rc;
624
625 if (a->argc != 1)
626 return errorSyntax(USAGE_DISCARDSTATE, "Incorrect number of parameters");
627
628 ComPtr<IMachine> machine;
629 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
630 machine.asOutParam()));
631 if (machine)
632 {
633 do
634 {
635 /* we have to open a session for this task */
636 CHECK_ERROR_BREAK(machine, LockMachine(a->session, LockType_Write));
637 do
638 {
639 ComPtr<IConsole> console;
640 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
641 CHECK_ERROR_BREAK(console, DiscardSavedState(true /* fDeleteFile */));
642 } while (0);
643 CHECK_ERROR_BREAK(a->session, UnlockMachine());
644 } while (0);
645 }
646
647 return SUCCEEDED(rc) ? 0 : 1;
648}
649
650int handleAdoptState(HandlerArg *a)
651{
652 HRESULT rc;
653
654 if (a->argc != 2)
655 return errorSyntax(USAGE_ADOPTSTATE, "Incorrect number of parameters");
656
657 ComPtr<IMachine> machine;
658 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
659 machine.asOutParam()));
660 if (machine)
661 {
662 char szStateFileAbs[RTPATH_MAX] = "";
663 int vrc = RTPathAbs(a->argv[1], szStateFileAbs, sizeof(szStateFileAbs));
664 if (RT_FAILURE(vrc))
665 {
666 RTMsgError("Cannot convert filename \"%s\" to absolute path", a->argv[0]);
667 return 1;
668 }
669
670 do
671 {
672 /* we have to open a session for this task */
673 CHECK_ERROR_BREAK(machine, LockMachine(a->session, LockType_Write));
674 do
675 {
676 ComPtr<IConsole> console;
677 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
678 CHECK_ERROR_BREAK(console, AdoptSavedState(Bstr(szStateFileAbs).raw()));
679 } while (0);
680 CHECK_ERROR_BREAK(a->session, UnlockMachine());
681 } while (0);
682 }
683
684 return SUCCEEDED(rc) ? 0 : 1;
685}
686
687int handleGetExtraData(HandlerArg *a)
688{
689 HRESULT rc = S_OK;
690
691 if (a->argc != 2)
692 return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");
693
694 /* global data? */
695 if (!strcmp(a->argv[0], "global"))
696 {
697 /* enumeration? */
698 if (!strcmp(a->argv[1], "enumerate"))
699 {
700 SafeArray<BSTR> aKeys;
701 CHECK_ERROR(a->virtualBox, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
702
703 for (size_t i = 0;
704 i < aKeys.size();
705 ++i)
706 {
707 Bstr bstrKey(aKeys[i]);
708 Bstr bstrValue;
709 CHECK_ERROR(a->virtualBox, GetExtraData(bstrKey.raw(),
710 bstrValue.asOutParam()));
711
712 RTPrintf("Key: %ls, Value: %ls\n", bstrKey.raw(), bstrValue.raw());
713 }
714 }
715 else
716 {
717 Bstr value;
718 CHECK_ERROR(a->virtualBox, GetExtraData(Bstr(a->argv[1]).raw(),
719 value.asOutParam()));
720 if (!value.isEmpty())
721 RTPrintf("Value: %ls\n", value.raw());
722 else
723 RTPrintf("No value set!\n");
724 }
725 }
726 else
727 {
728 ComPtr<IMachine> machine;
729 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
730 machine.asOutParam()));
731 if (machine)
732 {
733 /* enumeration? */
734 if (!strcmp(a->argv[1], "enumerate"))
735 {
736 SafeArray<BSTR> aKeys;
737 CHECK_ERROR(machine, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
738
739 for (size_t i = 0;
740 i < aKeys.size();
741 ++i)
742 {
743 Bstr bstrKey(aKeys[i]);
744 Bstr bstrValue;
745 CHECK_ERROR(machine, GetExtraData(bstrKey.raw(),
746 bstrValue.asOutParam()));
747
748 RTPrintf("Key: %ls, Value: %ls\n", bstrKey.raw(), bstrValue.raw());
749 }
750 }
751 else
752 {
753 Bstr value;
754 CHECK_ERROR(machine, GetExtraData(Bstr(a->argv[1]).raw(),
755 value.asOutParam()));
756 if (!value.isEmpty())
757 RTPrintf("Value: %ls\n", value.raw());
758 else
759 RTPrintf("No value set!\n");
760 }
761 }
762 }
763 return SUCCEEDED(rc) ? 0 : 1;
764}
765
766int handleSetExtraData(HandlerArg *a)
767{
768 HRESULT rc = S_OK;
769
770 if (a->argc < 2)
771 return errorSyntax(USAGE_SETEXTRADATA, "Not enough parameters");
772
773 /* global data? */
774 if (!strcmp(a->argv[0], "global"))
775 {
776 /** @todo passing NULL is deprecated */
777 if (a->argc < 3)
778 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]).raw(),
779 NULL));
780 else if (a->argc == 3)
781 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]).raw(),
782 Bstr(a->argv[2]).raw()));
783 else
784 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
785 }
786 else
787 {
788 ComPtr<IMachine> machine;
789 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
790 machine.asOutParam()));
791 if (machine)
792 {
793 /** @todo passing NULL is deprecated */
794 if (a->argc < 3)
795 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]).raw(),
796 NULL));
797 else if (a->argc == 3)
798 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]).raw(),
799 Bstr(a->argv[2]).raw()));
800 else
801 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
802 }
803 }
804 return SUCCEEDED(rc) ? 0 : 1;
805}
806
807int handleSetProperty(HandlerArg *a)
808{
809 HRESULT rc;
810
811 /* there must be two arguments: property name and value */
812 if (a->argc != 2)
813 return errorSyntax(USAGE_SETPROPERTY, "Incorrect number of parameters");
814
815 ComPtr<ISystemProperties> systemProperties;
816 a->virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
817
818 if (!strcmp(a->argv[0], "machinefolder"))
819 {
820 /* reset to default? */
821 if (!strcmp(a->argv[1], "default"))
822 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(NULL));
823 else
824 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(Bstr(a->argv[1]).raw()));
825 }
826 else if (!strcmp(a->argv[0], "hwvirtexclusive"))
827 {
828 bool fHwVirtExclusive;
829
830 if (!strcmp(a->argv[1], "on"))
831 fHwVirtExclusive = true;
832 else if (!strcmp(a->argv[1], "off"))
833 fHwVirtExclusive = false;
834 else
835 return errorArgument("Invalid hwvirtexclusive argument '%s'", a->argv[1]);
836 CHECK_ERROR(systemProperties, COMSETTER(ExclusiveHwVirt)(fHwVirtExclusive));
837 }
838 else if ( !strcmp(a->argv[0], "vrdeauthlibrary")
839 || !strcmp(a->argv[0], "vrdpauthlibrary"))
840 {
841 if (!strcmp(a->argv[0], "vrdpauthlibrary"))
842 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpauthlibrary' is deprecated. Use 'vrdeauthlibrary'.\n");
843
844 /* reset to default? */
845 if (!strcmp(a->argv[1], "default"))
846 CHECK_ERROR(systemProperties, COMSETTER(VRDEAuthLibrary)(NULL));
847 else
848 CHECK_ERROR(systemProperties, COMSETTER(VRDEAuthLibrary)(Bstr(a->argv[1]).raw()));
849 }
850 else if (!strcmp(a->argv[0], "websrvauthlibrary"))
851 {
852 /* reset to default? */
853 if (!strcmp(a->argv[1], "default"))
854 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(NULL));
855 else
856 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(Bstr(a->argv[1]).raw()));
857 }
858 else if (!strcmp(a->argv[0], "vrdeextpack"))
859 {
860 /* disable? */
861 if (!strcmp(a->argv[1], "null"))
862 CHECK_ERROR(systemProperties, COMSETTER(DefaultVRDEExtPack)(NULL));
863 else
864 CHECK_ERROR(systemProperties, COMSETTER(DefaultVRDEExtPack)(Bstr(a->argv[1]).raw()));
865 }
866 else if (!strcmp(a->argv[0], "loghistorycount"))
867 {
868 uint32_t uVal;
869 int vrc;
870 vrc = RTStrToUInt32Ex(a->argv[1], NULL, 0, &uVal);
871 if (vrc != VINF_SUCCESS)
872 return errorArgument("Error parsing Log history count '%s'", a->argv[1]);
873 CHECK_ERROR(systemProperties, COMSETTER(LogHistoryCount)(uVal));
874 }
875 else if (!strcmp(a->argv[0], "autostartdbpath"))
876 {
877 /* disable? */
878 if (!strcmp(a->argv[1], "null"))
879 CHECK_ERROR(systemProperties, COMSETTER(AutostartDatabasePath)(NULL));
880 else
881 CHECK_ERROR(systemProperties, COMSETTER(AutostartDatabasePath)(Bstr(a->argv[1]).raw()));
882 }
883 else if (!strcmp(a->argv[0], "defaultfrontend"))
884 {
885 Bstr bstrDefaultFrontend(a->argv[1]);
886 if (!strcmp(a->argv[1], "default"))
887 bstrDefaultFrontend.setNull();
888 CHECK_ERROR(systemProperties, COMSETTER(DefaultFrontend)(bstrDefaultFrontend.raw()));
889 }
890 else
891 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", a->argv[0]);
892
893 return SUCCEEDED(rc) ? 0 : 1;
894}
895
896int handleSharedFolder(HandlerArg *a)
897{
898 HRESULT rc;
899
900 /* we need at least a command and target */
901 if (a->argc < 2)
902 return errorSyntax(USAGE_SHAREDFOLDER, "Not enough parameters");
903
904 ComPtr<IMachine> machine;
905 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[1]).raw(),
906 machine.asOutParam()));
907 if (!machine)
908 return 1;
909
910 if (!strcmp(a->argv[0], "add"))
911 {
912 /* we need at least four more parameters */
913 if (a->argc < 5)
914 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Not enough parameters");
915
916 char *name = NULL;
917 char *hostpath = NULL;
918 bool fTransient = false;
919 bool fWritable = true;
920 bool fAutoMount = false;
921
922 for (int i = 2; i < a->argc; i++)
923 {
924 if ( !strcmp(a->argv[i], "--name")
925 || !strcmp(a->argv[i], "-name"))
926 {
927 if (a->argc <= i + 1 || !*a->argv[i+1])
928 return errorArgument("Missing argument to '%s'", a->argv[i]);
929 i++;
930 name = a->argv[i];
931 }
932 else if ( !strcmp(a->argv[i], "--hostpath")
933 || !strcmp(a->argv[i], "-hostpath"))
934 {
935 if (a->argc <= i + 1 || !*a->argv[i+1])
936 return errorArgument("Missing argument to '%s'", a->argv[i]);
937 i++;
938 hostpath = a->argv[i];
939 }
940 else if ( !strcmp(a->argv[i], "--readonly")
941 || !strcmp(a->argv[i], "-readonly"))
942 {
943 fWritable = false;
944 }
945 else if ( !strcmp(a->argv[i], "--transient")
946 || !strcmp(a->argv[i], "-transient"))
947 {
948 fTransient = true;
949 }
950 else if ( !strcmp(a->argv[i], "--automount")
951 || !strcmp(a->argv[i], "-automount"))
952 {
953 fAutoMount = true;
954 }
955 else
956 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
957 }
958
959 if (NULL != strstr(name, " "))
960 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "No spaces allowed in parameter '-name'!");
961
962 /* required arguments */
963 if (!name || !hostpath)
964 {
965 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Parameters --name and --hostpath are required");
966 }
967
968 if (fTransient)
969 {
970 ComPtr<IConsole> console;
971
972 /* open an existing session for the VM */
973 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
974 /* get the session machine */
975 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
976 /* get the session console */
977 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
978
979 CHECK_ERROR(console, CreateSharedFolder(Bstr(name).raw(),
980 Bstr(hostpath).raw(),
981 fWritable, fAutoMount));
982 if (console)
983 a->session->UnlockMachine();
984 }
985 else
986 {
987 /* open a session for the VM */
988 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), 1);
989
990 /* get the mutable session machine */
991 a->session->COMGETTER(Machine)(machine.asOutParam());
992
993 CHECK_ERROR(machine, CreateSharedFolder(Bstr(name).raw(),
994 Bstr(hostpath).raw(),
995 fWritable, fAutoMount));
996 if (SUCCEEDED(rc))
997 CHECK_ERROR(machine, SaveSettings());
998
999 a->session->UnlockMachine();
1000 }
1001 }
1002 else if (!strcmp(a->argv[0], "remove"))
1003 {
1004 /* we need at least two more parameters */
1005 if (a->argc < 3)
1006 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Not enough parameters");
1007
1008 char *name = NULL;
1009 bool fTransient = false;
1010
1011 for (int i = 2; i < a->argc; i++)
1012 {
1013 if ( !strcmp(a->argv[i], "--name")
1014 || !strcmp(a->argv[i], "-name"))
1015 {
1016 if (a->argc <= i + 1 || !*a->argv[i+1])
1017 return errorArgument("Missing argument to '%s'", a->argv[i]);
1018 i++;
1019 name = a->argv[i];
1020 }
1021 else if ( !strcmp(a->argv[i], "--transient")
1022 || !strcmp(a->argv[i], "-transient"))
1023 {
1024 fTransient = true;
1025 }
1026 else
1027 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
1028 }
1029
1030 /* required arguments */
1031 if (!name)
1032 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Parameter --name is required");
1033
1034 if (fTransient)
1035 {
1036 ComPtr<IConsole> console;
1037
1038 /* open an existing session for the VM */
1039 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
1040 /* get the session machine */
1041 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
1042 /* get the session console */
1043 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
1044
1045 CHECK_ERROR(console, RemoveSharedFolder(Bstr(name).raw()));
1046
1047 if (console)
1048 a->session->UnlockMachine();
1049 }
1050 else
1051 {
1052 /* open a session for the VM */
1053 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), 1);
1054
1055 /* get the mutable session machine */
1056 a->session->COMGETTER(Machine)(machine.asOutParam());
1057
1058 CHECK_ERROR(machine, RemoveSharedFolder(Bstr(name).raw()));
1059
1060 /* commit and close the session */
1061 CHECK_ERROR(machine, SaveSettings());
1062 a->session->UnlockMachine();
1063 }
1064 }
1065 else
1066 return errorSyntax(USAGE_SHAREDFOLDER, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
1067
1068 return 0;
1069}
1070
1071int handleExtPack(HandlerArg *a)
1072{
1073 if (a->argc < 1)
1074 return errorSyntax(USAGE_EXTPACK, "Incorrect number of parameters");
1075
1076 ComObjPtr<IExtPackManager> ptrExtPackMgr;
1077 CHECK_ERROR2_RET(a->virtualBox, COMGETTER(ExtensionPackManager)(ptrExtPackMgr.asOutParam()), RTEXITCODE_FAILURE);
1078
1079 RTGETOPTSTATE GetState;
1080 RTGETOPTUNION ValueUnion;
1081 int ch;
1082 HRESULT hrc = S_OK;
1083
1084 if (!strcmp(a->argv[0], "install"))
1085 {
1086 const char *pszName = NULL;
1087 bool fReplace = false;
1088
1089 static const RTGETOPTDEF s_aInstallOptions[] =
1090 {
1091 { "--replace", 'r', RTGETOPT_REQ_NOTHING },
1092 };
1093
1094 RTGetOptInit(&GetState, a->argc, a->argv, s_aInstallOptions, RT_ELEMENTS(s_aInstallOptions), 1, 0 /*fFlags*/);
1095 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1096 {
1097 switch (ch)
1098 {
1099 case 'r':
1100 fReplace = true;
1101 break;
1102
1103 case VINF_GETOPT_NOT_OPTION:
1104 if (pszName)
1105 return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
1106 pszName = ValueUnion.psz;
1107 break;
1108
1109 default:
1110 return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
1111 }
1112 }
1113 if (!pszName)
1114 return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack install\"");
1115
1116 char szPath[RTPATH_MAX];
1117 int vrc = RTPathAbs(pszName, szPath, sizeof(szPath));
1118 if (RT_FAILURE(vrc))
1119 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs(%s,,) failed with rc=%Rrc", pszName, vrc);
1120
1121 Bstr bstrTarball(szPath);
1122 Bstr bstrName;
1123 ComPtr<IExtPackFile> ptrExtPackFile;
1124 CHECK_ERROR2_RET(ptrExtPackMgr, OpenExtPackFile(bstrTarball.raw(), ptrExtPackFile.asOutParam()), RTEXITCODE_FAILURE);
1125 CHECK_ERROR2_RET(ptrExtPackFile, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
1126 ComPtr<IProgress> ptrProgress;
1127 CHECK_ERROR2_RET(ptrExtPackFile, Install(fReplace, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
1128 hrc = showProgress(ptrProgress);
1129 CHECK_PROGRESS_ERROR_RET(ptrProgress, ("Failed to install \"%s\"", szPath), RTEXITCODE_FAILURE);
1130
1131 RTPrintf("Successfully installed \"%ls\".\n", bstrName.raw());
1132 }
1133 else if (!strcmp(a->argv[0], "uninstall"))
1134 {
1135 const char *pszName = NULL;
1136 bool fForced = false;
1137
1138 static const RTGETOPTDEF s_aUninstallOptions[] =
1139 {
1140 { "--force", 'f', RTGETOPT_REQ_NOTHING },
1141 };
1142
1143 RTGetOptInit(&GetState, a->argc, a->argv, s_aUninstallOptions, RT_ELEMENTS(s_aUninstallOptions), 1, 0);
1144 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1145 {
1146 switch (ch)
1147 {
1148 case 'f':
1149 fForced = true;
1150 break;
1151
1152 case VINF_GETOPT_NOT_OPTION:
1153 if (pszName)
1154 return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
1155 pszName = ValueUnion.psz;
1156 break;
1157
1158 default:
1159 return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
1160 }
1161 }
1162 if (!pszName)
1163 return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack uninstall\"");
1164
1165 Bstr bstrName(pszName);
1166 ComPtr<IProgress> ptrProgress;
1167 CHECK_ERROR2_RET(ptrExtPackMgr, Uninstall(bstrName.raw(), fForced, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
1168 hrc = showProgress(ptrProgress);
1169 CHECK_PROGRESS_ERROR_RET(ptrProgress, ("Failed to uninstall \"%s\"", pszName), RTEXITCODE_FAILURE);
1170
1171 RTPrintf("Successfully uninstalled \"%s\".\n", pszName);
1172 }
1173 else if (!strcmp(a->argv[0], "cleanup"))
1174 {
1175 if (a->argc > 1)
1176 return errorSyntax(USAGE_EXTPACK, "Too many parameters given to \"extpack cleanup\"");
1177
1178 CHECK_ERROR2_RET(ptrExtPackMgr, Cleanup(), RTEXITCODE_FAILURE);
1179 RTPrintf("Successfully performed extension pack cleanup\n");
1180 }
1181 else
1182 return errorSyntax(USAGE_EXTPACK, "Unknown command \"%s\"", a->argv[0]);
1183
1184 return RTEXITCODE_SUCCESS;
1185}
1186
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