VirtualBox

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

Last change on this file since 31562 was 31562, checked in by vboxsync, 15 years ago

Main: merge IVirtualBox::FindHardDisk, GetHardDisk, FindDVDImage, GetDVDImage, FindFloppyImage and GetFloppyImage into one IVirtualBox::findMedium method

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