VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageDisk.cpp@ 18948

Last change on this file since 18948 was 18901, checked in by vboxsync, 16 years ago

VBoxManage: fix the relative path name hack, it issued bogus errors for the API interpretation of relative path names.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 50.8 KB
Line 
1/* $Id: VBoxManageDisk.cpp 18901 2009-04-15 12:04:59Z vboxsync $ */
2/** @file
3 * VBoxManage - The disk delated commands.
4 */
5
6/*
7 * Copyright (C) 2006-2008 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22#ifndef VBOX_ONLY_DOCS
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <VBox/com/com.h>
28#include <VBox/com/array.h>
29#include <VBox/com/ErrorInfo.h>
30#include <VBox/com/errorprint2.h>
31#include <VBox/com/VirtualBox.h>
32
33#include <iprt/asm.h>
34#include <iprt/file.h>
35#include <iprt/path.h>
36#include <iprt/param.h>
37#include <iprt/stream.h>
38#include <iprt/string.h>
39#include <iprt/ctype.h>
40#include <iprt/getopt.h>
41#include <VBox/log.h>
42#include <VBox/VBoxHDD.h>
43
44#include "VBoxManage.h"
45using namespace com;
46
47
48// funcs
49///////////////////////////////////////////////////////////////////////////////
50
51
52static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
53{
54 RTPrintf("ERROR: ");
55 RTPrintfV(pszFormat, va);
56 RTPrintf("\n");
57 RTPrintf("Error code %Rrc at %s(%u) in function %s\n", rc, RT_SRC_POS_ARGS);
58}
59
60
61static int parseDiskVariant(const char *psz, HardDiskVariant_T *pDiskVariant)
62{
63 int rc = VINF_SUCCESS;
64 unsigned DiskVariant = (unsigned)(*pDiskVariant);
65 while (psz && *psz && RT_SUCCESS(rc))
66 {
67 size_t len;
68 const char *pszComma = strchr(psz, ',');
69 if (pszComma)
70 len = pszComma - psz;
71 else
72 len = strlen(psz);
73 if (len > 0)
74 {
75 // Parsing is intentionally inconsistent: "standard" resets the
76 // variant, whereas the other flags are cumulative.
77 if (!RTStrNICmp(psz, "standard", len))
78 DiskVariant = HardDiskVariant_Standard;
79 else if ( !RTStrNICmp(psz, "fixed", len)
80 || !RTStrNICmp(psz, "static", len))
81 DiskVariant |= HardDiskVariant_Fixed;
82 else if (!RTStrNICmp(psz, "Diff", len))
83 DiskVariant |= HardDiskVariant_Diff;
84 else if (!RTStrNICmp(psz, "split2g", len))
85 DiskVariant |= HardDiskVariant_VmdkSplit2G;
86 else if ( !RTStrNICmp(psz, "stream", len)
87 || !RTStrNICmp(psz, "streamoptimized", len))
88 DiskVariant |= HardDiskVariant_VmdkStreamOptimized;
89 else if (!RTStrNICmp(psz, "esx", len))
90 DiskVariant |= HardDiskVariant_VmdkESX;
91 else
92 rc = VERR_PARSE_ERROR;
93 }
94 if (pszComma)
95 psz += len + 1;
96 else
97 psz += len;
98 }
99
100 if (RT_SUCCESS(rc))
101 *pDiskVariant = (HardDiskVariant_T)DiskVariant;
102 return rc;
103}
104
105static int parseDiskType(const char *psz, HardDiskType_T *pDiskType)
106{
107 int rc = VINF_SUCCESS;
108 HardDiskType_T DiskType = HardDiskType_Normal;
109 if (!RTStrICmp(psz, "normal"))
110 DiskType = HardDiskType_Normal;
111 else if (!RTStrICmp(psz, "immutable"))
112 DiskType = HardDiskType_Immutable;
113 else if (!RTStrICmp(psz, "writethrough"))
114 DiskType = HardDiskType_Writethrough;
115 else
116 rc = VERR_PARSE_ERROR;
117
118 if (RT_SUCCESS(rc))
119 *pDiskType = DiskType;
120 return rc;
121}
122
123/** @todo move this into getopt, as getting bool values is generic */
124static int parseBool(const char *psz, bool *pb)
125{
126 int rc = VINF_SUCCESS;
127 if ( !RTStrICmp(psz, "on")
128 || !RTStrICmp(psz, "yes")
129 || !RTStrICmp(psz, "true")
130 || !RTStrICmp(psz, "1")
131 || !RTStrICmp(psz, "enable")
132 || !RTStrICmp(psz, "enabled"))
133 {
134 *pb = true;
135 }
136 else if ( !RTStrICmp(psz, "off")
137 || !RTStrICmp(psz, "no")
138 || !RTStrICmp(psz, "false")
139 || !RTStrICmp(psz, "0")
140 || !RTStrICmp(psz, "disable")
141 || !RTStrICmp(psz, "disabled"))
142 {
143 *pb = false;
144 }
145 else
146 rc = VERR_PARSE_ERROR;
147
148 return rc;
149}
150
151static const RTGETOPTDEF g_aCreateHardDiskOptions[] =
152{
153 { "--filename", 'f', RTGETOPT_REQ_STRING },
154 { "-filename", 'f', RTGETOPT_REQ_STRING }, // deprecated
155 { "--size", 's', RTGETOPT_REQ_UINT64 },
156 { "-size", 's', RTGETOPT_REQ_UINT64 }, // deprecated
157 { "--format", 'o', RTGETOPT_REQ_STRING },
158 { "-format", 'o', RTGETOPT_REQ_STRING }, // deprecated
159 { "--static", 'F', RTGETOPT_REQ_NOTHING },
160 { "-static", 'F', RTGETOPT_REQ_NOTHING }, // deprecated
161 { "--variant", 'm', RTGETOPT_REQ_STRING },
162 { "-variant", 'm', RTGETOPT_REQ_STRING }, // deprecated
163 { "--type", 't', RTGETOPT_REQ_STRING },
164 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
165 { "--comment", 'c', RTGETOPT_REQ_STRING },
166 { "-comment", 'c', RTGETOPT_REQ_STRING }, // deprecated
167 { "--remember", 'r', RTGETOPT_REQ_NOTHING },
168 { "-remember", 'r', RTGETOPT_REQ_NOTHING }, // deprecated
169 { "--register", 'r', RTGETOPT_REQ_NOTHING }, // deprecated (inofficial)
170 { "-register", 'r', RTGETOPT_REQ_NOTHING }, // deprecated
171};
172
173int handleCreateHardDisk(HandlerArg *a)
174{
175 HRESULT rc;
176 int vrc;
177 Bstr filename;
178 uint64_t sizeMB = 0;
179 Bstr format = "VDI";
180 HardDiskVariant_T DiskVariant = HardDiskVariant_Standard;
181 Bstr comment;
182 bool fRemember = false;
183 HardDiskType_T DiskType = HardDiskType_Normal;
184
185 int c;
186 RTGETOPTUNION ValueUnion;
187 RTGETOPTSTATE GetState;
188 // start at 0 because main() has hacked both the argc and argv given to us
189 RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateHardDiskOptions, RT_ELEMENTS(g_aCreateHardDiskOptions), 0, 0 /* fFlags */);
190 while ((c = RTGetOpt(&GetState, &ValueUnion)))
191 {
192 switch (c)
193 {
194 case 'f': // --filename
195 filename = ValueUnion.psz;
196 break;
197
198 case 's': // --size
199 sizeMB = ValueUnion.u64;
200 break;
201
202 case 'o': // --format
203 format = ValueUnion.psz;
204 break;
205
206 case 'F': // --static ("fixed"/"flat")
207 {
208 unsigned uDiskVariant = (unsigned)DiskVariant;
209 uDiskVariant |= HardDiskVariant_Fixed;
210 DiskVariant = (HardDiskVariant_T)uDiskVariant;
211 break;
212 }
213
214 case 'm': // --variant
215 vrc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
216 if (RT_FAILURE(vrc))
217 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
218 break;
219
220 case 'c': // --comment
221 comment = ValueUnion.psz;
222 break;
223
224 case 'r': // --remember
225 fRemember = true;
226 break;
227
228 case 't': // --type
229 vrc = parseDiskType(ValueUnion.psz, &DiskType);
230 if ( RT_FAILURE(vrc)
231 || (DiskType != HardDiskType_Normal && DiskType != HardDiskType_Writethrough))
232 return errorArgument("Invalid hard disk type '%s'", ValueUnion.psz);
233 break;
234
235 case VINF_GETOPT_NOT_OPTION:
236 return errorSyntax(USAGE_CREATEHD, "Invalid parameter '%s'", ValueUnion.psz);
237
238 default:
239 if (c > 0)
240 {
241 if (RT_C_IS_PRINT(c))
242 return errorSyntax(USAGE_CREATEHD, "Invalid option -%c", c);
243 else
244 return errorSyntax(USAGE_CREATEHD, "Invalid option case %i", c);
245 }
246 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
247 return errorSyntax(USAGE_CREATEHD, "unknown option: %s\n", ValueUnion.psz);
248 else if (ValueUnion.pDef)
249 return errorSyntax(USAGE_CREATEHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
250 else
251 return errorSyntax(USAGE_CREATEHD, "error: %Rrs", c);
252 }
253 }
254
255 /* check the outcome */
256 if (!filename || (sizeMB == 0))
257 return errorSyntax(USAGE_CREATEHD, "Parameters --filename and --size are required");
258
259 ComPtr<IHardDisk> hardDisk;
260 CHECK_ERROR(a->virtualBox, CreateHardDisk(format, filename, hardDisk.asOutParam()));
261 if (SUCCEEDED(rc) && hardDisk)
262 {
263 /* we will close the hard disk after the storage has been successfully
264 * created unless fRemember is set */
265 bool doClose = false;
266
267 if (!comment.isNull())
268 {
269 CHECK_ERROR(hardDisk,COMSETTER(Description)(comment));
270 }
271 ComPtr<IProgress> progress;
272 CHECK_ERROR(hardDisk, CreateBaseStorage(sizeMB, DiskVariant, progress.asOutParam()));
273 if (SUCCEEDED(rc) && progress)
274 {
275 showProgress(progress);
276 if (SUCCEEDED(rc))
277 {
278 progress->COMGETTER(ResultCode)(&rc);
279 if (FAILED(rc))
280 {
281 com::ProgressErrorInfo info(progress);
282 if (info.isBasicAvailable())
283 RTPrintf("Error: failed to create hard disk. Error message: %lS\n", info.getText().raw());
284 else
285 RTPrintf("Error: failed to create hard disk. No error message available!\n");
286 }
287 else
288 {
289 doClose = !fRemember;
290
291 Guid uuid;
292 CHECK_ERROR(hardDisk, COMGETTER(Id)(uuid.asOutParam()));
293
294 if (DiskType == HardDiskType_Writethrough)
295 {
296 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Writethrough));
297 }
298
299 RTPrintf("Disk image created. UUID: %s\n", uuid.toString().raw());
300 }
301 }
302 }
303 if (doClose)
304 {
305 CHECK_ERROR(hardDisk, Close());
306 }
307 }
308 return SUCCEEDED(rc) ? 0 : 1;
309}
310
311#if 0 /* disabled until disk shrinking is implemented based on VBoxHDD */
312static DECLCALLBACK(int) hardDiskProgressCallback(PVM pVM, unsigned uPercent, void *pvUser)
313{
314 unsigned *pPercent = (unsigned *)pvUser;
315
316 if (*pPercent != uPercent)
317 {
318 *pPercent = uPercent;
319 RTPrintf(".");
320 if ((uPercent % 10) == 0 && uPercent)
321 RTPrintf("%d%%", uPercent);
322 RTStrmFlush(g_pStdOut);
323 }
324
325 return VINF_SUCCESS;
326}
327#endif
328
329static const RTGETOPTDEF g_aModifyHardDiskOptions[] =
330{
331 { "--type", 't', RTGETOPT_REQ_STRING },
332 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
333 { "settype", 't', RTGETOPT_REQ_STRING }, // deprecated
334 { "--autoreset", 'z', RTGETOPT_REQ_STRING },
335 { "-autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
336 { "autoreset", 'z', RTGETOPT_REQ_STRING }, // deprecated
337 { "--compact", 'c', RTGETOPT_REQ_NOTHING },
338 { "-compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
339 { "compact", 'c', RTGETOPT_REQ_NOTHING }, // deprecated
340};
341
342int handleModifyHardDisk(HandlerArg *a)
343{
344 HRESULT rc;
345 int vrc;
346 ComPtr<IHardDisk> hardDisk;
347 HardDiskType_T DiskType;
348 bool AutoReset = false;
349 bool fModifyDiskType = false, fModifyAutoReset = false, fModifyCompact = false;;
350 const char *FilenameOrUuid = NULL;
351
352 int c;
353 RTGETOPTUNION ValueUnion;
354 RTGETOPTSTATE GetState;
355 // start at 0 because main() has hacked both the argc and argv given to us
356 RTGetOptInit(&GetState, a->argc, a->argv, g_aModifyHardDiskOptions, RT_ELEMENTS(g_aModifyHardDiskOptions), 0, 0 /* fFlags */);
357 while ((c = RTGetOpt(&GetState, &ValueUnion)))
358 {
359 switch (c)
360 {
361 case 't': // --type
362 vrc = parseDiskType(ValueUnion.psz, &DiskType);
363 if (RT_FAILURE(vrc))
364 return errorArgument("Invalid hard disk type '%s'", ValueUnion.psz);
365 fModifyDiskType = true;
366 break;
367
368 case 'z': // --autoreset
369 vrc = parseBool(ValueUnion.psz, &AutoReset);
370 if (RT_FAILURE(vrc))
371 return errorArgument("Invalid autoreset parameter '%s'", ValueUnion.psz);
372 fModifyAutoReset = true;
373 break;
374
375 case 'c': // --compact
376 fModifyCompact = true;
377 break;
378
379 case VINF_GETOPT_NOT_OPTION:
380 if (!FilenameOrUuid)
381 FilenameOrUuid = ValueUnion.psz;
382 else
383 return errorSyntax(USAGE_CREATEHD, "Invalid parameter '%s'", ValueUnion.psz);
384 break;
385
386 default:
387 if (c > 0)
388 {
389 if (RT_C_IS_PRINT(c))
390 return errorSyntax(USAGE_MODIFYHD, "Invalid option -%c", c);
391 else
392 return errorSyntax(USAGE_MODIFYHD, "Invalid option case %i", c);
393 }
394 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
395 return errorSyntax(USAGE_MODIFYHD, "unknown option: %s\n", ValueUnion.psz);
396 else if (ValueUnion.pDef)
397 return errorSyntax(USAGE_MODIFYHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
398 else
399 return errorSyntax(USAGE_MODIFYHD, "error: %Rrs", c);
400 }
401 }
402
403 if (!FilenameOrUuid)
404 return errorSyntax(USAGE_MODIFYHD, "Disk name or UUID required");
405
406 if (!fModifyDiskType && !fModifyAutoReset && !fModifyCompact)
407 return errorSyntax(USAGE_MODIFYHD, "No operation specified");
408
409 /* first guess is that it's a UUID */
410 Guid uuid(FilenameOrUuid);
411 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
412 /* no? then it must be a filename */
413 if (!hardDisk)
414 {
415 CHECK_ERROR(a->virtualBox, FindHardDisk(Bstr(FilenameOrUuid), hardDisk.asOutParam()));
416 if (FAILED(rc))
417 return 1;
418 }
419
420 if (fModifyDiskType)
421 {
422 /* hard disk must be registered */
423 if (SUCCEEDED(rc) && hardDisk)
424 {
425 HardDiskType_T hddType;
426 CHECK_ERROR(hardDisk, COMGETTER(Type)(&hddType));
427
428 if (hddType != DiskType)
429 CHECK_ERROR(hardDisk, COMSETTER(Type)(DiskType));
430 }
431 else
432 return errorArgument("Hard disk image not registered");
433 }
434
435 if (fModifyAutoReset)
436 {
437 CHECK_ERROR(hardDisk, COMSETTER(AutoReset)(AutoReset));
438 }
439
440 if (fModifyCompact)
441 {
442#if 1
443 RTPrintf("Error: Compact hard disk operation is not implemented!\n");
444 RTPrintf("The functionality will be restored later.\n");
445 return 1;
446#else
447 /* the hard disk image might not be registered */
448 if (!hardDisk)
449 {
450 a->virtualBox->OpenHardDisk(Bstr(FilenameOrUuid), AccessMode_ReadWrite, hardDisk.asOutParam());
451 if (!hardDisk)
452 return errorArgument("Hard disk image not found");
453 }
454
455 /** @todo implement compacting of images. */
456#endif
457 }
458
459 return SUCCEEDED(rc) ? 0 : 1;
460}
461
462static const RTGETOPTDEF g_aCloneHardDiskOptions[] =
463{
464 { "--format", 'o', RTGETOPT_REQ_STRING },
465 { "-format", 'o', RTGETOPT_REQ_STRING },
466 { "--static", 'F', RTGETOPT_REQ_NOTHING },
467 { "-static", 'F', RTGETOPT_REQ_NOTHING },
468 { "--variant", 'm', RTGETOPT_REQ_STRING },
469 { "-variant", 'm', RTGETOPT_REQ_STRING },
470 { "--type", 't', RTGETOPT_REQ_STRING },
471 { "-type", 't', RTGETOPT_REQ_STRING },
472 { "--remember", 'r', RTGETOPT_REQ_NOTHING },
473 { "-remember", 'r', RTGETOPT_REQ_NOTHING },
474 { "--register", 'r', RTGETOPT_REQ_NOTHING },
475 { "-register", 'r', RTGETOPT_REQ_NOTHING },
476};
477
478int handleCloneHardDisk(HandlerArg *a)
479{
480 HRESULT rc;
481 int vrc;
482 Bstr src, dst;
483 Bstr format;
484 HardDiskVariant_T DiskVariant = HardDiskVariant_Standard;
485 bool fRemember = false;
486 HardDiskType_T DiskType = HardDiskType_Normal;
487
488 int c;
489 RTGETOPTUNION ValueUnion;
490 RTGETOPTSTATE GetState;
491 // start at 0 because main() has hacked both the argc and argv given to us
492 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneHardDiskOptions, RT_ELEMENTS(g_aCloneHardDiskOptions), 0, 0 /* fFlags */);
493 while ((c = RTGetOpt(&GetState, &ValueUnion)))
494 {
495 switch (c)
496 {
497 case 'o': // --format
498 format = ValueUnion.psz;
499 break;
500
501 case 'm': // --variant
502 vrc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
503 if (RT_FAILURE(vrc))
504 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
505 break;
506
507 case 'r': // --remember
508 fRemember = true;
509 break;
510
511 case 't': // --type
512 vrc = parseDiskType(ValueUnion.psz, &DiskType);
513 if (RT_FAILURE(vrc))
514 return errorArgument("Invalid hard disk type '%s'", ValueUnion.psz);
515 break;
516
517 case VINF_GETOPT_NOT_OPTION:
518 if (src.isEmpty())
519 src = ValueUnion.psz;
520 else if (dst.isEmpty())
521 dst = ValueUnion.psz;
522 else
523 return errorSyntax(USAGE_CLONEHD, "Invalid parameter '%s'", ValueUnion.psz);
524 break;
525
526 default:
527 if (c > 0)
528 {
529 if (RT_C_IS_GRAPH(c))
530 return errorSyntax(USAGE_CLONEHD, "unhandled option: -%c", c);
531 else
532 return errorSyntax(USAGE_CLONEHD, "unhandled option: %i", c);
533 }
534 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
535 return errorSyntax(USAGE_CLONEHD, "unknown option: %s", ValueUnion.psz);
536 else if (ValueUnion.pDef)
537 return errorSyntax(USAGE_CLONEHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
538 else
539 return errorSyntax(USAGE_CLONEHD, "error: %Rrs", c);
540 }
541 }
542
543 if (src.isEmpty())
544 return errorSyntax(USAGE_CLONEHD, "Mandatory UUID or input file parameter missing");
545 if (dst.isEmpty())
546 return errorSyntax(USAGE_CLONEHD, "Mandatory output file parameter missing");
547
548 ComPtr<IHardDisk> srcDisk;
549 ComPtr<IHardDisk> dstDisk;
550 bool unknown = false;
551
552 /* first guess is that it's a UUID */
553 Guid uuid(Utf8Str(src).raw());
554 rc = a->virtualBox->GetHardDisk(uuid, srcDisk.asOutParam());
555 /* no? then it must be a filename */
556 if (FAILED (rc))
557 {
558 rc = a->virtualBox->FindHardDisk(src, srcDisk.asOutParam());
559 /* no? well, then it's an unkwnown image */
560 if (FAILED (rc))
561 {
562 CHECK_ERROR(a->virtualBox, OpenHardDisk(src, AccessMode_ReadWrite, srcDisk.asOutParam()));
563 if (SUCCEEDED (rc))
564 {
565 unknown = true;
566 }
567 }
568 }
569
570 do
571 {
572 if (!SUCCEEDED(rc))
573 break;
574
575 if (format.isEmpty())
576 {
577 /* get the format of the source hard disk */
578 CHECK_ERROR_BREAK(srcDisk, COMGETTER(Format) (format.asOutParam()));
579 }
580
581 CHECK_ERROR_BREAK(a->virtualBox, CreateHardDisk(format, dst, dstDisk.asOutParam()));
582
583 ComPtr<IProgress> progress;
584 CHECK_ERROR_BREAK(srcDisk, CloneTo(dstDisk, DiskVariant, NULL, progress.asOutParam()));
585
586 showProgress(progress);
587 progress->COMGETTER(ResultCode)(&rc);
588 if (FAILED(rc))
589 {
590 com::ProgressErrorInfo info(progress);
591 if (info.isBasicAvailable())
592 RTPrintf("Error: failed to clone hard disk. Error message: %lS\n", info.getText().raw());
593 else
594 RTPrintf("Error: failed to clone hard disk. No error message available!\n");
595 break;
596 }
597
598 CHECK_ERROR_BREAK(dstDisk, COMGETTER(Id)(uuid.asOutParam()));
599
600 RTPrintf("Clone hard disk created in format '%ls'. UUID: %s\n",
601 format.raw(), uuid.toString().raw());
602 }
603 while (0);
604
605 if (!fRemember && !dstDisk.isNull())
606 {
607 /* forget the created clone */
608 dstDisk->Close();
609 }
610
611 if (unknown)
612 {
613 /* close the unknown hard disk to forget it again */
614 srcDisk->Close();
615 }
616
617 return SUCCEEDED(rc) ? 0 : 1;
618}
619
620static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
621{
622 { "--format", 'o', RTGETOPT_REQ_STRING },
623 { "-format", 'o', RTGETOPT_REQ_STRING },
624 { "--static", 'F', RTGETOPT_REQ_NOTHING },
625 { "-static", 'F', RTGETOPT_REQ_NOTHING },
626 { "--variant", 'm', RTGETOPT_REQ_STRING },
627 { "-variant", 'm', RTGETOPT_REQ_STRING },
628};
629
630int handleConvertFromRaw(int argc, char *argv[])
631{
632 int rc = VINF_SUCCESS;
633 bool fReadFromStdIn = false;
634 const char *format = "VDI";
635 const char *srcfilename = NULL;
636 const char *dstfilename = NULL;
637 const char *filesize = NULL;
638 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
639 void *pvBuf = NULL;
640
641 int c;
642 RTGETOPTUNION ValueUnion;
643 RTGETOPTSTATE GetState;
644 // start at 0 because main() has hacked both the argc and argv given to us
645 RTGetOptInit(&GetState, argc, argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions), 0, 0 /* fFlags */);
646 while ((c = RTGetOpt(&GetState, &ValueUnion)))
647 {
648 switch (c)
649 {
650 case 'o': // --format
651 format = ValueUnion.psz;
652 break;
653
654 case 'm': // --variant
655 HardDiskVariant_T DiskVariant;
656 rc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
657 if (RT_FAILURE(rc))
658 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
659 /// @todo cleaner solution than assuming 1:1 mapping?
660 uImageFlags = (unsigned)DiskVariant;
661 break;
662
663 case VINF_GETOPT_NOT_OPTION:
664 if (!srcfilename)
665 {
666 srcfilename = ValueUnion.psz;
667#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
668 fReadFromStdIn = !strcmp(srcfilename, "stdin");
669#endif
670 }
671 else if (!dstfilename)
672 dstfilename = ValueUnion.psz;
673 else if (fReadFromStdIn && !filesize)
674 filesize = ValueUnion.psz;
675 else
676 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid parameter '%s'", ValueUnion.psz);
677 break;
678
679 default:
680 if (c > 0)
681 {
682 if (RT_C_IS_PRINT(c))
683 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid option -%c", c);
684 else
685 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid option case %i", c);
686 }
687 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
688 return errorSyntax(USAGE_CREATEHD, "unknown option: %s\n", ValueUnion.psz);
689 else if (ValueUnion.pDef)
690 return errorSyntax(USAGE_CONVERTFROMRAW, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
691 else
692 return errorSyntax(USAGE_CONVERTFROMRAW, "error: %Rrs", c);
693 }
694 }
695
696 if (!srcfilename || !dstfilename || (fReadFromStdIn && !filesize))
697 return errorSyntax(USAGE_CONVERTFROMRAW, "Incorrect number of parameters");
698 RTPrintf("Converting from raw image file=\"%s\" to file=\"%s\"...\n",
699 srcfilename, dstfilename);
700
701 PVBOXHDD pDisk = NULL;
702
703 PVDINTERFACE pVDIfs = NULL;
704 VDINTERFACE vdInterfaceError;
705 VDINTERFACEERROR vdInterfaceErrorCallbacks;
706 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
707 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
708 vdInterfaceErrorCallbacks.pfnError = handleVDError;
709
710 rc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
711 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
712 AssertRC(rc);
713
714 /* open raw image file. */
715 RTFILE File;
716 if (fReadFromStdIn)
717 File = 0;
718 else
719 rc = RTFileOpen(&File, srcfilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
720 if (RT_FAILURE(rc))
721 {
722 RTPrintf("File=\"%s\" open error: %Rrf\n", srcfilename, rc);
723 goto out;
724 }
725
726 uint64_t cbFile;
727 /* get image size. */
728 if (fReadFromStdIn)
729 cbFile = RTStrToUInt64(filesize);
730 else
731 rc = RTFileGetSize(File, &cbFile);
732 if (RT_FAILURE(rc))
733 {
734 RTPrintf("Error getting image size for file \"%s\": %Rrc\n", srcfilename, rc);
735 goto out;
736 }
737
738 RTPrintf("Creating %s image with size %RU64 bytes (%RU64MB)...\n", (uImageFlags & VD_IMAGE_FLAGS_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
739 char pszComment[256];
740 RTStrPrintf(pszComment, sizeof(pszComment), "Converted image from %s", srcfilename);
741 rc = VDCreate(pVDIfs, &pDisk);
742 if (RT_FAILURE(rc))
743 {
744 RTPrintf("Error while creating the virtual disk container: %Rrc\n", rc);
745 goto out;
746 }
747
748 Assert(RT_MIN(cbFile / 512 / 16 / 63, 16383) -
749 (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383) == 0);
750 PDMMEDIAGEOMETRY PCHS, LCHS;
751 PCHS.cCylinders = (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383);
752 PCHS.cHeads = 16;
753 PCHS.cSectors = 63;
754 LCHS.cCylinders = 0;
755 LCHS.cHeads = 0;
756 LCHS.cSectors = 0;
757 rc = VDCreateBase(pDisk, format, dstfilename, cbFile,
758 uImageFlags, pszComment, &PCHS, &LCHS, NULL,
759 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
760 if (RT_FAILURE(rc))
761 {
762 RTPrintf("Error while creating the disk image \"%s\": %Rrc\n", dstfilename, rc);
763 goto out;
764 }
765
766 size_t cbBuffer;
767 cbBuffer = _1M;
768 pvBuf = RTMemAlloc(cbBuffer);
769 if (!pvBuf)
770 {
771 rc = VERR_NO_MEMORY;
772 RTPrintf("Not enough memory allocating buffers for image \"%s\": %Rrc\n", dstfilename, rc);
773 goto out;
774 }
775
776 uint64_t offFile;
777 offFile = 0;
778 while (offFile < cbFile)
779 {
780 size_t cbRead;
781 size_t cbToRead;
782 cbRead = 0;
783 cbToRead = cbFile - offFile >= (uint64_t)cbBuffer ?
784 cbBuffer : (size_t) (cbFile - offFile);
785 rc = RTFileRead(File, pvBuf, cbToRead, &cbRead);
786 if (RT_FAILURE(rc) || !cbRead)
787 break;
788 rc = VDWrite(pDisk, offFile, pvBuf, cbRead);
789 if (RT_FAILURE(rc))
790 {
791 RTPrintf("Failed to write to disk image \"%s\": %Rrc\n", dstfilename, rc);
792 goto out;
793 }
794 offFile += cbRead;
795 }
796
797out:
798 if (pvBuf)
799 RTMemFree(pvBuf);
800 if (pDisk)
801 VDClose(pDisk, RT_FAILURE(rc));
802 if (File != NIL_RTFILE)
803 RTFileClose(File);
804
805 return RT_FAILURE(rc);
806}
807
808static const RTGETOPTDEF g_aAddiSCSIDiskOptions[] =
809{
810 { "--server", 's', RTGETOPT_REQ_STRING },
811 { "-server", 's', RTGETOPT_REQ_STRING }, // deprecated
812 { "--target", 'T', RTGETOPT_REQ_STRING },
813 { "-target", 'T', RTGETOPT_REQ_STRING }, // deprecated
814 { "--port", 'p', RTGETOPT_REQ_STRING },
815 { "-port", 'p', RTGETOPT_REQ_STRING }, // deprecated
816 { "--lun", 'l', RTGETOPT_REQ_STRING },
817 { "-lun", 'l', RTGETOPT_REQ_STRING }, // deprecated
818 { "--encodedlun", 'L', RTGETOPT_REQ_STRING },
819 { "-encodedlun", 'L', RTGETOPT_REQ_STRING }, // deprecated
820 { "--username", 'u', RTGETOPT_REQ_STRING },
821 { "-username", 'u', RTGETOPT_REQ_STRING }, // deprecated
822 { "--password", 'P', RTGETOPT_REQ_STRING },
823 { "-password", 'P', RTGETOPT_REQ_STRING }, // deprecated
824 { "--type", 't', RTGETOPT_REQ_STRING },
825 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
826 { "--comment", 'c', RTGETOPT_REQ_STRING },
827 { "-comment", 'c', RTGETOPT_REQ_STRING }, // deprecated
828 { "--intnet", 'I', RTGETOPT_REQ_NOTHING },
829 { "-intnet", 'I', RTGETOPT_REQ_NOTHING }, // deprecated
830};
831
832int handleAddiSCSIDisk(HandlerArg *a)
833{
834 HRESULT rc;
835 int vrc;
836 Bstr server;
837 Bstr target;
838 Bstr port;
839 Bstr lun;
840 Bstr username;
841 Bstr password;
842 Bstr comment;
843 bool fIntNet = false;
844 HardDiskType_T DiskType = HardDiskType_Normal;
845
846 int c;
847 RTGETOPTUNION ValueUnion;
848 RTGETOPTSTATE GetState;
849 // start at 0 because main() has hacked both the argc and argv given to us
850 RTGetOptInit(&GetState, a->argc, a->argv, g_aAddiSCSIDiskOptions, RT_ELEMENTS(g_aAddiSCSIDiskOptions), 0, 0 /* fFlags */);
851 while ((c = RTGetOpt(&GetState, &ValueUnion)))
852 {
853 switch (c)
854 {
855 case 's': // --server
856 server = ValueUnion.psz;
857 break;
858
859 case 'T': // --target
860 target = ValueUnion.psz;
861 break;
862
863 case 'p': // --port
864 port = ValueUnion.psz;
865 break;
866
867 case 'l': // --lun
868 lun = ValueUnion.psz;
869 break;
870
871 case 'L': // --encodedlun
872 lun = BstrFmt("enc%s", ValueUnion.psz);
873 break;
874
875 case 'u': // --username
876 username = ValueUnion.psz;
877 break;
878
879 case 'P': // --password
880 password = ValueUnion.psz;
881 break;
882
883 case 't': // --type
884 vrc = parseDiskType(ValueUnion.psz, &DiskType);
885 if (RT_FAILURE(vrc))
886 return errorArgument("Invalid hard disk type '%s'", ValueUnion.psz);
887 break;
888
889 case 'c': // --comment
890 comment = ValueUnion.psz;
891 break;
892
893 case 'I': // --intnet
894 fIntNet = true;
895 break;
896
897 case VINF_GETOPT_NOT_OPTION:
898 return errorSyntax(USAGE_ADDISCSIDISK, "Invalid parameter '%s'", ValueUnion.psz);
899
900 default:
901 if (c > 0)
902 {
903 if (RT_C_IS_PRINT(c))
904 return errorSyntax(USAGE_ADDISCSIDISK, "Invalid option -%c", c);
905 else
906 return errorSyntax(USAGE_ADDISCSIDISK, "Invalid option case %i", c);
907 }
908 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
909 return errorSyntax(USAGE_ADDISCSIDISK, "unknown option: %s\n", ValueUnion.psz);
910 else if (ValueUnion.pDef)
911 return errorSyntax(USAGE_ADDISCSIDISK, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
912 else
913 return errorSyntax(USAGE_ADDISCSIDISK, "error: %Rrs", c);
914 }
915 }
916
917 /* check for required options */
918 if (!server || !target)
919 return errorSyntax(USAGE_ADDISCSIDISK, "Parameters --server and --target are required");
920
921 do
922 {
923 ComPtr<IHardDisk> hardDisk;
924 /** @todo move the location stuff to Main, which can use pfnComposeName
925 * from the disk backends to construct the location properly. Also do
926 * not use slashes to separate the parts, as otherwise only the last
927 * element comtaining information will be shown. */
928 if (lun.isEmpty() || lun == "0" || lun == "enc0")
929 {
930 CHECK_ERROR_BREAK (a->virtualBox,
931 CreateHardDisk(Bstr ("iSCSI"),
932 BstrFmt ("%ls|%ls", server.raw(), target.raw()),
933 hardDisk.asOutParam()));
934 }
935 else
936 {
937 CHECK_ERROR_BREAK (a->virtualBox,
938 CreateHardDisk(Bstr ("iSCSI"),
939 BstrFmt ("%ls|%ls|%ls", server.raw(), target.raw(), lun.raw()),
940 hardDisk.asOutParam()));
941 }
942 CheckComRCBreakRC (rc);
943
944 if (!comment.isNull())
945 CHECK_ERROR(hardDisk, COMSETTER(Description)(comment));
946
947 if (!port.isNull())
948 server = BstrFmt ("%ls:%ls", server.raw(), port.raw());
949
950 com::SafeArray <BSTR> names;
951 com::SafeArray <BSTR> values;
952
953 Bstr ("TargetAddress").detachTo (names.appendedRaw());
954 server.detachTo (values.appendedRaw());
955 Bstr ("TargetName").detachTo (names.appendedRaw());
956 target.detachTo (values.appendedRaw());
957
958 if (!lun.isNull())
959 {
960 Bstr ("LUN").detachTo (names.appendedRaw());
961 lun.detachTo (values.appendedRaw());
962 }
963 if (!username.isNull())
964 {
965 Bstr ("InitiatorUsername").detachTo (names.appendedRaw());
966 username.detachTo (values.appendedRaw());
967 }
968 if (!password.isNull())
969 {
970 Bstr ("InitiatorSecret").detachTo (names.appendedRaw());
971 password.detachTo (values.appendedRaw());
972 }
973
974 /// @todo add --initiator option
975 Bstr ("InitiatorName").detachTo (names.appendedRaw());
976 Bstr ("iqn.2008-04.com.sun.virtualbox.initiator").detachTo (values.appendedRaw());
977
978 /// @todo add --targetName and --targetPassword options
979
980 if (fIntNet)
981 {
982 Bstr ("HostIPStack").detachTo (names.appendedRaw());
983 Bstr ("0").detachTo (values.appendedRaw());
984 }
985
986 CHECK_ERROR_BREAK (hardDisk,
987 SetProperties (ComSafeArrayAsInParam (names),
988 ComSafeArrayAsInParam (values)));
989
990 if (DiskType != HardDiskType_Normal)
991 {
992 CHECK_ERROR(hardDisk, COMSETTER(Type)(DiskType));
993 }
994
995 Guid guid;
996 CHECK_ERROR(hardDisk, COMGETTER(Id)(guid.asOutParam()));
997 RTPrintf("iSCSI disk created. UUID: %s\n", guid.toString().raw());
998 }
999 while (0);
1000
1001 return SUCCEEDED(rc) ? 0 : 1;
1002}
1003
1004static const RTGETOPTDEF g_aShowHardDiskInfoOptions[] =
1005{
1006 { "--dummy", '\0', RTGETOPT_REQ_NOTHING }, // placeholder for C++
1007};
1008
1009int handleShowHardDiskInfo(HandlerArg *a)
1010{
1011 HRESULT rc;
1012 const char *FilenameOrUuid = NULL;
1013
1014 int c;
1015 RTGETOPTUNION ValueUnion;
1016 RTGETOPTSTATE GetState;
1017 // start at 0 because main() has hacked both the argc and argv given to us
1018 RTGetOptInit(&GetState, a->argc, a->argv, g_aShowHardDiskInfoOptions, RT_ELEMENTS(g_aShowHardDiskInfoOptions), 0, 0 /* fFlags */);
1019 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1020 {
1021 switch (c)
1022 {
1023 case VINF_GETOPT_NOT_OPTION:
1024 if (!FilenameOrUuid)
1025 FilenameOrUuid = ValueUnion.psz;
1026 else
1027 return errorSyntax(USAGE_SHOWHDINFO, "Invalid parameter '%s'", ValueUnion.psz);
1028 break;
1029
1030 default:
1031 if (c > 0)
1032 {
1033 if (RT_C_IS_PRINT(c))
1034 return errorSyntax(USAGE_SHOWHDINFO, "Invalid option -%c", c);
1035 else
1036 return errorSyntax(USAGE_SHOWHDINFO, "Invalid option case %i", c);
1037 }
1038 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1039 return errorSyntax(USAGE_SHOWHDINFO, "unknown option: %s\n", ValueUnion.psz);
1040 else if (ValueUnion.pDef)
1041 return errorSyntax(USAGE_SHOWHDINFO, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1042 else
1043 return errorSyntax(USAGE_SHOWHDINFO, "error: %Rrs", c);
1044 }
1045 }
1046
1047 /* check for required options */
1048 if (!FilenameOrUuid)
1049 return errorSyntax(USAGE_SHOWHDINFO, "Disk name or UUID required");
1050
1051 ComPtr<IHardDisk> hardDisk;
1052 bool unknown = false;
1053 /* first guess is that it's a UUID */
1054 Guid uuid(FilenameOrUuid);
1055 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
1056 /* no? then it must be a filename */
1057 if (FAILED (rc))
1058 {
1059 rc = a->virtualBox->FindHardDisk(Bstr(FilenameOrUuid), hardDisk.asOutParam());
1060 /* no? well, then it's an unkwnown image */
1061 if (FAILED (rc))
1062 {
1063 CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(FilenameOrUuid), AccessMode_ReadWrite, hardDisk.asOutParam()));
1064 if (SUCCEEDED (rc))
1065 {
1066 unknown = true;
1067 }
1068 }
1069 }
1070 do
1071 {
1072 if (!SUCCEEDED(rc))
1073 break;
1074
1075 hardDisk->COMGETTER(Id)(uuid.asOutParam());
1076 RTPrintf("UUID: %s\n", uuid.toString().raw());
1077
1078 /* check for accessibility */
1079 /// @todo NEWMEDIA check accessibility of all parents
1080 /// @todo NEWMEDIA print the full state value
1081 MediaState_T state;
1082 CHECK_ERROR_BREAK (hardDisk, COMGETTER(State)(&state));
1083 RTPrintf("Accessible: %s\n", state != MediaState_Inaccessible ? "yes" : "no");
1084
1085 if (state == MediaState_Inaccessible)
1086 {
1087 Bstr err;
1088 CHECK_ERROR_BREAK (hardDisk, COMGETTER(LastAccessError)(err.asOutParam()));
1089 RTPrintf("Access Error: %lS\n", err.raw());
1090 }
1091
1092 Bstr description;
1093 hardDisk->COMGETTER(Description)(description.asOutParam());
1094 if (description)
1095 {
1096 RTPrintf("Description: %lS\n", description.raw());
1097 }
1098
1099 ULONG64 logicalSize;
1100 hardDisk->COMGETTER(LogicalSize)(&logicalSize);
1101 RTPrintf("Logical size: %llu MBytes\n", logicalSize);
1102 ULONG64 actualSize;
1103 hardDisk->COMGETTER(Size)(&actualSize);
1104 RTPrintf("Current size on disk: %llu MBytes\n", actualSize >> 20);
1105
1106 ComPtr <IHardDisk> parent;
1107 hardDisk->COMGETTER(Parent) (parent.asOutParam());
1108
1109 HardDiskType_T type;
1110 hardDisk->COMGETTER(Type)(&type);
1111 const char *typeStr = "unknown";
1112 switch (type)
1113 {
1114 case HardDiskType_Normal:
1115 if (!parent.isNull())
1116 typeStr = "normal (differencing)";
1117 else
1118 typeStr = "normal (base)";
1119 break;
1120 case HardDiskType_Immutable:
1121 typeStr = "immutable";
1122 break;
1123 case HardDiskType_Writethrough:
1124 typeStr = "writethrough";
1125 break;
1126 }
1127 RTPrintf("Type: %s\n", typeStr);
1128
1129 Bstr format;
1130 hardDisk->COMGETTER(Format)(format.asOutParam());
1131 RTPrintf("Storage format: %lS\n", format.raw());
1132
1133 if (!unknown)
1134 {
1135 com::SafeGUIDArray machineIds;
1136 hardDisk->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
1137 for (size_t j = 0; j < machineIds.size(); ++ j)
1138 {
1139 ComPtr<IMachine> machine;
1140 CHECK_ERROR(a->virtualBox, GetMachine(machineIds[j], machine.asOutParam()));
1141 ASSERT(machine);
1142 Bstr name;
1143 machine->COMGETTER(Name)(name.asOutParam());
1144 machine->COMGETTER(Id)(uuid.asOutParam());
1145 RTPrintf("%s%lS (UUID: %RTuuid)\n",
1146 j == 0 ? "In use by VMs: " : " ",
1147 name.raw(), &machineIds[j]);
1148 }
1149 /// @todo NEWMEDIA check usage in snapshots too
1150 /// @todo NEWMEDIA also list children
1151 }
1152
1153 Bstr loc;
1154 hardDisk->COMGETTER(Location)(loc.asOutParam());
1155 RTPrintf("Location: %lS\n", loc.raw());
1156
1157 /* print out information specific for differencing hard disks */
1158 if (!parent.isNull())
1159 {
1160 BOOL autoReset = FALSE;
1161 hardDisk->COMGETTER(AutoReset)(&autoReset);
1162 RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
1163 }
1164 }
1165 while (0);
1166
1167 if (unknown)
1168 {
1169 /* close the unknown hard disk to forget it again */
1170 hardDisk->Close();
1171 }
1172
1173 return SUCCEEDED(rc) ? 0 : 1;
1174}
1175
1176static const RTGETOPTDEF g_aOpenMediumOptions[] =
1177{
1178 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1179 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1180 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1181 { "--type", 't', RTGETOPT_REQ_STRING },
1182 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
1183};
1184
1185int handleOpenMedium(HandlerArg *a)
1186{
1187 HRESULT rc = S_OK;
1188 int vrc;
1189 enum {
1190 CMD_NONE,
1191 CMD_DISK,
1192 CMD_DVD,
1193 CMD_FLOPPY
1194 } cmd = CMD_NONE;
1195 const char *Filename = NULL;
1196 HardDiskType_T DiskType = HardDiskType_Normal;
1197 bool fDiskType = false;
1198
1199 int c;
1200 RTGETOPTUNION ValueUnion;
1201 RTGETOPTSTATE GetState;
1202 // start at 0 because main() has hacked both the argc and argv given to us
1203 RTGetOptInit(&GetState, a->argc, a->argv, g_aOpenMediumOptions, RT_ELEMENTS(g_aOpenMediumOptions), 0, 0 /* fFlags */);
1204 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1205 {
1206 switch (c)
1207 {
1208 case 'd': // disk
1209 if (cmd != CMD_NONE)
1210 return errorSyntax(USAGE_OPENMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1211 cmd = CMD_DISK;
1212 break;
1213
1214 case 'D': // DVD
1215 if (cmd != CMD_NONE)
1216 return errorSyntax(USAGE_OPENMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1217 cmd = CMD_DVD;
1218 break;
1219
1220 case 'f': // floppy
1221 if (cmd != CMD_NONE)
1222 return errorSyntax(USAGE_OPENMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1223 cmd = CMD_FLOPPY;
1224 break;
1225
1226 case 't': // --type
1227 vrc = parseDiskType(ValueUnion.psz, &DiskType);
1228 if (RT_FAILURE(vrc))
1229 return errorArgument("Invalid hard disk type '%s'", ValueUnion.psz);
1230 fDiskType = true;
1231 break;
1232
1233 case VINF_GETOPT_NOT_OPTION:
1234 if (!Filename)
1235 Filename = ValueUnion.psz;
1236 else
1237 return errorSyntax(USAGE_OPENMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1238 break;
1239
1240 default:
1241 if (c > 0)
1242 {
1243 if (RT_C_IS_PRINT(c))
1244 return errorSyntax(USAGE_OPENMEDIUM, "Invalid option -%c", c);
1245 else
1246 return errorSyntax(USAGE_OPENMEDIUM, "Invalid option case %i", c);
1247 }
1248 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1249 return errorSyntax(USAGE_OPENMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1250 else if (ValueUnion.pDef)
1251 return errorSyntax(USAGE_OPENMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1252 else
1253 return errorSyntax(USAGE_OPENMEDIUM, "error: %Rrs", c);
1254 }
1255 }
1256
1257 /* check for required options */
1258 if (cmd == CMD_NONE)
1259 return errorSyntax(USAGE_OPENMEDIUM, "Command variant disk/dvd/floppy required");
1260 if (!Filename)
1261 return errorSyntax(USAGE_OPENMEDIUM, "Disk name required");
1262
1263 /** @todo remove this hack!
1264 * First try opening the image as is (using the regular API semantics for
1265 * images with relative path or without path), and if that fails with a
1266 * file related error then try it again with what the client thinks the
1267 * relative path would mean. Requires doing the command twice in certain
1268 * cases. This is an ugly hack and needs to be removed whevever we have a
1269 * chance to clean up the API semantics. */
1270 if (cmd == CMD_DISK)
1271 {
1272 ComPtr<IHardDisk> hardDisk;
1273 rc = a->virtualBox->OpenHardDisk(Bstr(Filename), AccessMode_ReadWrite, hardDisk.asOutParam());
1274 if (rc == VBOX_E_FILE_ERROR)
1275 {
1276 char szFilenameAbs[RTPATH_MAX] = "";
1277 int vrc = RTPathAbs(Filename, szFilenameAbs, sizeof(szFilenameAbs));
1278 if (RT_FAILURE(vrc))
1279 {
1280 RTPrintf("Cannot convert filename \"%s\" to absolute path\n", Filename);
1281 return 1;
1282 }
1283 CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(szFilenameAbs), AccessMode_ReadWrite, hardDisk.asOutParam()));
1284 }
1285 else if (FAILED(rc))
1286 CHECK_ERROR(a->virtualBox, OpenHardDisk(Bstr(Filename), AccessMode_ReadWrite, hardDisk.asOutParam()));
1287 if (SUCCEEDED(rc) && hardDisk)
1288 {
1289 /* change the type if requested */
1290 if (DiskType != HardDiskType_Normal)
1291 {
1292 CHECK_ERROR(hardDisk, COMSETTER(Type)(DiskType));
1293 }
1294 }
1295 }
1296 else if (cmd == CMD_DVD)
1297 {
1298 if (fDiskType)
1299 return errorSyntax(USAGE_OPENMEDIUM, "Invalid option for DVD images");
1300 ComPtr<IDVDImage> dvdImage;
1301 rc = a->virtualBox->OpenDVDImage(Bstr(Filename), Guid(), dvdImage.asOutParam());
1302 if (rc == VBOX_E_FILE_ERROR)
1303 {
1304 char szFilenameAbs[RTPATH_MAX] = "";
1305 int vrc = RTPathAbs(Filename, szFilenameAbs, sizeof(szFilenameAbs));
1306 if (RT_FAILURE(vrc))
1307 {
1308 RTPrintf("Cannot convert filename \"%s\" to absolute path\n", Filename);
1309 return 1;
1310 }
1311 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(szFilenameAbs), Guid(), dvdImage.asOutParam()));
1312 }
1313 else if (FAILED(rc))
1314 CHECK_ERROR(a->virtualBox, OpenDVDImage(Bstr(Filename), Guid(), dvdImage.asOutParam()));
1315 }
1316 else if (cmd == CMD_FLOPPY)
1317 {
1318 if (fDiskType)
1319 return errorSyntax(USAGE_OPENMEDIUM, "Invalid option for DVD images");
1320 ComPtr<IFloppyImage> floppyImage;
1321 rc = a->virtualBox->OpenFloppyImage(Bstr(Filename), Guid(), floppyImage.asOutParam());
1322 if (rc == VBOX_E_FILE_ERROR)
1323 {
1324 char szFilenameAbs[RTPATH_MAX] = "";
1325 int vrc = RTPathAbs(Filename, szFilenameAbs, sizeof(szFilenameAbs));
1326 if (RT_FAILURE(vrc))
1327 {
1328 RTPrintf("Cannot convert filename \"%s\" to absolute path\n", Filename);
1329 return 1;
1330 }
1331 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(szFilenameAbs), Guid(), floppyImage.asOutParam()));
1332 }
1333 else if (FAILED(rc))
1334 CHECK_ERROR(a->virtualBox, OpenFloppyImage(Bstr(Filename), Guid(), floppyImage.asOutParam()));
1335 }
1336
1337 return SUCCEEDED(rc) ? 0 : 1;
1338}
1339
1340static const RTGETOPTDEF g_aCloseMediumOptions[] =
1341{
1342 { "disk", 'd', RTGETOPT_REQ_NOTHING },
1343 { "dvd", 'D', RTGETOPT_REQ_NOTHING },
1344 { "floppy", 'f', RTGETOPT_REQ_NOTHING },
1345};
1346
1347int handleCloseMedium(HandlerArg *a)
1348{
1349 HRESULT rc = S_OK;
1350 enum {
1351 CMD_NONE,
1352 CMD_DISK,
1353 CMD_DVD,
1354 CMD_FLOPPY
1355 } cmd = CMD_NONE;
1356 const char *FilenameOrUuid = NULL;
1357
1358 int c;
1359 RTGETOPTUNION ValueUnion;
1360 RTGETOPTSTATE GetState;
1361 // start at 0 because main() has hacked both the argc and argv given to us
1362 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloseMediumOptions, RT_ELEMENTS(g_aCloseMediumOptions), 0, 0 /* fFlags */);
1363 while ((c = RTGetOpt(&GetState, &ValueUnion)))
1364 {
1365 switch (c)
1366 {
1367 case 'd': // disk
1368 if (cmd != CMD_NONE)
1369 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1370 cmd = CMD_DISK;
1371 break;
1372
1373 case 'D': // DVD
1374 if (cmd != CMD_NONE)
1375 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1376 cmd = CMD_DVD;
1377 break;
1378
1379 case 'f': // floppy
1380 if (cmd != CMD_NONE)
1381 return errorSyntax(USAGE_CLOSEMEDIUM, "Only one command can be specified: '%s'", ValueUnion.psz);
1382 cmd = CMD_FLOPPY;
1383 break;
1384
1385 case VINF_GETOPT_NOT_OPTION:
1386 if (!FilenameOrUuid)
1387 FilenameOrUuid = ValueUnion.psz;
1388 else
1389 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid parameter '%s'", ValueUnion.psz);
1390 break;
1391
1392 default:
1393 if (c > 0)
1394 {
1395 if (RT_C_IS_PRINT(c))
1396 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option -%c", c);
1397 else
1398 return errorSyntax(USAGE_CLOSEMEDIUM, "Invalid option case %i", c);
1399 }
1400 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
1401 return errorSyntax(USAGE_CLOSEMEDIUM, "unknown option: %s\n", ValueUnion.psz);
1402 else if (ValueUnion.pDef)
1403 return errorSyntax(USAGE_CLOSEMEDIUM, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
1404 else
1405 return errorSyntax(USAGE_CLOSEMEDIUM, "error: %Rrs", c);
1406 }
1407 }
1408
1409 /* check for required options */
1410 if (cmd == CMD_NONE)
1411 return errorSyntax(USAGE_CLOSEMEDIUM, "Command variant disk/dvd/floppy required");
1412 if (!FilenameOrUuid)
1413 return errorSyntax(USAGE_CLOSEMEDIUM, "Disk name or UUID required");
1414
1415 /* first guess is that it's a UUID */
1416 Guid uuid(FilenameOrUuid);
1417
1418 if (cmd == CMD_DISK)
1419 {
1420 ComPtr<IHardDisk> hardDisk;
1421 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
1422 /* not a UUID or not registered? Then it must be a filename */
1423 if (!hardDisk)
1424 {
1425 CHECK_ERROR(a->virtualBox, FindHardDisk(Bstr(FilenameOrUuid), hardDisk.asOutParam()));
1426 }
1427 if (SUCCEEDED(rc) && hardDisk)
1428 {
1429 CHECK_ERROR(hardDisk, Close());
1430 }
1431 }
1432 else
1433 if (cmd == CMD_DVD)
1434 {
1435 ComPtr<IDVDImage> dvdImage;
1436 rc = a->virtualBox->GetDVDImage(uuid, dvdImage.asOutParam());
1437 /* not a UUID or not registered? Then it must be a filename */
1438 if (!dvdImage)
1439 {
1440 CHECK_ERROR(a->virtualBox, FindDVDImage(Bstr(FilenameOrUuid), dvdImage.asOutParam()));
1441 }
1442 if (SUCCEEDED(rc) && dvdImage)
1443 {
1444 CHECK_ERROR(dvdImage, Close());
1445 }
1446 }
1447 else
1448 if (cmd == CMD_FLOPPY)
1449 {
1450 ComPtr<IFloppyImage> floppyImage;
1451 rc = a->virtualBox->GetFloppyImage(uuid, floppyImage.asOutParam());
1452 /* not a UUID or not registered? Then it must be a filename */
1453 if (!floppyImage)
1454 {
1455 CHECK_ERROR(a->virtualBox, FindFloppyImage(Bstr(FilenameOrUuid), floppyImage.asOutParam()));
1456 }
1457 if (SUCCEEDED(rc) && floppyImage)
1458 {
1459 CHECK_ERROR(floppyImage, Close());
1460 }
1461 }
1462
1463 return SUCCEEDED(rc) ? 0 : 1;
1464}
1465#endif /* !VBOX_ONLY_DOCS */
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