VirtualBox

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

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

Frontends/VBoxManage: client code for cloning to existing image, plus code for legacy --static option which was forgotten

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