VirtualBox

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

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

FE/CLI: unregistervm: better error checking; show error on failure

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