VirtualBox

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

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

2nd part of build fix

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