VirtualBox

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

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

VBoxHDD/compact: better error handling

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