VirtualBox

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

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

VBoxManage: don't crash on VBoxManage createhd --help

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.0 KB
Line 
1/* $Id: VBoxManageDisk.cpp 18624 2009-04-02 10:09:34Z 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/stream.h>
36#include <iprt/string.h>
37#include <iprt/ctype.h>
38#include <iprt/getopt.h>
39#include <VBox/log.h>
40#include <VBox/VBoxHDD.h>
41
42#include "VBoxManage.h"
43using namespace com;
44
45
46// funcs
47///////////////////////////////////////////////////////////////////////////////
48
49
50static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
51{
52 RTPrintf("ERROR: ");
53 RTPrintfV(pszFormat, va);
54 RTPrintf("\n");
55 RTPrintf("Error code %Rrc at %s(%u) in function %s\n", rc, RT_SRC_POS_ARGS);
56}
57
58
59static int parseDiskVariant(const char *psz, HardDiskVariant_T *pDiskVariant)
60{
61 int rc = VINF_SUCCESS;
62 unsigned DiskVariant = (unsigned)(*pDiskVariant);
63 while (psz && *psz && RT_SUCCESS(rc))
64 {
65 size_t len;
66 const char *pszComma = strchr(psz, ',');
67 if (pszComma)
68 len = pszComma - psz;
69 else
70 len = strlen(psz);
71 if (len > 0)
72 {
73 // Parsing is intentionally inconsistent: "standard" resets the
74 // variant, whereas the other flags are cumulative.
75 if (!RTStrNICmp(psz, "standard", len))
76 DiskVariant = HardDiskVariant_Standard;
77 else if ( !RTStrNICmp(psz, "fixed", len)
78 || !RTStrNICmp(psz, "static", len))
79 DiskVariant |= HardDiskVariant_Fixed;
80 else if (!RTStrNICmp(psz, "Diff", len))
81 DiskVariant |= HardDiskVariant_Diff;
82 else if (!RTStrNICmp(psz, "split2g", len))
83 DiskVariant |= HardDiskVariant_VmdkSplit2G;
84 else if ( !RTStrNICmp(psz, "stream", len)
85 || !RTStrNICmp(psz, "streamoptimized", len))
86 DiskVariant |= HardDiskVariant_VmdkStreamOptimized;
87 else if (!RTStrNICmp(psz, "esx", len))
88 DiskVariant |= HardDiskVariant_VmdkESX;
89 else
90 rc = VERR_PARSE_ERROR;
91 }
92 if (pszComma)
93 psz += len + 1;
94 else
95 psz += len;
96 }
97
98 if (RT_SUCCESS(rc))
99 *pDiskVariant = (HardDiskVariant_T)DiskVariant;
100 return rc;
101}
102
103static int parseDiskType(const char *psz, HardDiskType_T *pDiskType)
104{
105 int rc = VINF_SUCCESS;
106 HardDiskType_T DiskType = HardDiskType_Normal;
107 if (!RTStrICmp(psz, "normal"))
108 DiskType = HardDiskType_Normal;
109 else if (RTStrICmp(psz, "immutable"))
110 DiskType = HardDiskType_Immutable;
111 else if (RTStrICmp(psz, "writethrough"))
112 DiskType = HardDiskType_Writethrough;
113 else
114 rc = VERR_PARSE_ERROR;
115
116 if (RT_SUCCESS(rc))
117 *pDiskType = DiskType;
118 return rc;
119}
120
121static const RTGETOPTDEF g_aCreateHardDiskOptions[] =
122{
123 { "--filename", 'f', RTGETOPT_REQ_STRING },
124 { "-filename", 'f', RTGETOPT_REQ_STRING }, // deprecated
125 { "--size", 's', RTGETOPT_REQ_UINT64 },
126 { "-size", 's', RTGETOPT_REQ_UINT64 }, // deprecated
127 { "--format", 'o', RTGETOPT_REQ_STRING },
128 { "-format", 'o', RTGETOPT_REQ_STRING }, // deprecated
129 { "--static", 'F', RTGETOPT_REQ_NOTHING },
130 { "-static", 'F', RTGETOPT_REQ_NOTHING }, // deprecated
131 { "--variant", 'm', RTGETOPT_REQ_STRING },
132 { "-variant", 'm', RTGETOPT_REQ_STRING }, // deprecated
133 { "--type", 't', RTGETOPT_REQ_STRING },
134 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
135 { "--comment", 'c', RTGETOPT_REQ_STRING },
136 { "-comment", 'c', RTGETOPT_REQ_STRING }, // deprecated
137 { "--remember", 'r', RTGETOPT_REQ_NOTHING },
138 { "-remember", 'r', RTGETOPT_REQ_NOTHING }, // deprecated
139 { "--register", 'r', RTGETOPT_REQ_NOTHING }, // deprecated (inofficial)
140 { "-register", 'r', RTGETOPT_REQ_NOTHING }, // deprecated
141};
142
143int handleCreateHardDisk(HandlerArg *a)
144{
145 HRESULT rc;
146 Bstr filename;
147 uint64_t sizeMB = 0;
148 Bstr format = "VDI";
149 HardDiskVariant_T DiskVariant = HardDiskVariant_Standard;
150 Bstr comment;
151 bool fRemember = false;
152 HardDiskType_T DiskType = HardDiskType_Normal;
153
154 int c;
155 RTGETOPTUNION ValueUnion;
156 RTGETOPTSTATE GetState;
157 // start at 0 because main() has hacked both the argc and argv given to us
158 RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateHardDiskOptions, RT_ELEMENTS(g_aCreateHardDiskOptions), 0, 0 /* fFlags */);
159 while ((c = RTGetOpt(&GetState, &ValueUnion)))
160 {
161 switch (c)
162 {
163 case 'f': // --filename
164 filename = ValueUnion.psz;
165 break;
166
167 case 's': // --size
168 sizeMB = ValueUnion.u64;
169 break;
170
171 case 'o': // --format
172 format = ValueUnion.psz;
173 break;
174
175 case 'F': // --static ("fixed"/"flat")
176 {
177 unsigned uDiskVariant = (unsigned)DiskVariant;
178 uDiskVariant |= HardDiskVariant_Fixed;
179 DiskVariant = (HardDiskVariant_T)uDiskVariant;
180 break;
181 }
182
183 case 'm': // --variant
184 rc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
185 if (RT_FAILURE(rc))
186 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
187 break;
188
189 case 'c': // --comment
190 comment = ValueUnion.psz;
191 break;
192
193 case 'r': // --remember
194 fRemember = true;
195 break;
196
197 case 't': // --type
198 rc = parseDiskType(ValueUnion.psz, &DiskType);
199 if ( RT_FAILURE(rc)
200 || (DiskType != HardDiskType_Normal && DiskType != HardDiskType_Writethrough))
201 return errorArgument("Invalid hard disk type '%s'", ValueUnion.psz);
202 break;
203
204 case VINF_GETOPT_NOT_OPTION:
205 return errorSyntax(USAGE_CREATEHD, "Invalid parameter '%s'", ValueUnion.psz);
206
207 default:
208 if (c > 0)
209 {
210 if (RT_C_IS_PRINT(c))
211 return errorSyntax(USAGE_CREATEHD, "Invalid option -%c", c);
212 else
213 return errorSyntax(USAGE_CREATEHD, "Invalid option case %i", c);
214 }
215 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
216 return errorSyntax(USAGE_CREATEHD, "unknown option: %s\n", ValueUnion.psz);
217 else if (ValueUnion.pDef)
218 return errorSyntax(USAGE_CREATEHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
219 else
220 return errorSyntax(USAGE_CREATEHD, "error: %Rrs", c);
221 }
222 }
223
224 /* check the outcome */
225 if (!filename || (sizeMB == 0))
226 return errorSyntax(USAGE_CREATEHD, "Parameters -filename and -size are required");
227
228 ComPtr<IHardDisk> hardDisk;
229 CHECK_ERROR(a->virtualBox, CreateHardDisk(format, filename, hardDisk.asOutParam()));
230 if (SUCCEEDED(rc) && hardDisk)
231 {
232 /* we will close the hard disk after the storage has been successfully
233 * created unless fRemember is set */
234 bool doClose = false;
235
236 if (!comment.isNull())
237 {
238 CHECK_ERROR(hardDisk,COMSETTER(Description)(comment));
239 }
240 ComPtr<IProgress> progress;
241 CHECK_ERROR(hardDisk, CreateBaseStorage(sizeMB, DiskVariant, progress.asOutParam()));
242 if (SUCCEEDED(rc) && progress)
243 {
244 showProgress(progress);
245 if (SUCCEEDED(rc))
246 {
247 progress->COMGETTER(ResultCode)(&rc);
248 if (FAILED(rc))
249 {
250 com::ProgressErrorInfo info(progress);
251 if (info.isBasicAvailable())
252 RTPrintf("Error: failed to create hard disk. Error message: %lS\n", info.getText().raw());
253 else
254 RTPrintf("Error: failed to create hard disk. No error message available!\n");
255 }
256 else
257 {
258 doClose = !fRemember;
259
260 Guid uuid;
261 CHECK_ERROR(hardDisk, COMGETTER(Id)(uuid.asOutParam()));
262
263 if (DiskType == HardDiskType_Writethrough)
264 {
265 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Writethrough));
266 }
267
268 RTPrintf("Disk image created. UUID: %s\n", uuid.toString().raw());
269 }
270 }
271 }
272 if (doClose)
273 {
274 CHECK_ERROR(hardDisk, Close());
275 }
276 }
277 return SUCCEEDED(rc) ? 0 : 1;
278}
279
280#if 0 /* disabled until disk shrinking is implemented based on VBoxHDD */
281static DECLCALLBACK(int) hardDiskProgressCallback(PVM pVM, unsigned uPercent, void *pvUser)
282{
283 unsigned *pPercent = (unsigned *)pvUser;
284
285 if (*pPercent != uPercent)
286 {
287 *pPercent = uPercent;
288 RTPrintf(".");
289 if ((uPercent % 10) == 0 && uPercent)
290 RTPrintf("%d%%", uPercent);
291 RTStrmFlush(g_pStdOut);
292 }
293
294 return VINF_SUCCESS;
295}
296#endif
297
298
299int handleModifyHardDisk(HandlerArg *a)
300{
301 HRESULT rc;
302
303 /* The uuid/filename and a command */
304 if (a->argc < 2)
305 return errorSyntax(USAGE_MODIFYHD, "Incorrect number of parameters");
306
307 ComPtr<IHardDisk> hardDisk;
308 Bstr filepath;
309
310 /* first guess is that it's a UUID */
311 Guid uuid(a->argv[0]);
312 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
313 /* no? then it must be a filename */
314 if (!hardDisk)
315 {
316 filepath = a->argv[0];
317 CHECK_ERROR(a->virtualBox, FindHardDisk(filepath, hardDisk.asOutParam()));
318 if (FAILED(rc))
319 return 1;
320 }
321
322 /* let's find out which command */
323 if (strcmp(a->argv[1], "settype") == 0)
324 {
325 /* hard disk must be registered */
326 if (SUCCEEDED(rc) && hardDisk)
327 {
328 char *type = NULL;
329
330 if (a->argc <= 2)
331 return errorArgument("Missing argument for settype");
332
333 type = a->argv[2];
334
335 HardDiskType_T hddType;
336 CHECK_ERROR(hardDisk, COMGETTER(Type)(&hddType));
337
338 if (strcmp(type, "normal") == 0)
339 {
340 if (hddType != HardDiskType_Normal)
341 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Normal));
342 }
343 else if (strcmp(type, "writethrough") == 0)
344 {
345 if (hddType != HardDiskType_Writethrough)
346 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Writethrough));
347
348 }
349 else if (strcmp(type, "immutable") == 0)
350 {
351 if (hddType != HardDiskType_Immutable)
352 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Immutable));
353 }
354 else
355 {
356 return errorArgument("Invalid hard disk type '%s' specified", Utf8Str(type).raw());
357 }
358 }
359 else
360 return errorArgument("Hard disk image not registered");
361 }
362 else if (strcmp(a->argv[1], "autoreset") == 0)
363 {
364 char *onOff = NULL;
365
366 if (a->argc <= 2)
367 return errorArgument("Missing argument for autoreset");
368
369 onOff = a->argv[2];
370
371 if (strcmp(onOff, "on") == 0)
372 {
373 CHECK_ERROR(hardDisk, COMSETTER(AutoReset)(TRUE));
374 }
375 else if (strcmp(onOff, "off") == 0)
376 {
377 CHECK_ERROR(hardDisk, COMSETTER(AutoReset)(FALSE));
378 }
379 else
380 {
381 return errorArgument("Invalid autoreset argument '%s' specified",
382 Utf8Str(onOff).raw());
383 }
384 }
385 else if (strcmp(a->argv[1], "compact") == 0)
386 {
387#if 1
388 RTPrintf("Error: Shrink hard disk operation is not implemented!\n");
389 return 1;
390#else
391 /* the hard disk image might not be registered */
392 if (!hardDisk)
393 {
394 a->virtualBox->OpenHardDisk(Bstr(a->argv[0]), AccessMode_ReadWrite, hardDisk.asOutParam());
395 if (!hardDisk)
396 return errorArgument("Hard disk image not found");
397 }
398
399 Bstr format;
400 hardDisk->COMGETTER(Format)(format.asOutParam());
401 if (format != "VDI")
402 return errorArgument("Invalid hard disk type. The command only works on VDI files\n");
403
404 Bstr fileName;
405 hardDisk->COMGETTER(Location)(fileName.asOutParam());
406
407 /* make sure the object reference is released */
408 hardDisk = NULL;
409
410 unsigned uProcent;
411
412 RTPrintf("Shrinking '%lS': 0%%", fileName.raw());
413 int vrc = VDIShrinkImage(Utf8Str(fileName).raw(), hardDiskProgressCallback, &uProcent);
414 if (RT_FAILURE(vrc))
415 {
416 RTPrintf("Error while shrinking hard disk image: %Rrc\n", vrc);
417 rc = E_FAIL;
418 }
419#endif
420 }
421 else
422 return errorSyntax(USAGE_MODIFYHD, "Invalid parameter '%s'", Utf8Str(a->argv[1]).raw());
423
424 return SUCCEEDED(rc) ? 0 : 1;
425}
426
427static const RTGETOPTDEF g_aCloneHardDiskOptions[] =
428{
429 { "--format", 'o', RTGETOPT_REQ_STRING },
430 { "-format", 'o', RTGETOPT_REQ_STRING },
431 { "--static", 'F', RTGETOPT_REQ_NOTHING },
432 { "-static", 'F', RTGETOPT_REQ_NOTHING },
433 { "--variant", 'm', RTGETOPT_REQ_STRING },
434 { "-variant", 'm', RTGETOPT_REQ_STRING },
435 { "--type", 't', RTGETOPT_REQ_STRING },
436 { "-type", 't', RTGETOPT_REQ_STRING },
437 { "--remember", 'r', RTGETOPT_REQ_NOTHING },
438 { "-remember", 'r', RTGETOPT_REQ_NOTHING },
439 { "--register", 'r', RTGETOPT_REQ_NOTHING },
440 { "-register", 'r', RTGETOPT_REQ_NOTHING },
441};
442
443int handleCloneHardDisk(HandlerArg *a)
444{
445 Bstr src, dst;
446 Bstr format;
447 HardDiskVariant_T DiskVariant = HardDiskVariant_Standard;
448 bool fRemember = false;
449 HardDiskType_T DiskType = HardDiskType_Normal;
450
451 HRESULT rc;
452
453 int c;
454 RTGETOPTUNION ValueUnion;
455 RTGETOPTSTATE GetState;
456 // start at 0 because main() has hacked both the argc and argv given to us
457 RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneHardDiskOptions, RT_ELEMENTS(g_aCloneHardDiskOptions), 0, 0 /* fFlags */);
458 while ((c = RTGetOpt(&GetState, &ValueUnion)))
459 {
460 switch (c)
461 {
462 case 'o': // --format
463 format = ValueUnion.psz;
464 break;
465
466 case 'm': // --variant
467 rc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
468 if (RT_FAILURE(rc))
469 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
470 break;
471
472 case 'r': // --remember
473 fRemember = true;
474 break;
475
476 case 't': // --type
477 rc = parseDiskType(ValueUnion.psz, &DiskType);
478 if (RT_FAILURE(rc))
479 return errorArgument("Invalid hard disk type '%s'", ValueUnion.psz);
480 break;
481
482 case VINF_GETOPT_NOT_OPTION:
483 if (src.isEmpty())
484 src = ValueUnion.psz;
485 else if (dst.isEmpty())
486 dst = ValueUnion.psz;
487 else
488 return errorSyntax(USAGE_CLONEHD, "Invalid parameter '%s'", ValueUnion.psz);
489 break;
490
491 default:
492 if (c > 0)
493 {
494 if (RT_C_IS_GRAPH(c))
495 return errorSyntax(USAGE_CLONEHD, "unhandled option: -%c", c);
496 else
497 return errorSyntax(USAGE_CLONEHD, "unhandled option: %i", c);
498 }
499 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
500 return errorSyntax(USAGE_CLONEHD, "unknown option: %s", ValueUnion.psz);
501 else if (ValueUnion.pDef)
502 return errorSyntax(USAGE_CLONEHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
503 else
504 return errorSyntax(USAGE_CLONEHD, "error: %Rrs", c);
505 }
506 }
507
508 if (src.isEmpty())
509 return errorSyntax(USAGE_CLONEHD, "Mandatory UUID or input file parameter missing");
510 if (dst.isEmpty())
511 return errorSyntax(USAGE_CLONEHD, "Mandatory output file parameter missing");
512
513 ComPtr<IHardDisk> srcDisk;
514 ComPtr<IHardDisk> dstDisk;
515 bool unknown = false;
516
517 /* first guess is that it's a UUID */
518 Guid uuid(Utf8Str(src).raw());
519 rc = a->virtualBox->GetHardDisk(uuid, srcDisk.asOutParam());
520 /* no? then it must be a filename */
521 if (FAILED (rc))
522 {
523 rc = a->virtualBox->FindHardDisk(src, srcDisk.asOutParam());
524 /* no? well, then it's an unkwnown image */
525 if (FAILED (rc))
526 {
527 CHECK_ERROR(a->virtualBox, OpenHardDisk(src, AccessMode_ReadWrite, srcDisk.asOutParam()));
528 if (SUCCEEDED (rc))
529 {
530 unknown = true;
531 }
532 }
533 }
534
535 do
536 {
537 if (!SUCCEEDED(rc))
538 break;
539
540 if (format.isEmpty())
541 {
542 /* get the format of the source hard disk */
543 CHECK_ERROR_BREAK(srcDisk, COMGETTER(Format) (format.asOutParam()));
544 }
545
546 CHECK_ERROR_BREAK(a->virtualBox, CreateHardDisk(format, dst, dstDisk.asOutParam()));
547
548 ComPtr<IProgress> progress;
549 CHECK_ERROR_BREAK(srcDisk, CloneTo(dstDisk, DiskVariant, NULL, progress.asOutParam()));
550
551 showProgress(progress);
552 progress->COMGETTER(ResultCode)(&rc);
553 if (FAILED(rc))
554 {
555 com::ProgressErrorInfo info(progress);
556 if (info.isBasicAvailable())
557 RTPrintf("Error: failed to clone hard disk. Error message: %lS\n", info.getText().raw());
558 else
559 RTPrintf("Error: failed to clone hard disk. No error message available!\n");
560 break;
561 }
562
563 CHECK_ERROR_BREAK(dstDisk, COMGETTER(Id)(uuid.asOutParam()));
564
565 RTPrintf("Clone hard disk created in format '%ls'. UUID: %s\n",
566 format.raw(), uuid.toString().raw());
567 }
568 while (0);
569
570 if (!fRemember && !dstDisk.isNull())
571 {
572 /* forget the created clone */
573 dstDisk->Close();
574 }
575
576 if (unknown)
577 {
578 /* close the unknown hard disk to forget it again */
579 srcDisk->Close();
580 }
581
582 return SUCCEEDED(rc) ? 0 : 1;
583}
584
585static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
586{
587 { "--format", 'o', RTGETOPT_REQ_STRING },
588 { "-format", 'o', RTGETOPT_REQ_STRING },
589 { "--static", 'F', RTGETOPT_REQ_NOTHING },
590 { "-static", 'F', RTGETOPT_REQ_NOTHING },
591 { "--variant", 'm', RTGETOPT_REQ_STRING },
592 { "-variant", 'm', RTGETOPT_REQ_STRING },
593};
594
595int handleConvertFromRaw(int argc, char *argv[])
596{
597 int rc = VINF_SUCCESS;
598 bool fReadFromStdIn = false;
599 const char *format = "VDI";
600 const char *srcfilename = NULL;
601 const char *dstfilename = NULL;
602 const char *filesize = NULL;
603 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
604 void *pvBuf = NULL;
605
606 int c;
607 RTGETOPTUNION ValueUnion;
608 RTGETOPTSTATE GetState;
609 // start at 0 because main() has hacked both the argc and argv given to us
610 RTGetOptInit(&GetState, argc, argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions), 0, 0 /* fFlags */);
611 while ((c = RTGetOpt(&GetState, &ValueUnion)))
612 {
613 switch (c)
614 {
615 case 'o': // --format
616 format = ValueUnion.psz;
617 break;
618
619 case 'm': // --variant
620 HardDiskVariant_T DiskVariant;
621 rc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
622 if (RT_FAILURE(rc))
623 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
624 /// @todo cleaner solution than assuming 1:1 mapping?
625 uImageFlags = (unsigned)DiskVariant;
626 break;
627
628 case VINF_GETOPT_NOT_OPTION:
629 if (!srcfilename)
630 {
631 srcfilename = ValueUnion.psz;
632#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
633 fReadFromStdIn = !strcmp(srcfilename, "stdin");
634#endif
635 }
636 else if (!dstfilename)
637 dstfilename = ValueUnion.psz;
638 else if (fReadFromStdIn && !filesize)
639 filesize = ValueUnion.psz;
640 else
641 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid parameter '%s'", ValueUnion.psz);
642 break;
643
644 default:
645 if (c > 0)
646 {
647 if (RT_C_IS_PRINT(c))
648 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid option -%c", c);
649 else
650 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid option case %i", c);
651 }
652 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
653 return errorSyntax(USAGE_CREATEHD, "unknown option: %s\n", ValueUnion.psz);
654 else if (ValueUnion.pDef)
655 return errorSyntax(USAGE_CONVERTFROMRAW, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
656 else
657 return errorSyntax(USAGE_CONVERTFROMRAW, "error: %Rrs", c);
658 }
659 }
660
661 if (!srcfilename || !dstfilename || (fReadFromStdIn && !filesize))
662 return errorSyntax(USAGE_CONVERTFROMRAW, "Incorrect number of parameters");
663 RTPrintf("Converting from raw image file=\"%s\" to file=\"%s\"...\n",
664 srcfilename, dstfilename);
665
666 PVBOXHDD pDisk = NULL;
667
668 PVDINTERFACE pVDIfs = NULL;
669 VDINTERFACE vdInterfaceError;
670 VDINTERFACEERROR vdInterfaceErrorCallbacks;
671 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
672 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
673 vdInterfaceErrorCallbacks.pfnError = handleVDError;
674
675 rc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
676 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
677 AssertRC(rc);
678
679 /* open raw image file. */
680 RTFILE File;
681 if (fReadFromStdIn)
682 File = 0;
683 else
684 rc = RTFileOpen(&File, srcfilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
685 if (RT_FAILURE(rc))
686 {
687 RTPrintf("File=\"%s\" open error: %Rrf\n", srcfilename, rc);
688 goto out;
689 }
690
691 uint64_t cbFile;
692 /* get image size. */
693 if (fReadFromStdIn)
694 cbFile = RTStrToUInt64(filesize);
695 else
696 rc = RTFileGetSize(File, &cbFile);
697 if (RT_FAILURE(rc))
698 {
699 RTPrintf("Error getting image size for file \"%s\": %Rrc\n", srcfilename, rc);
700 goto out;
701 }
702
703 RTPrintf("Creating %s image with size %RU64 bytes (%RU64MB)...\n", (uImageFlags & VD_IMAGE_FLAGS_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
704 char pszComment[256];
705 RTStrPrintf(pszComment, sizeof(pszComment), "Converted image from %s", srcfilename);
706 rc = VDCreate(pVDIfs, &pDisk);
707 if (RT_FAILURE(rc))
708 {
709 RTPrintf("Error while creating the virtual disk container: %Rrc\n", rc);
710 goto out;
711 }
712
713 Assert(RT_MIN(cbFile / 512 / 16 / 63, 16383) -
714 (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383) == 0);
715 PDMMEDIAGEOMETRY PCHS, LCHS;
716 PCHS.cCylinders = (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383);
717 PCHS.cHeads = 16;
718 PCHS.cSectors = 63;
719 LCHS.cCylinders = 0;
720 LCHS.cHeads = 0;
721 LCHS.cSectors = 0;
722 rc = VDCreateBase(pDisk, format, dstfilename, cbFile,
723 uImageFlags, pszComment, &PCHS, &LCHS, NULL,
724 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
725 if (RT_FAILURE(rc))
726 {
727 RTPrintf("Error while creating the disk image \"%s\": %Rrc\n", dstfilename, rc);
728 goto out;
729 }
730
731 size_t cbBuffer;
732 cbBuffer = _1M;
733 pvBuf = RTMemAlloc(cbBuffer);
734 if (!pvBuf)
735 {
736 rc = VERR_NO_MEMORY;
737 RTPrintf("Not enough memory allocating buffers for image \"%s\": %Rrc\n", dstfilename, rc);
738 goto out;
739 }
740
741 uint64_t offFile;
742 offFile = 0;
743 while (offFile < cbFile)
744 {
745 size_t cbRead;
746 size_t cbToRead;
747 cbRead = 0;
748 cbToRead = cbFile - offFile >= (uint64_t)cbBuffer ?
749 cbBuffer : (size_t) (cbFile - offFile);
750 rc = RTFileRead(File, pvBuf, cbToRead, &cbRead);
751 if (RT_FAILURE(rc) || !cbRead)
752 break;
753 rc = VDWrite(pDisk, offFile, pvBuf, cbRead);
754 if (RT_FAILURE(rc))
755 {
756 RTPrintf("Failed to write to disk image \"%s\": %Rrc\n", dstfilename, rc);
757 goto out;
758 }
759 offFile += cbRead;
760 }
761
762out:
763 if (pvBuf)
764 RTMemFree(pvBuf);
765 if (pDisk)
766 VDClose(pDisk, RT_FAILURE(rc));
767 if (File != NIL_RTFILE)
768 RTFileClose(File);
769
770 return RT_FAILURE(rc);
771}
772
773int handleAddiSCSIDisk(HandlerArg *a)
774{
775 HRESULT rc;
776 Bstr server;
777 Bstr target;
778 Bstr port;
779 Bstr lun;
780 Bstr username;
781 Bstr password;
782 Bstr comment;
783 bool fIntNet = false;
784
785 /* at least server and target */
786 if (a->argc < 4)
787 return errorSyntax(USAGE_ADDISCSIDISK, "Not enough parameters");
788
789 /* let's have a closer look at the arguments */
790 for (int i = 0; i < a->argc; i++)
791 {
792 if (strcmp(a->argv[i], "-server") == 0)
793 {
794 if (a->argc <= i + 1)
795 return errorArgument("Missing argument to '%s'", a->argv[i]);
796 i++;
797 server = a->argv[i];
798 }
799 else if (strcmp(a->argv[i], "-target") == 0)
800 {
801 if (a->argc <= i + 1)
802 return errorArgument("Missing argument to '%s'", a->argv[i]);
803 i++;
804 target = a->argv[i];
805 }
806 else if (strcmp(a->argv[i], "-port") == 0)
807 {
808 if (a->argc <= i + 1)
809 return errorArgument("Missing argument to '%s'", a->argv[i]);
810 i++;
811 port = a->argv[i];
812 }
813 else if (strcmp(a->argv[i], "-lun") == 0)
814 {
815 if (a->argc <= i + 1)
816 return errorArgument("Missing argument to '%s'", a->argv[i]);
817 i++;
818 lun = a->argv[i];
819 }
820 else if (strcmp(a->argv[i], "-encodedlun") == 0)
821 {
822 if (a->argc <= i + 1)
823 return errorArgument("Missing argument to '%s'", a->argv[i]);
824 i++;
825 lun = BstrFmt("enc%s", a->argv[i]);
826 }
827 else if (strcmp(a->argv[i], "-username") == 0)
828 {
829 if (a->argc <= i + 1)
830 return errorArgument("Missing argument to '%s'", a->argv[i]);
831 i++;
832 username = a->argv[i];
833 }
834 else if (strcmp(a->argv[i], "-password") == 0)
835 {
836 if (a->argc <= i + 1)
837 return errorArgument("Missing argument to '%s'", a->argv[i]);
838 i++;
839 password = a->argv[i];
840 }
841 else if (strcmp(a->argv[i], "-comment") == 0)
842 {
843 if (a->argc <= i + 1)
844 return errorArgument("Missing argument to '%s'", a->argv[i]);
845 i++;
846 comment = a->argv[i];
847 }
848 else if (strcmp(a->argv[i], "-intnet") == 0)
849 {
850 i++;
851 fIntNet = true;
852 }
853 else
854 return errorSyntax(USAGE_ADDISCSIDISK, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
855 }
856
857 /* check for required options */
858 if (!server || !target)
859 return errorSyntax(USAGE_ADDISCSIDISK, "Parameters -server and -target are required");
860
861 do
862 {
863 ComPtr<IHardDisk> hardDisk;
864 /** @todo move the location stuff to Main, which can use pfnComposeName
865 * from the disk backends to construct the location properly. */
866 CHECK_ERROR_BREAK (a->virtualBox,
867 CreateHardDisk(Bstr ("iSCSI"),
868 BstrFmt ("%ls/%ls/%ls", server.raw(), target.raw(), lun.raw()),
869 hardDisk.asOutParam()));
870 CheckComRCBreakRC (rc);
871
872 if (!comment.isNull())
873 CHECK_ERROR_BREAK(hardDisk, COMSETTER(Description)(comment));
874
875 if (!port.isNull())
876 server = BstrFmt ("%ls:%ls", server.raw(), port.raw());
877
878 com::SafeArray <BSTR> names;
879 com::SafeArray <BSTR> values;
880
881 Bstr ("TargetAddress").detachTo (names.appendedRaw());
882 server.detachTo (values.appendedRaw());
883 Bstr ("TargetName").detachTo (names.appendedRaw());
884 target.detachTo (values.appendedRaw());
885
886 if (!lun.isNull())
887 {
888 Bstr ("LUN").detachTo (names.appendedRaw());
889 lun.detachTo (values.appendedRaw());
890 }
891 if (!username.isNull())
892 {
893 Bstr ("InitiatorUsername").detachTo (names.appendedRaw());
894 username.detachTo (values.appendedRaw());
895 }
896 if (!password.isNull())
897 {
898 Bstr ("InitiatorSecret").detachTo (names.appendedRaw());
899 password.detachTo (values.appendedRaw());
900 }
901
902 /// @todo add -initiator option
903 Bstr ("InitiatorName").detachTo (names.appendedRaw());
904 Bstr ("iqn.2008-04.com.sun.virtualbox.initiator").detachTo (values.appendedRaw());
905
906 /// @todo add -targetName and -targetPassword options
907
908 if (fIntNet)
909 {
910 Bstr ("HostIPStack").detachTo (names.appendedRaw());
911 Bstr ("0").detachTo (values.appendedRaw());
912 }
913
914 CHECK_ERROR_BREAK (hardDisk,
915 SetProperties (ComSafeArrayAsInParam (names),
916 ComSafeArrayAsInParam (values)));
917
918 Guid guid;
919 CHECK_ERROR(hardDisk, COMGETTER(Id)(guid.asOutParam()));
920 RTPrintf("iSCSI disk created. UUID: %s\n", guid.toString().raw());
921 }
922 while (0);
923
924 return SUCCEEDED(rc) ? 0 : 1;
925}
926
927
928int handleShowHardDiskInfo(HandlerArg *a)
929{
930 HRESULT rc;
931
932 if (a->argc != 1)
933 return errorSyntax(USAGE_SHOWHDINFO, "Incorrect number of parameters");
934
935 ComPtr<IHardDisk> hardDisk;
936 Bstr filepath;
937
938 bool unknown = false;
939
940 /* first guess is that it's a UUID */
941 Guid uuid(a->argv[0]);
942 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
943 /* no? then it must be a filename */
944 if (FAILED (rc))
945 {
946 filepath = a->argv[0];
947 rc = a->virtualBox->FindHardDisk(filepath, hardDisk.asOutParam());
948 /* no? well, then it's an unkwnown image */
949 if (FAILED (rc))
950 {
951 CHECK_ERROR(a->virtualBox, OpenHardDisk(filepath, AccessMode_ReadWrite, hardDisk.asOutParam()));
952 if (SUCCEEDED (rc))
953 {
954 unknown = true;
955 }
956 }
957 }
958 do
959 {
960 if (!SUCCEEDED(rc))
961 break;
962
963 hardDisk->COMGETTER(Id)(uuid.asOutParam());
964 RTPrintf("UUID: %s\n", uuid.toString().raw());
965
966 /* check for accessibility */
967 /// @todo NEWMEDIA check accessibility of all parents
968 /// @todo NEWMEDIA print the full state value
969 MediaState_T state;
970 CHECK_ERROR_BREAK (hardDisk, COMGETTER(State)(&state));
971 RTPrintf("Accessible: %s\n", state != MediaState_Inaccessible ? "yes" : "no");
972
973 if (state == MediaState_Inaccessible)
974 {
975 Bstr err;
976 CHECK_ERROR_BREAK (hardDisk, COMGETTER(LastAccessError)(err.asOutParam()));
977 RTPrintf("Access Error: %lS\n", err.raw());
978 }
979
980 Bstr description;
981 hardDisk->COMGETTER(Description)(description.asOutParam());
982 if (description)
983 {
984 RTPrintf("Description: %lS\n", description.raw());
985 }
986
987 ULONG64 logicalSize;
988 hardDisk->COMGETTER(LogicalSize)(&logicalSize);
989 RTPrintf("Logical size: %llu MBytes\n", logicalSize);
990 ULONG64 actualSize;
991 hardDisk->COMGETTER(Size)(&actualSize);
992 RTPrintf("Current size on disk: %llu MBytes\n", actualSize >> 20);
993
994 ComPtr <IHardDisk> parent;
995 hardDisk->COMGETTER(Parent) (parent.asOutParam());
996
997 HardDiskType_T type;
998 hardDisk->COMGETTER(Type)(&type);
999 const char *typeStr = "unknown";
1000 switch (type)
1001 {
1002 case HardDiskType_Normal:
1003 if (!parent.isNull())
1004 typeStr = "normal (differencing)";
1005 else
1006 typeStr = "normal (base)";
1007 break;
1008 case HardDiskType_Immutable:
1009 typeStr = "immutable";
1010 break;
1011 case HardDiskType_Writethrough:
1012 typeStr = "writethrough";
1013 break;
1014 }
1015 RTPrintf("Type: %s\n", typeStr);
1016
1017 Bstr format;
1018 hardDisk->COMGETTER(Format)(format.asOutParam());
1019 RTPrintf("Storage format: %lS\n", format.raw());
1020
1021 if (!unknown)
1022 {
1023 com::SafeGUIDArray machineIds;
1024 hardDisk->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
1025 for (size_t j = 0; j < machineIds.size(); ++ j)
1026 {
1027 ComPtr<IMachine> machine;
1028 CHECK_ERROR(a->virtualBox, GetMachine(machineIds[j], machine.asOutParam()));
1029 ASSERT(machine);
1030 Bstr name;
1031 machine->COMGETTER(Name)(name.asOutParam());
1032 machine->COMGETTER(Id)(uuid.asOutParam());
1033 RTPrintf("%s%lS (UUID: %RTuuid)\n",
1034 j == 0 ? "In use by VMs: " : " ",
1035 name.raw(), &machineIds[j]);
1036 }
1037 /// @todo NEWMEDIA check usage in snapshots too
1038 /// @todo NEWMEDIA also list children
1039 }
1040
1041 Bstr loc;
1042 hardDisk->COMGETTER(Location)(loc.asOutParam());
1043 RTPrintf("Location: %lS\n", loc.raw());
1044
1045 /* print out information specific for differencing hard disks */
1046 if (!parent.isNull())
1047 {
1048 BOOL autoReset = FALSE;
1049 hardDisk->COMGETTER(AutoReset)(&autoReset);
1050 RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
1051 }
1052 }
1053 while (0);
1054
1055 if (unknown)
1056 {
1057 /* close the unknown hard disk to forget it again */
1058 hardDisk->Close();
1059 }
1060
1061 return SUCCEEDED(rc) ? 0 : 1;
1062}
1063
1064int handleOpenMedium(HandlerArg *a)
1065{
1066 HRESULT rc;
1067
1068 if (a->argc < 2)
1069 return errorSyntax(USAGE_REGISTERIMAGE, "Not enough parameters");
1070
1071 Bstr filepath(a->argv[1]);
1072
1073 if (strcmp(a->argv[0], "disk") == 0)
1074 {
1075 const char *type = NULL;
1076 /* there can be a type parameter */
1077 if ((a->argc > 2) && (a->argc != 4))
1078 return errorSyntax(USAGE_REGISTERIMAGE, "Incorrect number of parameters");
1079 if (a->argc == 4)
1080 {
1081 if (strcmp(a->argv[2], "-type") != 0)
1082 return errorSyntax(USAGE_REGISTERIMAGE, "Invalid parameter '%s'", Utf8Str(a->argv[2]).raw());
1083 if ( (strcmp(a->argv[3], "normal") != 0)
1084 && (strcmp(a->argv[3], "immutable") != 0)
1085 && (strcmp(a->argv[3], "writethrough") != 0))
1086 return errorArgument("Invalid hard disk type '%s' specified", Utf8Str(a->argv[3]).raw());
1087 type = a->argv[3];
1088 }
1089
1090 ComPtr<IHardDisk> hardDisk;
1091 CHECK_ERROR(a->virtualBox, OpenHardDisk(filepath, AccessMode_ReadWrite, hardDisk.asOutParam()));
1092 if (SUCCEEDED(rc) && hardDisk)
1093 {
1094 /* change the type if requested */
1095 if (type)
1096 {
1097 if (strcmp(type, "normal") == 0)
1098 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Normal));
1099 else if (strcmp(type, "immutable") == 0)
1100 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Immutable));
1101 else if (strcmp(type, "writethrough") == 0)
1102 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Writethrough));
1103 }
1104 }
1105 }
1106 else if (strcmp(a->argv[0], "dvd") == 0)
1107 {
1108 ComPtr<IDVDImage> dvdImage;
1109 CHECK_ERROR(a->virtualBox, OpenDVDImage(filepath, Guid(), dvdImage.asOutParam()));
1110 }
1111 else if (strcmp(a->argv[0], "floppy") == 0)
1112 {
1113 ComPtr<IFloppyImage> floppyImage;
1114 CHECK_ERROR(a->virtualBox, OpenFloppyImage(filepath, Guid(), floppyImage.asOutParam()));
1115 }
1116 else
1117 return errorSyntax(USAGE_REGISTERIMAGE, "Invalid parameter '%s'", Utf8Str(a->argv[1]).raw());
1118
1119 return SUCCEEDED(rc) ? 0 : 1;
1120}
1121
1122int handleCloseMedium(HandlerArg *a)
1123{
1124 HRESULT rc;
1125
1126 if (a->argc != 2)
1127 return errorSyntax(USAGE_UNREGISTERIMAGE, "Incorrect number of parameters");
1128
1129 /* first guess is that it's a UUID */
1130 Guid uuid(a->argv[1]);
1131
1132 if (strcmp(a->argv[0], "disk") == 0)
1133 {
1134 ComPtr<IHardDisk> hardDisk;
1135 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
1136 /* not a UUID or not registered? Then it must be a filename */
1137 if (!hardDisk)
1138 {
1139 CHECK_ERROR(a->virtualBox, FindHardDisk(Bstr(a->argv[1]), hardDisk.asOutParam()));
1140 }
1141 if (SUCCEEDED(rc) && hardDisk)
1142 {
1143 CHECK_ERROR(hardDisk, Close());
1144 }
1145 }
1146 else
1147 if (strcmp(a->argv[0], "dvd") == 0)
1148 {
1149 ComPtr<IDVDImage> dvdImage;
1150 rc = a->virtualBox->GetDVDImage(uuid, dvdImage.asOutParam());
1151 /* not a UUID or not registered? Then it must be a filename */
1152 if (!dvdImage)
1153 {
1154 CHECK_ERROR(a->virtualBox, FindDVDImage(Bstr(a->argv[1]), dvdImage.asOutParam()));
1155 }
1156 if (SUCCEEDED(rc) && dvdImage)
1157 {
1158 CHECK_ERROR(dvdImage, Close());
1159 }
1160 }
1161 else
1162 if (strcmp(a->argv[0], "floppy") == 0)
1163 {
1164 ComPtr<IFloppyImage> floppyImage;
1165 rc = a->virtualBox->GetFloppyImage(uuid, floppyImage.asOutParam());
1166 /* not a UUID or not registered? Then it must be a filename */
1167 if (!floppyImage)
1168 {
1169 CHECK_ERROR(a->virtualBox, FindFloppyImage(Bstr(a->argv[1]), floppyImage.asOutParam()));
1170 }
1171 if (SUCCEEDED(rc) && floppyImage)
1172 {
1173 CHECK_ERROR(floppyImage, Close());
1174 }
1175 }
1176 else
1177 return errorSyntax(USAGE_UNREGISTERIMAGE, "Invalid parameter '%s'", Utf8Str(a->argv[1]).raw());
1178
1179 return SUCCEEDED(rc) ? 0 : 1;
1180}
1181#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