VirtualBox

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

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

compile fix

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