VirtualBox

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

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

API/others: Renamed IConsole::discardSavedState to IConsole::forgetSavedState, added parameter. Deleted old IConsole::powerDown, renamed IConsole::powerDownAsync to IConsole::powerDown (as promised for 2.1). Implemented perl sample code for registering a hard disk. Cleaned up constant formatting in the API docs. Updated SDK changelog. Renamed com/errorprint2.h to com/errorprint.h, added a few assertion variants. Eliminated com/errorprint_legacy.h. Adjusted all files using the affected headers and APIs. Renamed tstHeadless2 to tstHeadless.

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