VirtualBox

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

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

VBoxManage: fixed createhd --type shareable

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