VirtualBox

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

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

Frontends/VBoxManage+glue/ErrorInfo: revert change which broke error reporting (4.0.0 regression), clean up on the way

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 31.3 KB
Line 
1/* $Id: VBoxManageMisc.cpp 35517 2011-01-13 10:47:12Z vboxsync $ */
2/** @file
3 * VBoxManage - VirtualBox's command-line interface.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#ifndef VBOX_ONLY_DOCS
23# include <VBox/com/com.h>
24# include <VBox/com/string.h>
25# include <VBox/com/Guid.h>
26# include <VBox/com/array.h>
27# include <VBox/com/ErrorInfo.h>
28# include <VBox/com/errorprint.h>
29# include <VBox/com/EventQueue.h>
30
31# include <VBox/com/VirtualBox.h>
32#endif /* !VBOX_ONLY_DOCS */
33
34#include <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(a->virtualBox, FindMachine(Bstr(VMName).raw(),
153 machine.asOutParam()));
154 if (machine)
155 {
156 SafeIfaceArray<IMedium> aMedia;
157 CleanupMode_T cleanupMode = CleanupMode_DetachAllReturnNone;
158 if (fDelete)
159 cleanupMode = CleanupMode_DetachAllReturnHardDisksOnly;
160 CHECK_ERROR(machine, Unregister(cleanupMode,
161 ComSafeArrayAsOutParam(aMedia)));
162 if (SUCCEEDED(rc))
163 {
164 if (fDelete)
165 {
166 ComPtr<IProgress> pProgress;
167 CHECK_ERROR(machine, Delete(ComSafeArrayAsInParam(aMedia), pProgress.asOutParam()));
168 CHECK_ERROR(pProgress, WaitForCompletion(-1));
169 }
170 }
171 }
172 return SUCCEEDED(rc) ? 0 : 1;
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
269int handleStartVM(HandlerArg *a)
270{
271 HRESULT rc;
272 const char *VMName = NULL;
273 Bstr sessionType = "gui";
274
275 static const RTGETOPTDEF s_aStartVMOptions[] =
276 {
277 { "--type", 't', RTGETOPT_REQ_STRING },
278 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
279 };
280 int c;
281 RTGETOPTUNION ValueUnion;
282 RTGETOPTSTATE GetState;
283 // start at 0 because main() has hacked both the argc and argv given to us
284 RTGetOptInit(&GetState, a->argc, a->argv, s_aStartVMOptions, RT_ELEMENTS(s_aStartVMOptions),
285 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
286 while ((c = RTGetOpt(&GetState, &ValueUnion)))
287 {
288 switch (c)
289 {
290 case 't': // --type
291 if (!RTStrICmp(ValueUnion.psz, "gui"))
292 {
293 sessionType = "gui";
294 }
295#ifdef VBOX_WITH_VBOXSDL
296 else if (!RTStrICmp(ValueUnion.psz, "sdl"))
297 {
298 sessionType = "sdl";
299 }
300#endif
301#ifdef VBOX_WITH_HEADLESS
302 else if (!RTStrICmp(ValueUnion.psz, "capture"))
303 {
304 sessionType = "capture";
305 }
306 else if (!RTStrICmp(ValueUnion.psz, "headless"))
307 {
308 sessionType = "headless";
309 }
310#endif
311 else
312 return errorArgument("Invalid session type '%s'", ValueUnion.psz);
313 break;
314
315 case VINF_GETOPT_NOT_OPTION:
316 if (!VMName)
317 VMName = ValueUnion.psz;
318 else
319 return errorSyntax(USAGE_STARTVM, "Invalid parameter '%s'", ValueUnion.psz);
320 break;
321
322 default:
323 if (c > 0)
324 {
325 if (RT_C_IS_PRINT(c))
326 return errorSyntax(USAGE_STARTVM, "Invalid option -%c", c);
327 else
328 return errorSyntax(USAGE_STARTVM, "Invalid option case %i", c);
329 }
330 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
331 return errorSyntax(USAGE_STARTVM, "unknown option: %s\n", ValueUnion.psz);
332 else if (ValueUnion.pDef)
333 return errorSyntax(USAGE_STARTVM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
334 else
335 return errorSyntax(USAGE_STARTVM, "error: %Rrs", c);
336 }
337 }
338
339 /* check for required options */
340 if (!VMName)
341 return errorSyntax(USAGE_STARTVM, "VM name required");
342
343 ComPtr<IMachine> machine;
344 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMName).raw(),
345 machine.asOutParam()));
346 if (machine)
347 {
348 Bstr env;
349#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
350 /* make sure the VM process will start on the same display as VBoxManage */
351 Utf8Str str;
352 const char *pszDisplay = RTEnvGet("DISPLAY");
353 if (pszDisplay)
354 str = Utf8StrFmt("DISPLAY=%s\n", pszDisplay);
355 const char *pszXAuth = RTEnvGet("XAUTHORITY");
356 if (pszXAuth)
357 str.append(Utf8StrFmt("XAUTHORITY=%s\n", pszXAuth));
358 env = str;
359#endif
360 ComPtr<IProgress> progress;
361 CHECK_ERROR_RET(machine, LaunchVMProcess(a->session, sessionType.raw(),
362 env.raw(), progress.asOutParam()), rc);
363 RTPrintf("Waiting for the VM to power on...\n");
364 CHECK_ERROR_RET(progress, WaitForCompletion(-1), 1);
365
366 BOOL completed;
367 CHECK_ERROR_RET(progress, COMGETTER(Completed)(&completed), rc);
368 ASSERT(completed);
369
370 LONG iRc;
371 CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc);
372 if (FAILED(iRc))
373 {
374 ProgressErrorInfo info(progress);
375 com::GluePrintErrorInfo(info);
376 }
377 else
378 {
379 RTPrintf("VM has been successfully started.\n");
380 }
381 }
382
383 /* it's important to always close sessions */
384 a->session->UnlockMachine();
385
386 return SUCCEEDED(rc) ? 0 : 1;
387}
388
389int handleDiscardState(HandlerArg *a)
390{
391 HRESULT rc;
392
393 if (a->argc != 1)
394 return errorSyntax(USAGE_DISCARDSTATE, "Incorrect number of parameters");
395
396 ComPtr<IMachine> machine;
397 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
398 machine.asOutParam()));
399 if (machine)
400 {
401 do
402 {
403 /* we have to open a session for this task */
404 CHECK_ERROR_BREAK(machine, LockMachine(a->session, LockType_Write));
405 do
406 {
407 ComPtr<IConsole> console;
408 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
409 CHECK_ERROR_BREAK(console, DiscardSavedState(true /* fDeleteFile */));
410 } while (0);
411 CHECK_ERROR_BREAK(a->session, UnlockMachine());
412 } while (0);
413 }
414
415 return SUCCEEDED(rc) ? 0 : 1;
416}
417
418int handleAdoptState(HandlerArg *a)
419{
420 HRESULT rc;
421
422 if (a->argc != 2)
423 return errorSyntax(USAGE_ADOPTSTATE, "Incorrect number of parameters");
424
425 ComPtr<IMachine> machine;
426 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
427 machine.asOutParam()));
428 if (machine)
429 {
430 do
431 {
432 /* we have to open a session for this task */
433 CHECK_ERROR_BREAK(machine, LockMachine(a->session, LockType_Write));
434 do
435 {
436 ComPtr<IConsole> console;
437 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
438 CHECK_ERROR_BREAK(console, AdoptSavedState(Bstr(a->argv[1]).raw()));
439 } while (0);
440 CHECK_ERROR_BREAK(a->session, UnlockMachine());
441 } while (0);
442 }
443
444 return SUCCEEDED(rc) ? 0 : 1;
445}
446
447int handleGetExtraData(HandlerArg *a)
448{
449 HRESULT rc = S_OK;
450
451 if (a->argc != 2)
452 return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");
453
454 /* global data? */
455 if (!strcmp(a->argv[0], "global"))
456 {
457 /* enumeration? */
458 if (!strcmp(a->argv[1], "enumerate"))
459 {
460 SafeArray<BSTR> aKeys;
461 CHECK_ERROR(a->virtualBox, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
462
463 for (size_t i = 0;
464 i < aKeys.size();
465 ++i)
466 {
467 Bstr bstrKey(aKeys[i]);
468 Bstr bstrValue;
469 CHECK_ERROR(a->virtualBox, GetExtraData(bstrKey.raw(),
470 bstrValue.asOutParam()));
471
472 RTPrintf("Key: %lS, Value: %lS\n", bstrKey.raw(), bstrValue.raw());
473 }
474 }
475 else
476 {
477 Bstr value;
478 CHECK_ERROR(a->virtualBox, GetExtraData(Bstr(a->argv[1]).raw(),
479 value.asOutParam()));
480 if (!value.isEmpty())
481 RTPrintf("Value: %lS\n", value.raw());
482 else
483 RTPrintf("No value set!\n");
484 }
485 }
486 else
487 {
488 ComPtr<IMachine> machine;
489 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
490 machine.asOutParam()));
491 if (machine)
492 {
493 /* enumeration? */
494 if (!strcmp(a->argv[1], "enumerate"))
495 {
496 SafeArray<BSTR> aKeys;
497 CHECK_ERROR(machine, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
498
499 for (size_t i = 0;
500 i < aKeys.size();
501 ++i)
502 {
503 Bstr bstrKey(aKeys[i]);
504 Bstr bstrValue;
505 CHECK_ERROR(machine, GetExtraData(bstrKey.raw(),
506 bstrValue.asOutParam()));
507
508 RTPrintf("Key: %lS, Value: %lS\n", bstrKey.raw(), bstrValue.raw());
509 }
510 }
511 else
512 {
513 Bstr value;
514 CHECK_ERROR(machine, GetExtraData(Bstr(a->argv[1]).raw(),
515 value.asOutParam()));
516 if (!value.isEmpty())
517 RTPrintf("Value: %lS\n", value.raw());
518 else
519 RTPrintf("No value set!\n");
520 }
521 }
522 }
523 return SUCCEEDED(rc) ? 0 : 1;
524}
525
526int handleSetExtraData(HandlerArg *a)
527{
528 HRESULT rc = S_OK;
529
530 if (a->argc < 2)
531 return errorSyntax(USAGE_SETEXTRADATA, "Not enough parameters");
532
533 /* global data? */
534 if (!strcmp(a->argv[0], "global"))
535 {
536 /** @todo passing NULL is deprecated */
537 if (a->argc < 3)
538 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]).raw(),
539 NULL));
540 else if (a->argc == 3)
541 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]).raw(),
542 Bstr(a->argv[2]).raw()));
543 else
544 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
545 }
546 else
547 {
548 ComPtr<IMachine> machine;
549 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
550 machine.asOutParam()));
551 if (machine)
552 {
553 /** @todo passing NULL is deprecated */
554 if (a->argc < 3)
555 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]).raw(),
556 NULL));
557 else if (a->argc == 3)
558 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]).raw(),
559 Bstr(a->argv[2]).raw()));
560 else
561 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
562 }
563 }
564 return SUCCEEDED(rc) ? 0 : 1;
565}
566
567int handleSetProperty(HandlerArg *a)
568{
569 HRESULT rc;
570
571 /* there must be two arguments: property name and value */
572 if (a->argc != 2)
573 return errorSyntax(USAGE_SETPROPERTY, "Incorrect number of parameters");
574
575 ComPtr<ISystemProperties> systemProperties;
576 a->virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
577
578 if (!strcmp(a->argv[0], "machinefolder"))
579 {
580 /* reset to default? */
581 if (!strcmp(a->argv[1], "default"))
582 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(NULL));
583 else
584 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(Bstr(a->argv[1]).raw()));
585 }
586 else if ( !strcmp(a->argv[0], "vrdeauthlibrary")
587 || !strcmp(a->argv[0], "vrdpauthlibrary"))
588 {
589 if (!strcmp(a->argv[0], "vrdpauthlibrary"))
590 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpauthlibrary' is deprecated. Use 'vrdeauthlibrary'.\n");
591
592 /* reset to default? */
593 if (!strcmp(a->argv[1], "default"))
594 CHECK_ERROR(systemProperties, COMSETTER(VRDEAuthLibrary)(NULL));
595 else
596 CHECK_ERROR(systemProperties, COMSETTER(VRDEAuthLibrary)(Bstr(a->argv[1]).raw()));
597 }
598 else if (!strcmp(a->argv[0], "websrvauthlibrary"))
599 {
600 /* reset to default? */
601 if (!strcmp(a->argv[1], "default"))
602 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(NULL));
603 else
604 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(Bstr(a->argv[1]).raw()));
605 }
606 else if (!strcmp(a->argv[0], "vrdeextpack"))
607 {
608 /* disable? */
609 if (!strcmp(a->argv[1], "null"))
610 CHECK_ERROR(systemProperties, COMSETTER(DefaultVRDEExtPack)(NULL));
611 else
612 CHECK_ERROR(systemProperties, COMSETTER(DefaultVRDEExtPack)(Bstr(a->argv[1]).raw()));
613 }
614 else if (!strcmp(a->argv[0], "loghistorycount"))
615 {
616 uint32_t uVal;
617 int vrc;
618 vrc = RTStrToUInt32Ex(a->argv[1], NULL, 0, &uVal);
619 if (vrc != VINF_SUCCESS)
620 return errorArgument("Error parsing Log history count '%s'", a->argv[1]);
621 CHECK_ERROR(systemProperties, COMSETTER(LogHistoryCount)(uVal));
622 }
623 else
624 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", a->argv[0]);
625
626 return SUCCEEDED(rc) ? 0 : 1;
627}
628
629int handleSharedFolder(HandlerArg *a)
630{
631 HRESULT rc;
632
633 /* we need at least a command and target */
634 if (a->argc < 2)
635 return errorSyntax(USAGE_SHAREDFOLDER, "Not enough parameters");
636
637 ComPtr<IMachine> machine;
638 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[1]).raw(),
639 machine.asOutParam()));
640 if (!machine)
641 return 1;
642
643 if (!strcmp(a->argv[0], "add"))
644 {
645 /* we need at least four more parameters */
646 if (a->argc < 5)
647 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Not enough parameters");
648
649 char *name = NULL;
650 char *hostpath = NULL;
651 bool fTransient = false;
652 bool fWritable = true;
653 bool fAutoMount = false;
654
655 for (int i = 2; i < a->argc; i++)
656 {
657 if ( !strcmp(a->argv[i], "--name")
658 || !strcmp(a->argv[i], "-name"))
659 {
660 if (a->argc <= i + 1 || !*a->argv[i+1])
661 return errorArgument("Missing argument to '%s'", a->argv[i]);
662 i++;
663 name = a->argv[i];
664 }
665 else if ( !strcmp(a->argv[i], "--hostpath")
666 || !strcmp(a->argv[i], "-hostpath"))
667 {
668 if (a->argc <= i + 1 || !*a->argv[i+1])
669 return errorArgument("Missing argument to '%s'", a->argv[i]);
670 i++;
671 hostpath = a->argv[i];
672 }
673 else if ( !strcmp(a->argv[i], "--readonly")
674 || !strcmp(a->argv[i], "-readonly"))
675 {
676 fWritable = false;
677 }
678 else if ( !strcmp(a->argv[i], "--transient")
679 || !strcmp(a->argv[i], "-transient"))
680 {
681 fTransient = true;
682 }
683 else if ( !strcmp(a->argv[i], "--automount")
684 || !strcmp(a->argv[i], "-automount"))
685 {
686 fAutoMount = true;
687 }
688 else
689 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
690 }
691
692 if (NULL != strstr(name, " "))
693 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "No spaces allowed in parameter '-name'!");
694
695 /* required arguments */
696 if (!name || !hostpath)
697 {
698 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Parameters --name and --hostpath are required");
699 }
700
701 if (fTransient)
702 {
703 ComPtr <IConsole> console;
704
705 /* open an existing session for the VM */
706 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
707 /* get the session machine */
708 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
709 /* get the session console */
710 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
711
712 CHECK_ERROR(console, CreateSharedFolder(Bstr(name).raw(),
713 Bstr(hostpath).raw(),
714 fWritable, fAutoMount));
715 if (console)
716 a->session->UnlockMachine();
717 }
718 else
719 {
720 /* open a session for the VM */
721 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), 1);
722
723 /* get the mutable session machine */
724 a->session->COMGETTER(Machine)(machine.asOutParam());
725
726 CHECK_ERROR(machine, CreateSharedFolder(Bstr(name).raw(),
727 Bstr(hostpath).raw(),
728 fWritable, fAutoMount));
729 if (SUCCEEDED(rc))
730 CHECK_ERROR(machine, SaveSettings());
731
732 a->session->UnlockMachine();
733 }
734 }
735 else if (!strcmp(a->argv[0], "remove"))
736 {
737 /* we need at least two more parameters */
738 if (a->argc < 3)
739 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Not enough parameters");
740
741 char *name = NULL;
742 bool fTransient = false;
743
744 for (int i = 2; i < a->argc; i++)
745 {
746 if ( !strcmp(a->argv[i], "--name")
747 || !strcmp(a->argv[i], "-name"))
748 {
749 if (a->argc <= i + 1 || !*a->argv[i+1])
750 return errorArgument("Missing argument to '%s'", a->argv[i]);
751 i++;
752 name = a->argv[i];
753 }
754 else if ( !strcmp(a->argv[i], "--transient")
755 || !strcmp(a->argv[i], "-transient"))
756 {
757 fTransient = true;
758 }
759 else
760 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
761 }
762
763 /* required arguments */
764 if (!name)
765 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Parameter --name is required");
766
767 if (fTransient)
768 {
769 ComPtr <IConsole> console;
770
771 /* open an existing session for the VM */
772 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
773 /* get the session machine */
774 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
775 /* get the session console */
776 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
777
778 CHECK_ERROR(console, RemoveSharedFolder(Bstr(name).raw()));
779
780 if (console)
781 a->session->UnlockMachine();
782 }
783 else
784 {
785 /* open a session for the VM */
786 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), 1);
787
788 /* get the mutable session machine */
789 a->session->COMGETTER(Machine)(machine.asOutParam());
790
791 CHECK_ERROR(machine, RemoveSharedFolder(Bstr(name).raw()));
792
793 /* commit and close the session */
794 CHECK_ERROR(machine, SaveSettings());
795 a->session->UnlockMachine();
796 }
797 }
798 else
799 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
800
801 return 0;
802}
803
804int handleExtPack(HandlerArg *a)
805{
806 if (a->argc < 1)
807 return errorSyntax(USAGE_EXTPACK, "Incorrect number of parameters");
808
809 ComObjPtr<IExtPackManager> ptrExtPackMgr;
810 CHECK_ERROR2_RET(a->virtualBox, COMGETTER(ExtensionPackManager)(ptrExtPackMgr.asOutParam()), RTEXITCODE_FAILURE);
811
812 RTGETOPTSTATE GetState;
813 RTGETOPTUNION ValueUnion;
814 int ch;
815 HRESULT hrc = S_OK;
816
817 if (!strcmp(a->argv[0], "install"))
818 {
819 const char *pszName = NULL;
820 bool fReplace = false;
821
822 static const RTGETOPTDEF s_aInstallOptions[] =
823 {
824 { "--replace", 'r', RTGETOPT_REQ_NOTHING },
825 };
826
827 RTGetOptInit(&GetState, a->argc, a->argv, s_aInstallOptions, RT_ELEMENTS(s_aInstallOptions), 1, 0 /*fFlags*/);
828 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
829 {
830 switch (ch)
831 {
832 case 'f':
833 fReplace = true;
834 break;
835
836 case VINF_GETOPT_NOT_OPTION:
837 if (pszName)
838 return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
839 pszName = ValueUnion.psz;
840 break;
841
842 default:
843 return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
844 }
845 }
846 if (!pszName)
847 return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack install\"");
848
849 char szPath[RTPATH_MAX];
850 int vrc = RTPathAbs(a->argv[1], szPath, sizeof(szPath));
851 if (RT_FAILURE(vrc))
852 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs(%s,,) failed with rc=%Rrc", a->argv[1], vrc);
853
854 Bstr bstrTarball(szPath);
855 Bstr bstrName;
856 ComPtr<IExtPackFile> ptrExtPackFile;
857 CHECK_ERROR2_RET(ptrExtPackMgr, OpenExtPackFile(bstrTarball.raw(), ptrExtPackFile.asOutParam()), RTEXITCODE_FAILURE);
858 CHECK_ERROR2_RET(ptrExtPackFile, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
859 ComPtr<IProgress> ptrProgress;
860 CHECK_ERROR2_RET(ptrExtPackFile, Install(fReplace, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
861 if (!ptrProgress.isNull())
862 CHECK_ERROR2_RET(ptrProgress, WaitForCompletion(-1), RTEXITCODE_FAILURE);
863 RTPrintf("Successfully installed \"%lS\".\n", bstrName.raw());
864 }
865 else if (!strcmp(a->argv[0], "uninstall"))
866 {
867 const char *pszName = NULL;
868 bool fForced = false;
869
870 static const RTGETOPTDEF s_aUninstallOptions[] =
871 {
872 { "--forced", 'f', RTGETOPT_REQ_NOTHING },
873 };
874
875 RTGetOptInit(&GetState, a->argc, a->argv, s_aUninstallOptions, RT_ELEMENTS(s_aUninstallOptions), 1, 0);
876 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
877 {
878 switch (ch)
879 {
880 case 'f':
881 fForced = true;
882 break;
883
884 case VINF_GETOPT_NOT_OPTION:
885 if (pszName)
886 return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
887 pszName = ValueUnion.psz;
888 break;
889
890 default:
891 return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
892 }
893 }
894 if (!pszName)
895 return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack uninstall\"");
896
897 Bstr bstrName(pszName);
898 ComPtr<IProgress> ptrProgress;
899 CHECK_ERROR2_RET(ptrExtPackMgr, Uninstall(bstrName.raw(), fForced, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
900 if (!ptrProgress.isNull())
901 CHECK_ERROR2_RET(ptrProgress, WaitForCompletion(-1), RTEXITCODE_FAILURE);
902 RTPrintf("Successfully uninstalled \"%s\".\n", pszName);
903 }
904 else if (!strcmp(a->argv[0], "cleanup"))
905 {
906 if (a->argc > 1)
907 return errorSyntax(USAGE_EXTPACK, "Too many parameters given to \"extpack cleanup\"");
908
909 CHECK_ERROR2_RET(ptrExtPackMgr, Cleanup(), RTEXITCODE_FAILURE);
910 RTPrintf("Successfully performed extension pack cleanup\n");
911 }
912 else
913 return errorSyntax(USAGE_EXTPACK, "Unknown command \"%s\"", a->argv[0]);
914
915 return RTEXITCODE_SUCCESS;
916}
917
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use