VirtualBox

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

Last change on this file since 46658 was 46658, checked in by vboxsync, 11 years ago

include VBox/com/EventQueue only if necessary

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.8 KB
Line 
1/* $Id: VBoxManageMisc.cpp 46658 2013-06-19 13:21:08Z 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], "vrdeauthlibrary")
827 || !strcmp(a->argv[0], "vrdpauthlibrary"))
828 {
829 if (!strcmp(a->argv[0], "vrdpauthlibrary"))
830 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpauthlibrary' is deprecated. Use 'vrdeauthlibrary'.\n");
831
832 /* reset to default? */
833 if (!strcmp(a->argv[1], "default"))
834 CHECK_ERROR(systemProperties, COMSETTER(VRDEAuthLibrary)(NULL));
835 else
836 CHECK_ERROR(systemProperties, COMSETTER(VRDEAuthLibrary)(Bstr(a->argv[1]).raw()));
837 }
838 else if (!strcmp(a->argv[0], "websrvauthlibrary"))
839 {
840 /* reset to default? */
841 if (!strcmp(a->argv[1], "default"))
842 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(NULL));
843 else
844 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(Bstr(a->argv[1]).raw()));
845 }
846 else if (!strcmp(a->argv[0], "vrdeextpack"))
847 {
848 /* disable? */
849 if (!strcmp(a->argv[1], "null"))
850 CHECK_ERROR(systemProperties, COMSETTER(DefaultVRDEExtPack)(NULL));
851 else
852 CHECK_ERROR(systemProperties, COMSETTER(DefaultVRDEExtPack)(Bstr(a->argv[1]).raw()));
853 }
854 else if (!strcmp(a->argv[0], "loghistorycount"))
855 {
856 uint32_t uVal;
857 int vrc;
858 vrc = RTStrToUInt32Ex(a->argv[1], NULL, 0, &uVal);
859 if (vrc != VINF_SUCCESS)
860 return errorArgument("Error parsing Log history count '%s'", a->argv[1]);
861 CHECK_ERROR(systemProperties, COMSETTER(LogHistoryCount)(uVal));
862 }
863 else if (!strcmp(a->argv[0], "autostartdbpath"))
864 {
865 /* disable? */
866 if (!strcmp(a->argv[1], "null"))
867 CHECK_ERROR(systemProperties, COMSETTER(AutostartDatabasePath)(NULL));
868 else
869 CHECK_ERROR(systemProperties, COMSETTER(AutostartDatabasePath)(Bstr(a->argv[1]).raw()));
870 }
871 else if (!strcmp(a->argv[0], "defaultfrontend"))
872 {
873 Bstr bstrDefaultFrontend(a->argv[1]);
874 if (!strcmp(a->argv[1], "default"))
875 bstrDefaultFrontend.setNull();
876 CHECK_ERROR(systemProperties, COMSETTER(DefaultFrontend)(bstrDefaultFrontend.raw()));
877 }
878 else
879 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", a->argv[0]);
880
881 return SUCCEEDED(rc) ? 0 : 1;
882}
883
884int handleSharedFolder(HandlerArg *a)
885{
886 HRESULT rc;
887
888 /* we need at least a command and target */
889 if (a->argc < 2)
890 return errorSyntax(USAGE_SHAREDFOLDER, "Not enough parameters");
891
892 ComPtr<IMachine> machine;
893 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[1]).raw(),
894 machine.asOutParam()));
895 if (!machine)
896 return 1;
897
898 if (!strcmp(a->argv[0], "add"))
899 {
900 /* we need at least four more parameters */
901 if (a->argc < 5)
902 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Not enough parameters");
903
904 char *name = NULL;
905 char *hostpath = NULL;
906 bool fTransient = false;
907 bool fWritable = true;
908 bool fAutoMount = false;
909
910 for (int i = 2; i < a->argc; i++)
911 {
912 if ( !strcmp(a->argv[i], "--name")
913 || !strcmp(a->argv[i], "-name"))
914 {
915 if (a->argc <= i + 1 || !*a->argv[i+1])
916 return errorArgument("Missing argument to '%s'", a->argv[i]);
917 i++;
918 name = a->argv[i];
919 }
920 else if ( !strcmp(a->argv[i], "--hostpath")
921 || !strcmp(a->argv[i], "-hostpath"))
922 {
923 if (a->argc <= i + 1 || !*a->argv[i+1])
924 return errorArgument("Missing argument to '%s'", a->argv[i]);
925 i++;
926 hostpath = a->argv[i];
927 }
928 else if ( !strcmp(a->argv[i], "--readonly")
929 || !strcmp(a->argv[i], "-readonly"))
930 {
931 fWritable = false;
932 }
933 else if ( !strcmp(a->argv[i], "--transient")
934 || !strcmp(a->argv[i], "-transient"))
935 {
936 fTransient = true;
937 }
938 else if ( !strcmp(a->argv[i], "--automount")
939 || !strcmp(a->argv[i], "-automount"))
940 {
941 fAutoMount = true;
942 }
943 else
944 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
945 }
946
947 if (NULL != strstr(name, " "))
948 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "No spaces allowed in parameter '-name'!");
949
950 /* required arguments */
951 if (!name || !hostpath)
952 {
953 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Parameters --name and --hostpath are required");
954 }
955
956 if (fTransient)
957 {
958 ComPtr <IConsole> console;
959
960 /* open an existing session for the VM */
961 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
962 /* get the session machine */
963 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
964 /* get the session console */
965 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
966
967 CHECK_ERROR(console, CreateSharedFolder(Bstr(name).raw(),
968 Bstr(hostpath).raw(),
969 fWritable, fAutoMount));
970 if (console)
971 a->session->UnlockMachine();
972 }
973 else
974 {
975 /* open a session for the VM */
976 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), 1);
977
978 /* get the mutable session machine */
979 a->session->COMGETTER(Machine)(machine.asOutParam());
980
981 CHECK_ERROR(machine, CreateSharedFolder(Bstr(name).raw(),
982 Bstr(hostpath).raw(),
983 fWritable, fAutoMount));
984 if (SUCCEEDED(rc))
985 CHECK_ERROR(machine, SaveSettings());
986
987 a->session->UnlockMachine();
988 }
989 }
990 else if (!strcmp(a->argv[0], "remove"))
991 {
992 /* we need at least two more parameters */
993 if (a->argc < 3)
994 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Not enough parameters");
995
996 char *name = NULL;
997 bool fTransient = false;
998
999 for (int i = 2; i < a->argc; i++)
1000 {
1001 if ( !strcmp(a->argv[i], "--name")
1002 || !strcmp(a->argv[i], "-name"))
1003 {
1004 if (a->argc <= i + 1 || !*a->argv[i+1])
1005 return errorArgument("Missing argument to '%s'", a->argv[i]);
1006 i++;
1007 name = a->argv[i];
1008 }
1009 else if ( !strcmp(a->argv[i], "--transient")
1010 || !strcmp(a->argv[i], "-transient"))
1011 {
1012 fTransient = true;
1013 }
1014 else
1015 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
1016 }
1017
1018 /* required arguments */
1019 if (!name)
1020 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Parameter --name is required");
1021
1022 if (fTransient)
1023 {
1024 ComPtr <IConsole> console;
1025
1026 /* open an existing session for the VM */
1027 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
1028 /* get the session machine */
1029 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
1030 /* get the session console */
1031 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
1032
1033 CHECK_ERROR(console, RemoveSharedFolder(Bstr(name).raw()));
1034
1035 if (console)
1036 a->session->UnlockMachine();
1037 }
1038 else
1039 {
1040 /* open a session for the VM */
1041 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), 1);
1042
1043 /* get the mutable session machine */
1044 a->session->COMGETTER(Machine)(machine.asOutParam());
1045
1046 CHECK_ERROR(machine, RemoveSharedFolder(Bstr(name).raw()));
1047
1048 /* commit and close the session */
1049 CHECK_ERROR(machine, SaveSettings());
1050 a->session->UnlockMachine();
1051 }
1052 }
1053 else
1054 return errorSyntax(USAGE_SHAREDFOLDER, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
1055
1056 return 0;
1057}
1058
1059int handleExtPack(HandlerArg *a)
1060{
1061 if (a->argc < 1)
1062 return errorSyntax(USAGE_EXTPACK, "Incorrect number of parameters");
1063
1064 ComObjPtr<IExtPackManager> ptrExtPackMgr;
1065 CHECK_ERROR2_RET(a->virtualBox, COMGETTER(ExtensionPackManager)(ptrExtPackMgr.asOutParam()), RTEXITCODE_FAILURE);
1066
1067 RTGETOPTSTATE GetState;
1068 RTGETOPTUNION ValueUnion;
1069 int ch;
1070 HRESULT hrc = S_OK;
1071
1072 if (!strcmp(a->argv[0], "install"))
1073 {
1074 const char *pszName = NULL;
1075 bool fReplace = false;
1076
1077 static const RTGETOPTDEF s_aInstallOptions[] =
1078 {
1079 { "--replace", 'r', RTGETOPT_REQ_NOTHING },
1080 };
1081
1082 RTGetOptInit(&GetState, a->argc, a->argv, s_aInstallOptions, RT_ELEMENTS(s_aInstallOptions), 1, 0 /*fFlags*/);
1083 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1084 {
1085 switch (ch)
1086 {
1087 case 'r':
1088 fReplace = true;
1089 break;
1090
1091 case VINF_GETOPT_NOT_OPTION:
1092 if (pszName)
1093 return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
1094 pszName = ValueUnion.psz;
1095 break;
1096
1097 default:
1098 return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
1099 }
1100 }
1101 if (!pszName)
1102 return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack install\"");
1103
1104 char szPath[RTPATH_MAX];
1105 int vrc = RTPathAbs(pszName, szPath, sizeof(szPath));
1106 if (RT_FAILURE(vrc))
1107 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs(%s,,) failed with rc=%Rrc", pszName, vrc);
1108
1109 Bstr bstrTarball(szPath);
1110 Bstr bstrName;
1111 ComPtr<IExtPackFile> ptrExtPackFile;
1112 CHECK_ERROR2_RET(ptrExtPackMgr, OpenExtPackFile(bstrTarball.raw(), ptrExtPackFile.asOutParam()), RTEXITCODE_FAILURE);
1113 CHECK_ERROR2_RET(ptrExtPackFile, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
1114 ComPtr<IProgress> ptrProgress;
1115 CHECK_ERROR2_RET(ptrExtPackFile, Install(fReplace, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
1116 hrc = showProgress(ptrProgress);
1117 CHECK_PROGRESS_ERROR_RET(ptrProgress, ("Failed to install \"%s\"", szPath), RTEXITCODE_FAILURE);
1118
1119 RTPrintf("Successfully installed \"%ls\".\n", bstrName.raw());
1120 }
1121 else if (!strcmp(a->argv[0], "uninstall"))
1122 {
1123 const char *pszName = NULL;
1124 bool fForced = false;
1125
1126 static const RTGETOPTDEF s_aUninstallOptions[] =
1127 {
1128 { "--force", 'f', RTGETOPT_REQ_NOTHING },
1129 };
1130
1131 RTGetOptInit(&GetState, a->argc, a->argv, s_aUninstallOptions, RT_ELEMENTS(s_aUninstallOptions), 1, 0);
1132 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1133 {
1134 switch (ch)
1135 {
1136 case 'f':
1137 fForced = true;
1138 break;
1139
1140 case VINF_GETOPT_NOT_OPTION:
1141 if (pszName)
1142 return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
1143 pszName = ValueUnion.psz;
1144 break;
1145
1146 default:
1147 return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
1148 }
1149 }
1150 if (!pszName)
1151 return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack uninstall\"");
1152
1153 Bstr bstrName(pszName);
1154 ComPtr<IProgress> ptrProgress;
1155 CHECK_ERROR2_RET(ptrExtPackMgr, Uninstall(bstrName.raw(), fForced, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
1156 hrc = showProgress(ptrProgress);
1157 CHECK_PROGRESS_ERROR_RET(ptrProgress, ("Failed to uninstall \"%s\"", pszName), RTEXITCODE_FAILURE);
1158
1159 RTPrintf("Successfully uninstalled \"%s\".\n", pszName);
1160 }
1161 else if (!strcmp(a->argv[0], "cleanup"))
1162 {
1163 if (a->argc > 1)
1164 return errorSyntax(USAGE_EXTPACK, "Too many parameters given to \"extpack cleanup\"");
1165
1166 CHECK_ERROR2_RET(ptrExtPackMgr, Cleanup(), RTEXITCODE_FAILURE);
1167 RTPrintf("Successfully performed extension pack cleanup\n");
1168 }
1169 else
1170 return errorSyntax(USAGE_EXTPACK, "Unknown command \"%s\"", a->argv[0]);
1171
1172 return RTEXITCODE_SUCCESS;
1173}
1174
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