VirtualBox

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

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

Storage/API/VBoxManage/...: add maximum size check to prevent creation of invalid images, implement fixed-size ESX variants, update VBoxManage and docs accordingly

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