VirtualBox

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

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

Automated rebranding to Oracle copyright/license strings via filemuncher

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