VirtualBox

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

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

API/HardDisk, Storage/VBoxHDD, Frontend/VBoxManage: eliminated base image type, which led to much unnecessary code duplication. Was triggered by VBoxManage finally being able to create all image variants the backends can support.

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

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette