VirtualBox

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

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

VBoxManage: fixed error check

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 32.0 KB
Line 
1/* $Id: VBoxManageMisc.cpp 35827 2011-02-03 08:56:06Z 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 do
167 {
168 ComPtr<IProgress> pProgress;
169 CHECK_ERROR_BREAK(machine, Delete(ComSafeArrayAsInParam(aMedia), pProgress.asOutParam()));
170 CHECK_ERROR(pProgress, WaitForCompletion(-1));
171 } while (0);
172 }
173 }
174 }
175 return SUCCEEDED(rc) ? 0 : 1;
176}
177
178int handleCreateVM(HandlerArg *a)
179{
180 HRESULT rc;
181 Bstr baseFolder;
182 Bstr name;
183 Bstr osTypeId;
184 RTUUID id;
185 bool fRegister = false;
186
187 RTUuidClear(&id);
188 for (int i = 0; i < a->argc; i++)
189 {
190 if ( !strcmp(a->argv[i], "--basefolder")
191 || !strcmp(a->argv[i], "-basefolder"))
192 {
193 if (a->argc <= i + 1)
194 return errorArgument("Missing argument to '%s'", a->argv[i]);
195 i++;
196 baseFolder = a->argv[i];
197 }
198 else if ( !strcmp(a->argv[i], "--name")
199 || !strcmp(a->argv[i], "-name"))
200 {
201 if (a->argc <= i + 1)
202 return errorArgument("Missing argument to '%s'", a->argv[i]);
203 i++;
204 name = a->argv[i];
205 }
206 else if ( !strcmp(a->argv[i], "--ostype")
207 || !strcmp(a->argv[i], "-ostype"))
208 {
209 if (a->argc <= i + 1)
210 return errorArgument("Missing argument to '%s'", a->argv[i]);
211 i++;
212 osTypeId = a->argv[i];
213 }
214 else if ( !strcmp(a->argv[i], "--uuid")
215 || !strcmp(a->argv[i], "-uuid"))
216 {
217 if (a->argc <= i + 1)
218 return errorArgument("Missing argument to '%s'", a->argv[i]);
219 i++;
220 if (RT_FAILURE(RTUuidFromStr(&id, a->argv[i])))
221 return errorArgument("Invalid UUID format %s\n", a->argv[i]);
222 }
223 else if ( !strcmp(a->argv[i], "--register")
224 || !strcmp(a->argv[i], "-register"))
225 {
226 fRegister = true;
227 }
228 else
229 return errorSyntax(USAGE_CREATEVM, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
230 }
231
232 /* check for required options */
233 if (name.isEmpty())
234 return errorSyntax(USAGE_CREATEVM, "Parameter --name is required");
235
236 do
237 {
238 Bstr bstrSettingsFile;
239 CHECK_ERROR_BREAK(a->virtualBox,
240 ComposeMachineFilename(name.raw(),
241 baseFolder.raw(),
242 bstrSettingsFile.asOutParam()));
243 ComPtr<IMachine> machine;
244 CHECK_ERROR_BREAK(a->virtualBox,
245 CreateMachine(bstrSettingsFile.raw(),
246 name.raw(),
247 osTypeId.raw(),
248 Guid(id).toUtf16().raw(),
249 FALSE /* forceOverwrite */,
250 machine.asOutParam()));
251
252 CHECK_ERROR_BREAK(machine, SaveSettings());
253 if (fRegister)
254 {
255 CHECK_ERROR_BREAK(a->virtualBox, RegisterMachine(machine));
256 }
257 Bstr uuid;
258 CHECK_ERROR_BREAK(machine, COMGETTER(Id)(uuid.asOutParam()));
259 Bstr settingsFile;
260 CHECK_ERROR_BREAK(machine, COMGETTER(SettingsFilePath)(settingsFile.asOutParam()));
261 RTPrintf("Virtual machine '%ls' is created%s.\n"
262 "UUID: %s\n"
263 "Settings file: '%ls'\n",
264 name.raw(), fRegister ? " and registered" : "",
265 Utf8Str(uuid).c_str(), settingsFile.raw());
266 }
267 while (0);
268
269 return SUCCEEDED(rc) ? 0 : 1;
270}
271
272int handleStartVM(HandlerArg *a)
273{
274 HRESULT rc;
275 const char *VMName = NULL;
276 Bstr sessionType = "gui";
277
278 static const RTGETOPTDEF s_aStartVMOptions[] =
279 {
280 { "--type", 't', RTGETOPT_REQ_STRING },
281 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
282 };
283 int c;
284 RTGETOPTUNION ValueUnion;
285 RTGETOPTSTATE GetState;
286 // start at 0 because main() has hacked both the argc and argv given to us
287 RTGetOptInit(&GetState, a->argc, a->argv, s_aStartVMOptions, RT_ELEMENTS(s_aStartVMOptions),
288 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
289 while ((c = RTGetOpt(&GetState, &ValueUnion)))
290 {
291 switch (c)
292 {
293 case 't': // --type
294 if (!RTStrICmp(ValueUnion.psz, "gui"))
295 {
296 sessionType = "gui";
297 }
298#ifdef VBOX_WITH_VBOXSDL
299 else if (!RTStrICmp(ValueUnion.psz, "sdl"))
300 {
301 sessionType = "sdl";
302 }
303#endif
304#ifdef VBOX_WITH_HEADLESS
305 else if (!RTStrICmp(ValueUnion.psz, "capture"))
306 {
307 sessionType = "capture";
308 }
309 else if (!RTStrICmp(ValueUnion.psz, "headless"))
310 {
311 sessionType = "headless";
312 }
313#endif
314 else
315 return errorArgument("Invalid session type '%s'", ValueUnion.psz);
316 break;
317
318 case VINF_GETOPT_NOT_OPTION:
319 if (!VMName)
320 VMName = ValueUnion.psz;
321 else
322 return errorSyntax(USAGE_STARTVM, "Invalid parameter '%s'", ValueUnion.psz);
323 break;
324
325 default:
326 if (c > 0)
327 {
328 if (RT_C_IS_PRINT(c))
329 return errorSyntax(USAGE_STARTVM, "Invalid option -%c", c);
330 else
331 return errorSyntax(USAGE_STARTVM, "Invalid option case %i", c);
332 }
333 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
334 return errorSyntax(USAGE_STARTVM, "unknown option: %s\n", ValueUnion.psz);
335 else if (ValueUnion.pDef)
336 return errorSyntax(USAGE_STARTVM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
337 else
338 return errorSyntax(USAGE_STARTVM, "error: %Rrs", c);
339 }
340 }
341
342 /* check for required options */
343 if (!VMName)
344 return errorSyntax(USAGE_STARTVM, "VM name required");
345
346 ComPtr<IMachine> machine;
347 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMName).raw(),
348 machine.asOutParam()));
349 if (machine)
350 {
351 Bstr env;
352#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS)
353 /* make sure the VM process will start on the same display as VBoxManage */
354 Utf8Str str;
355 const char *pszDisplay = RTEnvGet("DISPLAY");
356 if (pszDisplay)
357 str = Utf8StrFmt("DISPLAY=%s\n", pszDisplay);
358 const char *pszXAuth = RTEnvGet("XAUTHORITY");
359 if (pszXAuth)
360 str.append(Utf8StrFmt("XAUTHORITY=%s\n", pszXAuth));
361 env = str;
362#endif
363 ComPtr<IProgress> progress;
364 CHECK_ERROR_RET(machine, LaunchVMProcess(a->session, sessionType.raw(),
365 env.raw(), progress.asOutParam()), rc);
366 RTPrintf("Waiting for the VM to power on...\n");
367 CHECK_ERROR_RET(progress, WaitForCompletion(-1), 1);
368
369 BOOL completed;
370 CHECK_ERROR_RET(progress, COMGETTER(Completed)(&completed), rc);
371 ASSERT(completed);
372
373 LONG iRc;
374 CHECK_ERROR_RET(progress, COMGETTER(ResultCode)(&iRc), rc);
375 if (FAILED(iRc))
376 {
377 ProgressErrorInfo info(progress);
378 com::GluePrintErrorInfo(info);
379 }
380 else
381 {
382 RTPrintf("VM has been successfully started.\n");
383 }
384 }
385
386 /* it's important to always close sessions */
387 a->session->UnlockMachine();
388
389 return SUCCEEDED(rc) ? 0 : 1;
390}
391
392int handleDiscardState(HandlerArg *a)
393{
394 HRESULT rc;
395
396 if (a->argc != 1)
397 return errorSyntax(USAGE_DISCARDSTATE, "Incorrect number of parameters");
398
399 ComPtr<IMachine> machine;
400 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
401 machine.asOutParam()));
402 if (machine)
403 {
404 do
405 {
406 /* we have to open a session for this task */
407 CHECK_ERROR_BREAK(machine, LockMachine(a->session, LockType_Write));
408 do
409 {
410 ComPtr<IConsole> console;
411 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
412 CHECK_ERROR_BREAK(console, DiscardSavedState(true /* fDeleteFile */));
413 } while (0);
414 CHECK_ERROR_BREAK(a->session, UnlockMachine());
415 } while (0);
416 }
417
418 return SUCCEEDED(rc) ? 0 : 1;
419}
420
421int handleAdoptState(HandlerArg *a)
422{
423 HRESULT rc;
424
425 if (a->argc != 2)
426 return errorSyntax(USAGE_ADOPTSTATE, "Incorrect number of parameters");
427
428 ComPtr<IMachine> machine;
429 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
430 machine.asOutParam()));
431 if (machine)
432 {
433 do
434 {
435 /* we have to open a session for this task */
436 CHECK_ERROR_BREAK(machine, LockMachine(a->session, LockType_Write));
437 do
438 {
439 ComPtr<IConsole> console;
440 CHECK_ERROR_BREAK(a->session, COMGETTER(Console)(console.asOutParam()));
441 CHECK_ERROR_BREAK(console, AdoptSavedState(Bstr(a->argv[1]).raw()));
442 } while (0);
443 CHECK_ERROR_BREAK(a->session, UnlockMachine());
444 } while (0);
445 }
446
447 return SUCCEEDED(rc) ? 0 : 1;
448}
449
450int handleGetExtraData(HandlerArg *a)
451{
452 HRESULT rc = S_OK;
453
454 if (a->argc != 2)
455 return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");
456
457 /* global data? */
458 if (!strcmp(a->argv[0], "global"))
459 {
460 /* enumeration? */
461 if (!strcmp(a->argv[1], "enumerate"))
462 {
463 SafeArray<BSTR> aKeys;
464 CHECK_ERROR(a->virtualBox, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
465
466 for (size_t i = 0;
467 i < aKeys.size();
468 ++i)
469 {
470 Bstr bstrKey(aKeys[i]);
471 Bstr bstrValue;
472 CHECK_ERROR(a->virtualBox, GetExtraData(bstrKey.raw(),
473 bstrValue.asOutParam()));
474
475 RTPrintf("Key: %lS, Value: %lS\n", bstrKey.raw(), bstrValue.raw());
476 }
477 }
478 else
479 {
480 Bstr value;
481 CHECK_ERROR(a->virtualBox, GetExtraData(Bstr(a->argv[1]).raw(),
482 value.asOutParam()));
483 if (!value.isEmpty())
484 RTPrintf("Value: %lS\n", value.raw());
485 else
486 RTPrintf("No value set!\n");
487 }
488 }
489 else
490 {
491 ComPtr<IMachine> machine;
492 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
493 machine.asOutParam()));
494 if (machine)
495 {
496 /* enumeration? */
497 if (!strcmp(a->argv[1], "enumerate"))
498 {
499 SafeArray<BSTR> aKeys;
500 CHECK_ERROR(machine, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));
501
502 for (size_t i = 0;
503 i < aKeys.size();
504 ++i)
505 {
506 Bstr bstrKey(aKeys[i]);
507 Bstr bstrValue;
508 CHECK_ERROR(machine, GetExtraData(bstrKey.raw(),
509 bstrValue.asOutParam()));
510
511 RTPrintf("Key: %lS, Value: %lS\n", bstrKey.raw(), bstrValue.raw());
512 }
513 }
514 else
515 {
516 Bstr value;
517 CHECK_ERROR(machine, GetExtraData(Bstr(a->argv[1]).raw(),
518 value.asOutParam()));
519 if (!value.isEmpty())
520 RTPrintf("Value: %lS\n", value.raw());
521 else
522 RTPrintf("No value set!\n");
523 }
524 }
525 }
526 return SUCCEEDED(rc) ? 0 : 1;
527}
528
529int handleSetExtraData(HandlerArg *a)
530{
531 HRESULT rc = S_OK;
532
533 if (a->argc < 2)
534 return errorSyntax(USAGE_SETEXTRADATA, "Not enough parameters");
535
536 /* global data? */
537 if (!strcmp(a->argv[0], "global"))
538 {
539 /** @todo passing NULL is deprecated */
540 if (a->argc < 3)
541 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]).raw(),
542 NULL));
543 else if (a->argc == 3)
544 CHECK_ERROR(a->virtualBox, SetExtraData(Bstr(a->argv[1]).raw(),
545 Bstr(a->argv[2]).raw()));
546 else
547 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
548 }
549 else
550 {
551 ComPtr<IMachine> machine;
552 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
553 machine.asOutParam()));
554 if (machine)
555 {
556 /** @todo passing NULL is deprecated */
557 if (a->argc < 3)
558 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]).raw(),
559 NULL));
560 else if (a->argc == 3)
561 CHECK_ERROR(machine, SetExtraData(Bstr(a->argv[1]).raw(),
562 Bstr(a->argv[2]).raw()));
563 else
564 return errorSyntax(USAGE_SETEXTRADATA, "Too many parameters");
565 }
566 }
567 return SUCCEEDED(rc) ? 0 : 1;
568}
569
570int handleSetProperty(HandlerArg *a)
571{
572 HRESULT rc;
573
574 /* there must be two arguments: property name and value */
575 if (a->argc != 2)
576 return errorSyntax(USAGE_SETPROPERTY, "Incorrect number of parameters");
577
578 ComPtr<ISystemProperties> systemProperties;
579 a->virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
580
581 if (!strcmp(a->argv[0], "machinefolder"))
582 {
583 /* reset to default? */
584 if (!strcmp(a->argv[1], "default"))
585 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(NULL));
586 else
587 CHECK_ERROR(systemProperties, COMSETTER(DefaultMachineFolder)(Bstr(a->argv[1]).raw()));
588 }
589 else if ( !strcmp(a->argv[0], "vrdeauthlibrary")
590 || !strcmp(a->argv[0], "vrdpauthlibrary"))
591 {
592 if (!strcmp(a->argv[0], "vrdpauthlibrary"))
593 RTStrmPrintf(g_pStdErr, "Warning: 'vrdpauthlibrary' is deprecated. Use 'vrdeauthlibrary'.\n");
594
595 /* reset to default? */
596 if (!strcmp(a->argv[1], "default"))
597 CHECK_ERROR(systemProperties, COMSETTER(VRDEAuthLibrary)(NULL));
598 else
599 CHECK_ERROR(systemProperties, COMSETTER(VRDEAuthLibrary)(Bstr(a->argv[1]).raw()));
600 }
601 else if (!strcmp(a->argv[0], "websrvauthlibrary"))
602 {
603 /* reset to default? */
604 if (!strcmp(a->argv[1], "default"))
605 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(NULL));
606 else
607 CHECK_ERROR(systemProperties, COMSETTER(WebServiceAuthLibrary)(Bstr(a->argv[1]).raw()));
608 }
609 else if (!strcmp(a->argv[0], "vrdeextpack"))
610 {
611 /* disable? */
612 if (!strcmp(a->argv[1], "null"))
613 CHECK_ERROR(systemProperties, COMSETTER(DefaultVRDEExtPack)(NULL));
614 else
615 CHECK_ERROR(systemProperties, COMSETTER(DefaultVRDEExtPack)(Bstr(a->argv[1]).raw()));
616 }
617 else if (!strcmp(a->argv[0], "loghistorycount"))
618 {
619 uint32_t uVal;
620 int vrc;
621 vrc = RTStrToUInt32Ex(a->argv[1], NULL, 0, &uVal);
622 if (vrc != VINF_SUCCESS)
623 return errorArgument("Error parsing Log history count '%s'", a->argv[1]);
624 CHECK_ERROR(systemProperties, COMSETTER(LogHistoryCount)(uVal));
625 }
626 else
627 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", a->argv[0]);
628
629 return SUCCEEDED(rc) ? 0 : 1;
630}
631
632int handleSharedFolder(HandlerArg *a)
633{
634 HRESULT rc;
635
636 /* we need at least a command and target */
637 if (a->argc < 2)
638 return errorSyntax(USAGE_SHAREDFOLDER, "Not enough parameters");
639
640 ComPtr<IMachine> machine;
641 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[1]).raw(),
642 machine.asOutParam()));
643 if (!machine)
644 return 1;
645
646 if (!strcmp(a->argv[0], "add"))
647 {
648 /* we need at least four more parameters */
649 if (a->argc < 5)
650 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Not enough parameters");
651
652 char *name = NULL;
653 char *hostpath = NULL;
654 bool fTransient = false;
655 bool fWritable = true;
656 bool fAutoMount = false;
657
658 for (int i = 2; i < a->argc; i++)
659 {
660 if ( !strcmp(a->argv[i], "--name")
661 || !strcmp(a->argv[i], "-name"))
662 {
663 if (a->argc <= i + 1 || !*a->argv[i+1])
664 return errorArgument("Missing argument to '%s'", a->argv[i]);
665 i++;
666 name = a->argv[i];
667 }
668 else if ( !strcmp(a->argv[i], "--hostpath")
669 || !strcmp(a->argv[i], "-hostpath"))
670 {
671 if (a->argc <= i + 1 || !*a->argv[i+1])
672 return errorArgument("Missing argument to '%s'", a->argv[i]);
673 i++;
674 hostpath = a->argv[i];
675 }
676 else if ( !strcmp(a->argv[i], "--readonly")
677 || !strcmp(a->argv[i], "-readonly"))
678 {
679 fWritable = false;
680 }
681 else if ( !strcmp(a->argv[i], "--transient")
682 || !strcmp(a->argv[i], "-transient"))
683 {
684 fTransient = true;
685 }
686 else if ( !strcmp(a->argv[i], "--automount")
687 || !strcmp(a->argv[i], "-automount"))
688 {
689 fAutoMount = true;
690 }
691 else
692 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
693 }
694
695 if (NULL != strstr(name, " "))
696 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "No spaces allowed in parameter '-name'!");
697
698 /* required arguments */
699 if (!name || !hostpath)
700 {
701 return errorSyntax(USAGE_SHAREDFOLDER_ADD, "Parameters --name and --hostpath are required");
702 }
703
704 if (fTransient)
705 {
706 ComPtr <IConsole> console;
707
708 /* open an existing session for the VM */
709 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
710 /* get the session machine */
711 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
712 /* get the session console */
713 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
714
715 CHECK_ERROR(console, CreateSharedFolder(Bstr(name).raw(),
716 Bstr(hostpath).raw(),
717 fWritable, fAutoMount));
718 if (console)
719 a->session->UnlockMachine();
720 }
721 else
722 {
723 /* open a session for the VM */
724 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), 1);
725
726 /* get the mutable session machine */
727 a->session->COMGETTER(Machine)(machine.asOutParam());
728
729 CHECK_ERROR(machine, CreateSharedFolder(Bstr(name).raw(),
730 Bstr(hostpath).raw(),
731 fWritable, fAutoMount));
732 if (SUCCEEDED(rc))
733 CHECK_ERROR(machine, SaveSettings());
734
735 a->session->UnlockMachine();
736 }
737 }
738 else if (!strcmp(a->argv[0], "remove"))
739 {
740 /* we need at least two more parameters */
741 if (a->argc < 3)
742 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Not enough parameters");
743
744 char *name = NULL;
745 bool fTransient = false;
746
747 for (int i = 2; i < a->argc; i++)
748 {
749 if ( !strcmp(a->argv[i], "--name")
750 || !strcmp(a->argv[i], "-name"))
751 {
752 if (a->argc <= i + 1 || !*a->argv[i+1])
753 return errorArgument("Missing argument to '%s'", a->argv[i]);
754 i++;
755 name = a->argv[i];
756 }
757 else if ( !strcmp(a->argv[i], "--transient")
758 || !strcmp(a->argv[i], "-transient"))
759 {
760 fTransient = true;
761 }
762 else
763 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Invalid parameter '%s'", Utf8Str(a->argv[i]).c_str());
764 }
765
766 /* required arguments */
767 if (!name)
768 return errorSyntax(USAGE_SHAREDFOLDER_REMOVE, "Parameter --name is required");
769
770 if (fTransient)
771 {
772 ComPtr <IConsole> console;
773
774 /* open an existing session for the VM */
775 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);
776 /* get the session machine */
777 CHECK_ERROR_RET(a->session, COMGETTER(Machine)(machine.asOutParam()), 1);
778 /* get the session console */
779 CHECK_ERROR_RET(a->session, COMGETTER(Console)(console.asOutParam()), 1);
780
781 CHECK_ERROR(console, RemoveSharedFolder(Bstr(name).raw()));
782
783 if (console)
784 a->session->UnlockMachine();
785 }
786 else
787 {
788 /* open a session for the VM */
789 CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Write), 1);
790
791 /* get the mutable session machine */
792 a->session->COMGETTER(Machine)(machine.asOutParam());
793
794 CHECK_ERROR(machine, RemoveSharedFolder(Bstr(name).raw()));
795
796 /* commit and close the session */
797 CHECK_ERROR(machine, SaveSettings());
798 a->session->UnlockMachine();
799 }
800 }
801 else
802 return errorSyntax(USAGE_SETPROPERTY, "Invalid parameter '%s'", Utf8Str(a->argv[0]).c_str());
803
804 return 0;
805}
806
807int handleExtPack(HandlerArg *a)
808{
809 if (a->argc < 1)
810 return errorSyntax(USAGE_EXTPACK, "Incorrect number of parameters");
811
812 ComObjPtr<IExtPackManager> ptrExtPackMgr;
813 CHECK_ERROR2_RET(a->virtualBox, COMGETTER(ExtensionPackManager)(ptrExtPackMgr.asOutParam()), RTEXITCODE_FAILURE);
814
815 RTGETOPTSTATE GetState;
816 RTGETOPTUNION ValueUnion;
817 int ch;
818 HRESULT hrc = S_OK;
819
820 if (!strcmp(a->argv[0], "install"))
821 {
822 const char *pszName = NULL;
823 bool fReplace = false;
824
825 static const RTGETOPTDEF s_aInstallOptions[] =
826 {
827 { "--replace", 'r', RTGETOPT_REQ_NOTHING },
828 };
829
830 RTGetOptInit(&GetState, a->argc, a->argv, s_aInstallOptions, RT_ELEMENTS(s_aInstallOptions), 1, 0 /*fFlags*/);
831 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
832 {
833 switch (ch)
834 {
835 case 'f':
836 fReplace = true;
837 break;
838
839 case VINF_GETOPT_NOT_OPTION:
840 if (pszName)
841 return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
842 pszName = ValueUnion.psz;
843 break;
844
845 default:
846 return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
847 }
848 }
849 if (!pszName)
850 return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack install\"");
851
852 char szPath[RTPATH_MAX];
853 int vrc = RTPathAbs(a->argv[1], szPath, sizeof(szPath));
854 if (RT_FAILURE(vrc))
855 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs(%s,,) failed with rc=%Rrc", a->argv[1], vrc);
856
857 Bstr bstrTarball(szPath);
858 Bstr bstrName;
859 ComPtr<IExtPackFile> ptrExtPackFile;
860 CHECK_ERROR2_RET(ptrExtPackMgr, OpenExtPackFile(bstrTarball.raw(), ptrExtPackFile.asOutParam()), RTEXITCODE_FAILURE);
861 CHECK_ERROR2_RET(ptrExtPackFile, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE);
862 ComPtr<IProgress> ptrProgress;
863 CHECK_ERROR2_RET(ptrExtPackFile, Install(fReplace, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
864 hrc = showProgress(ptrProgress);
865 if (FAILED(hrc))
866 {
867 com::ProgressErrorInfo ErrInfo(ptrProgress);
868 if (ErrInfo.isBasicAvailable())
869 RTMsgError("Failed to install \"%s\": %lS", szPath, ErrInfo.getText().raw());
870 else
871 RTMsgError("Failed to install \"%s\": No error message available!", szPath);
872 return RTEXITCODE_FAILURE;
873 }
874 RTPrintf("Successfully installed \"%lS\".\n", bstrName.raw());
875 }
876 else if (!strcmp(a->argv[0], "uninstall"))
877 {
878 const char *pszName = NULL;
879 bool fForced = false;
880
881 static const RTGETOPTDEF s_aUninstallOptions[] =
882 {
883 { "--forced", 'f', RTGETOPT_REQ_NOTHING },
884 };
885
886 RTGetOptInit(&GetState, a->argc, a->argv, s_aUninstallOptions, RT_ELEMENTS(s_aUninstallOptions), 1, 0);
887 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
888 {
889 switch (ch)
890 {
891 case 'f':
892 fForced = true;
893 break;
894
895 case VINF_GETOPT_NOT_OPTION:
896 if (pszName)
897 return errorSyntax(USAGE_EXTPACK, "Too many extension pack names given to \"extpack uninstall\"");
898 pszName = ValueUnion.psz;
899 break;
900
901 default:
902 return errorGetOpt(USAGE_EXTPACK, ch, &ValueUnion);
903 }
904 }
905 if (!pszName)
906 return errorSyntax(USAGE_EXTPACK, "No extension pack name was given to \"extpack uninstall\"");
907
908 Bstr bstrName(pszName);
909 ComPtr<IProgress> ptrProgress;
910 CHECK_ERROR2_RET(ptrExtPackMgr, Uninstall(bstrName.raw(), fForced, NULL, ptrProgress.asOutParam()), RTEXITCODE_FAILURE);
911 hrc = showProgress(ptrProgress);
912 if (FAILED(hrc))
913 {
914 com::ProgressErrorInfo ErrInfo(ptrProgress);
915 if (ErrInfo.isBasicAvailable())
916 RTMsgError("Failed to uninstall \"%s\": %lS", pszName, ErrInfo.getText().raw());
917 else
918 RTMsgError("Failed to uninstall \"%s\": No error message available!", pszName);
919 return RTEXITCODE_FAILURE;
920 }
921 RTPrintf("Successfully uninstalled \"%s\".\n", pszName);
922 }
923 else if (!strcmp(a->argv[0], "cleanup"))
924 {
925 if (a->argc > 1)
926 return errorSyntax(USAGE_EXTPACK, "Too many parameters given to \"extpack cleanup\"");
927
928 CHECK_ERROR2_RET(ptrExtPackMgr, Cleanup(), RTEXITCODE_FAILURE);
929 RTPrintf("Successfully performed extension pack cleanup\n");
930 }
931 else
932 return errorSyntax(USAGE_EXTPACK, "Unknown command \"%s\"", a->argv[0]);
933
934 return RTEXITCODE_SUCCESS;
935}
936
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