VirtualBox

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

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

Main: turn read/write param in OpenHardDisk into an enum

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 38.6 KB
Line 
1/* $Id: VBoxManageDisk.cpp 18177 2009-03-24 13:21:12Z 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 }, // deprecated
123 { "--size", 's', RTGETOPT_REQ_UINT64 },
124 { "-size", 's', RTGETOPT_REQ_UINT64 }, // deprecated
125 { "--format", 'o', RTGETOPT_REQ_STRING },
126 { "-format", 'o', RTGETOPT_REQ_STRING }, // deprecated
127 { "--static", 'F', RTGETOPT_REQ_NOTHING },
128 { "-static", 'F', RTGETOPT_REQ_NOTHING }, // deprecated
129 { "--variant", 'm', RTGETOPT_REQ_STRING },
130 { "-variant", 'm', RTGETOPT_REQ_STRING }, // deprecated
131 { "--type", 't', RTGETOPT_REQ_STRING },
132 { "-type", 't', RTGETOPT_REQ_STRING }, // deprecated
133 { "--comment", 'c', RTGETOPT_REQ_STRING },
134 { "-comment", 'c', RTGETOPT_REQ_STRING }, // deprecated
135 { "--remember", 'r', RTGETOPT_REQ_NOTHING },
136 { "-remember", 'r', RTGETOPT_REQ_NOTHING }, // deprecated
137 { "--register", 'r', RTGETOPT_REQ_NOTHING }, // deprecated (inofficial)
138 { "-register", 'r', RTGETOPT_REQ_NOTHING }, // deprecated
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 = (unsigned)DiskVariant;
176 uDiskVariant |= HardDiskVariant_Fixed;
177 DiskVariant = (HardDiskVariant_T)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]), AccessMode_ReadWrite, 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 break;
486
487 default:
488 if (c > 0)
489 {
490 if (RT_C_IS_GRAPH(c))
491 return errorSyntax(USAGE_CLONEHD, "unhandled option: -%c", c);
492 else
493 return errorSyntax(USAGE_CLONEHD, "unhandled option: %i", c);
494 }
495 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
496 return errorSyntax(USAGE_CLONEHD, "unknown option: %s", ValueUnion.psz);
497 else if (ValueUnion.pDef)
498 return errorSyntax(USAGE_CLONEHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
499 else
500 return errorSyntax(USAGE_CLONEHD, "error: %Rrs", c);
501 }
502 }
503
504 if (src.isEmpty())
505 return errorSyntax(USAGE_CLONEHD, "Mandatory UUID or input file parameter missing");
506 if (dst.isEmpty())
507 return errorSyntax(USAGE_CLONEHD, "Mandatory output file parameter missing");
508
509 ComPtr<IHardDisk> srcDisk;
510 ComPtr<IHardDisk> dstDisk;
511 bool unknown = false;
512
513 /* first guess is that it's a UUID */
514 Guid uuid(Utf8Str(src).raw());
515 rc = a->virtualBox->GetHardDisk(uuid, srcDisk.asOutParam());
516 /* no? then it must be a filename */
517 if (FAILED (rc))
518 {
519 rc = a->virtualBox->FindHardDisk(src, srcDisk.asOutParam());
520 /* no? well, then it's an unkwnown image */
521 if (FAILED (rc))
522 {
523 CHECK_ERROR(a->virtualBox, OpenHardDisk(src, AccessMode_ReadWrite, srcDisk.asOutParam()));
524 if (SUCCEEDED (rc))
525 {
526 unknown = true;
527 }
528 }
529 }
530
531 do
532 {
533 if (!SUCCEEDED(rc))
534 break;
535
536 if (format.isEmpty())
537 {
538 /* get the format of the source hard disk */
539 CHECK_ERROR_BREAK(srcDisk, COMGETTER(Format) (format.asOutParam()));
540 }
541
542 CHECK_ERROR_BREAK(a->virtualBox, CreateHardDisk(format, dst, dstDisk.asOutParam()));
543
544 ComPtr<IProgress> progress;
545 CHECK_ERROR_BREAK(srcDisk, CloneTo(dstDisk, DiskVariant, progress.asOutParam()));
546
547 showProgress(progress);
548 progress->COMGETTER(ResultCode)(&rc);
549 if (FAILED(rc))
550 {
551 com::ProgressErrorInfo info(progress);
552 if (info.isBasicAvailable())
553 RTPrintf("Error: failed to clone hard disk. Error message: %lS\n", info.getText().raw());
554 else
555 RTPrintf("Error: failed to clone hard disk. No error message available!\n");
556 break;
557 }
558
559 CHECK_ERROR_BREAK(dstDisk, COMGETTER(Id)(uuid.asOutParam()));
560
561 RTPrintf("Clone hard disk created in format '%ls'. UUID: %s\n",
562 format.raw(), uuid.toString().raw());
563 }
564 while (0);
565
566 if (!fRemember && !dstDisk.isNull())
567 {
568 /* forget the created clone */
569 dstDisk->Close();
570 }
571
572 if (unknown)
573 {
574 /* close the unknown hard disk to forget it again */
575 srcDisk->Close();
576 }
577
578 return SUCCEEDED(rc) ? 0 : 1;
579}
580
581static const RTGETOPTDEF g_aConvertFromRawHardDiskOptions[] =
582{
583 { "--format", 'o', RTGETOPT_REQ_STRING },
584 { "-format", 'o', RTGETOPT_REQ_STRING },
585 { "--static", 'F', RTGETOPT_REQ_NOTHING },
586 { "-static", 'F', RTGETOPT_REQ_NOTHING },
587 { "--variant", 'm', RTGETOPT_REQ_STRING },
588 { "-variant", 'm', RTGETOPT_REQ_STRING },
589};
590
591int handleConvertFromRaw(int argc, char *argv[])
592{
593 int rc = VINF_SUCCESS;
594 bool fReadFromStdIn = false;
595 const char *format = "VDI";
596 const char *srcfilename = NULL;
597 const char *dstfilename = NULL;
598 const char *filesize = NULL;
599 unsigned uImageFlags = VD_IMAGE_FLAGS_NONE;
600 void *pvBuf = NULL;
601
602 int c;
603 RTGETOPTUNION ValueUnion;
604 RTGETOPTSTATE GetState;
605 // start at 0 because main() has hacked both the argc and argv given to us
606 RTGetOptInit(&GetState, argc, argv, g_aConvertFromRawHardDiskOptions, RT_ELEMENTS(g_aConvertFromRawHardDiskOptions), 0, 0 /* fFlags */);
607 while ((c = RTGetOpt(&GetState, &ValueUnion)))
608 {
609 switch (c)
610 {
611 case 'o': // --format
612 format = ValueUnion.psz;
613 break;
614
615 case 'm': // --variant
616 HardDiskVariant_T DiskVariant;
617 rc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
618 if (RT_FAILURE(rc))
619 return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
620 /// @todo cleaner solution than assuming 1:1 mapping?
621 uImageFlags = (unsigned)DiskVariant;
622 break;
623
624 case VINF_GETOPT_NOT_OPTION:
625 if (!srcfilename)
626 {
627 srcfilename = ValueUnion.psz;
628#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
629 fReadFromStdIn = !strcmp(srcfilename, "stdin");
630#endif
631 }
632 else if (!dstfilename)
633 dstfilename = ValueUnion.psz;
634 else if (fReadFromStdIn && !filesize)
635 filesize = ValueUnion.psz;
636 else
637 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid parameter '%s'", ValueUnion.psz);
638 break;
639
640 default:
641 if (c > 0)
642 {
643 if (RT_C_IS_PRINT(c))
644 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid option -%c", c);
645 else
646 return errorSyntax(USAGE_CONVERTFROMRAW, "Invalid option case %i", c);
647 }
648 else if (ValueUnion.pDef)
649 return errorSyntax(USAGE_CONVERTFROMRAW, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
650 else
651 return errorSyntax(USAGE_CONVERTFROMRAW, "error: %Rrs", c);
652 }
653 }
654
655 if (!srcfilename || !dstfilename || (fReadFromStdIn && !filesize))
656 return errorSyntax(USAGE_CONVERTFROMRAW, "Incorrect number of parameters");
657 RTPrintf("Converting from raw image file=\"%s\" to file=\"%s\"...\n",
658 srcfilename, dstfilename);
659
660 PVBOXHDD pDisk = NULL;
661
662 PVDINTERFACE pVDIfs = NULL;
663 VDINTERFACE vdInterfaceError;
664 VDINTERFACEERROR vdInterfaceErrorCallbacks;
665 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
666 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
667 vdInterfaceErrorCallbacks.pfnError = handleVDError;
668
669 rc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
670 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
671 AssertRC(rc);
672
673 /* open raw image file. */
674 RTFILE File;
675 if (fReadFromStdIn)
676 File = 0;
677 else
678 rc = RTFileOpen(&File, srcfilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
679 if (RT_FAILURE(rc))
680 {
681 RTPrintf("File=\"%s\" open error: %Rrf\n", srcfilename, rc);
682 goto out;
683 }
684
685 uint64_t cbFile;
686 /* get image size. */
687 if (fReadFromStdIn)
688 cbFile = RTStrToUInt64(filesize);
689 else
690 rc = RTFileGetSize(File, &cbFile);
691 if (RT_FAILURE(rc))
692 {
693 RTPrintf("Error getting image size for file \"%s\": %Rrc\n", srcfilename, rc);
694 goto out;
695 }
696
697 RTPrintf("Creating %s image with size %RU64 bytes (%RU64MB)...\n", (uImageFlags & VD_IMAGE_FLAGS_FIXED) ? "fixed" : "dynamic", cbFile, (cbFile + _1M - 1) / _1M);
698 char pszComment[256];
699 RTStrPrintf(pszComment, sizeof(pszComment), "Converted image from %s", srcfilename);
700 rc = VDCreate(pVDIfs, &pDisk);
701 if (RT_FAILURE(rc))
702 {
703 RTPrintf("Error while creating the virtual disk container: %Rrc\n", rc);
704 goto out;
705 }
706
707 Assert(RT_MIN(cbFile / 512 / 16 / 63, 16383) -
708 (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383) == 0);
709 PDMMEDIAGEOMETRY PCHS, LCHS;
710 PCHS.cCylinders = (unsigned int)RT_MIN(cbFile / 512 / 16 / 63, 16383);
711 PCHS.cHeads = 16;
712 PCHS.cSectors = 63;
713 LCHS.cCylinders = 0;
714 LCHS.cHeads = 0;
715 LCHS.cSectors = 0;
716 rc = VDCreateBase(pDisk, format, dstfilename, cbFile,
717 uImageFlags, pszComment, &PCHS, &LCHS, NULL,
718 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
719 if (RT_FAILURE(rc))
720 {
721 RTPrintf("Error while creating the disk image \"%s\": %Rrc\n", dstfilename, rc);
722 goto out;
723 }
724
725 size_t cbBuffer;
726 cbBuffer = _1M;
727 pvBuf = RTMemAlloc(cbBuffer);
728 if (!pvBuf)
729 {
730 rc = VERR_NO_MEMORY;
731 RTPrintf("Not enough memory allocating buffers for image \"%s\": %Rrc\n", dstfilename, rc);
732 goto out;
733 }
734
735 uint64_t offFile;
736 offFile = 0;
737 while (offFile < cbFile)
738 {
739 size_t cbRead;
740 size_t cbToRead;
741 cbRead = 0;
742 cbToRead = cbFile - offFile >= (uint64_t)cbBuffer ?
743 cbBuffer : (size_t) (cbFile - offFile);
744 rc = RTFileRead(File, pvBuf, cbToRead, &cbRead);
745 if (RT_FAILURE(rc) || !cbRead)
746 break;
747 rc = VDWrite(pDisk, offFile, pvBuf, cbRead);
748 if (RT_FAILURE(rc))
749 {
750 RTPrintf("Failed to write to disk image \"%s\": %Rrc\n", dstfilename, rc);
751 goto out;
752 }
753 offFile += cbRead;
754 }
755
756out:
757 if (pvBuf)
758 RTMemFree(pvBuf);
759 if (pDisk)
760 VDClose(pDisk, RT_FAILURE(rc));
761 if (File != NIL_RTFILE)
762 RTFileClose(File);
763
764 return RT_FAILURE(rc);
765}
766
767int handleAddiSCSIDisk(HandlerArg *a)
768{
769 HRESULT rc;
770 Bstr server;
771 Bstr target;
772 Bstr port;
773 Bstr lun;
774 Bstr username;
775 Bstr password;
776 Bstr comment;
777 bool fIntNet = false;
778
779 /* at least server and target */
780 if (a->argc < 4)
781 return errorSyntax(USAGE_ADDISCSIDISK, "Not enough parameters");
782
783 /* let's have a closer look at the arguments */
784 for (int i = 0; i < a->argc; i++)
785 {
786 if (strcmp(a->argv[i], "-server") == 0)
787 {
788 if (a->argc <= i + 1)
789 return errorArgument("Missing argument to '%s'", a->argv[i]);
790 i++;
791 server = a->argv[i];
792 }
793 else if (strcmp(a->argv[i], "-target") == 0)
794 {
795 if (a->argc <= i + 1)
796 return errorArgument("Missing argument to '%s'", a->argv[i]);
797 i++;
798 target = a->argv[i];
799 }
800 else if (strcmp(a->argv[i], "-port") == 0)
801 {
802 if (a->argc <= i + 1)
803 return errorArgument("Missing argument to '%s'", a->argv[i]);
804 i++;
805 port = a->argv[i];
806 }
807 else if (strcmp(a->argv[i], "-lun") == 0)
808 {
809 if (a->argc <= i + 1)
810 return errorArgument("Missing argument to '%s'", a->argv[i]);
811 i++;
812 lun = a->argv[i];
813 }
814 else if (strcmp(a->argv[i], "-encodedlun") == 0)
815 {
816 if (a->argc <= i + 1)
817 return errorArgument("Missing argument to '%s'", a->argv[i]);
818 i++;
819 lun = BstrFmt("enc%s", a->argv[i]);
820 }
821 else if (strcmp(a->argv[i], "-username") == 0)
822 {
823 if (a->argc <= i + 1)
824 return errorArgument("Missing argument to '%s'", a->argv[i]);
825 i++;
826 username = a->argv[i];
827 }
828 else if (strcmp(a->argv[i], "-password") == 0)
829 {
830 if (a->argc <= i + 1)
831 return errorArgument("Missing argument to '%s'", a->argv[i]);
832 i++;
833 password = a->argv[i];
834 }
835 else if (strcmp(a->argv[i], "-comment") == 0)
836 {
837 if (a->argc <= i + 1)
838 return errorArgument("Missing argument to '%s'", a->argv[i]);
839 i++;
840 comment = a->argv[i];
841 }
842 else if (strcmp(a->argv[i], "-intnet") == 0)
843 {
844 i++;
845 fIntNet = true;
846 }
847 else
848 return errorSyntax(USAGE_ADDISCSIDISK, "Invalid parameter '%s'", Utf8Str(a->argv[i]).raw());
849 }
850
851 /* check for required options */
852 if (!server || !target)
853 return errorSyntax(USAGE_ADDISCSIDISK, "Parameters -server and -target are required");
854
855 do
856 {
857 ComPtr<IHardDisk> hardDisk;
858 /** @todo move the location stuff to Main, which can use pfnComposeName
859 * from the disk backends to construct the location properly. */
860 CHECK_ERROR_BREAK (a->virtualBox,
861 CreateHardDisk(Bstr ("iSCSI"),
862 BstrFmt ("%ls/%ls/%ls", server.raw(), target.raw(), lun.raw()),
863 hardDisk.asOutParam()));
864 CheckComRCBreakRC (rc);
865
866 if (!comment.isNull())
867 CHECK_ERROR_BREAK(hardDisk, COMSETTER(Description)(comment));
868
869 if (!port.isNull())
870 server = BstrFmt ("%ls:%ls", server.raw(), port.raw());
871
872 com::SafeArray <BSTR> names;
873 com::SafeArray <BSTR> values;
874
875 Bstr ("TargetAddress").detachTo (names.appendedRaw());
876 server.detachTo (values.appendedRaw());
877 Bstr ("TargetName").detachTo (names.appendedRaw());
878 target.detachTo (values.appendedRaw());
879
880 if (!lun.isNull())
881 {
882 Bstr ("LUN").detachTo (names.appendedRaw());
883 lun.detachTo (values.appendedRaw());
884 }
885 if (!username.isNull())
886 {
887 Bstr ("InitiatorUsername").detachTo (names.appendedRaw());
888 username.detachTo (values.appendedRaw());
889 }
890 if (!password.isNull())
891 {
892 Bstr ("InitiatorSecret").detachTo (names.appendedRaw());
893 password.detachTo (values.appendedRaw());
894 }
895
896 /// @todo add -initiator option
897 Bstr ("InitiatorName").detachTo (names.appendedRaw());
898 Bstr ("iqn.2008-04.com.sun.virtualbox.initiator").detachTo (values.appendedRaw());
899
900 /// @todo add -targetName and -targetPassword options
901
902 if (fIntNet)
903 {
904 Bstr ("HostIPStack").detachTo (names.appendedRaw());
905 Bstr ("0").detachTo (values.appendedRaw());
906 }
907
908 CHECK_ERROR_BREAK (hardDisk,
909 SetProperties (ComSafeArrayAsInParam (names),
910 ComSafeArrayAsInParam (values)));
911
912 Guid guid;
913 CHECK_ERROR(hardDisk, COMGETTER(Id)(guid.asOutParam()));
914 RTPrintf("iSCSI disk created. UUID: %s\n", guid.toString().raw());
915 }
916 while (0);
917
918 return SUCCEEDED(rc) ? 0 : 1;
919}
920
921
922int handleShowHardDiskInfo(HandlerArg *a)
923{
924 HRESULT rc;
925
926 if (a->argc != 1)
927 return errorSyntax(USAGE_SHOWHDINFO, "Incorrect number of parameters");
928
929 ComPtr<IHardDisk> hardDisk;
930 Bstr filepath;
931
932 bool unknown = false;
933
934 /* first guess is that it's a UUID */
935 Guid uuid(a->argv[0]);
936 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
937 /* no? then it must be a filename */
938 if (FAILED (rc))
939 {
940 filepath = a->argv[0];
941 rc = a->virtualBox->FindHardDisk(filepath, hardDisk.asOutParam());
942 /* no? well, then it's an unkwnown image */
943 if (FAILED (rc))
944 {
945 CHECK_ERROR(a->virtualBox, OpenHardDisk(filepath, AccessMode_ReadWrite, hardDisk.asOutParam()));
946 if (SUCCEEDED (rc))
947 {
948 unknown = true;
949 }
950 }
951 }
952 do
953 {
954 if (!SUCCEEDED(rc))
955 break;
956
957 hardDisk->COMGETTER(Id)(uuid.asOutParam());
958 RTPrintf("UUID: %s\n", uuid.toString().raw());
959
960 /* check for accessibility */
961 /// @todo NEWMEDIA check accessibility of all parents
962 /// @todo NEWMEDIA print the full state value
963 MediaState_T state;
964 CHECK_ERROR_BREAK (hardDisk, COMGETTER(State)(&state));
965 RTPrintf("Accessible: %s\n", state != MediaState_Inaccessible ? "yes" : "no");
966
967 if (state == MediaState_Inaccessible)
968 {
969 Bstr err;
970 CHECK_ERROR_BREAK (hardDisk, COMGETTER(LastAccessError)(err.asOutParam()));
971 RTPrintf("Access Error: %lS\n", err.raw());
972 }
973
974 Bstr description;
975 hardDisk->COMGETTER(Description)(description.asOutParam());
976 if (description)
977 {
978 RTPrintf("Description: %lS\n", description.raw());
979 }
980
981 ULONG64 logicalSize;
982 hardDisk->COMGETTER(LogicalSize)(&logicalSize);
983 RTPrintf("Logical size: %llu MBytes\n", logicalSize);
984 ULONG64 actualSize;
985 hardDisk->COMGETTER(Size)(&actualSize);
986 RTPrintf("Current size on disk: %llu MBytes\n", actualSize >> 20);
987
988 ComPtr <IHardDisk> parent;
989 hardDisk->COMGETTER(Parent) (parent.asOutParam());
990
991 HardDiskType_T type;
992 hardDisk->COMGETTER(Type)(&type);
993 const char *typeStr = "unknown";
994 switch (type)
995 {
996 case HardDiskType_Normal:
997 if (!parent.isNull())
998 typeStr = "normal (differencing)";
999 else
1000 typeStr = "normal (base)";
1001 break;
1002 case HardDiskType_Immutable:
1003 typeStr = "immutable";
1004 break;
1005 case HardDiskType_Writethrough:
1006 typeStr = "writethrough";
1007 break;
1008 }
1009 RTPrintf("Type: %s\n", typeStr);
1010
1011 Bstr format;
1012 hardDisk->COMGETTER(Format)(format.asOutParam());
1013 RTPrintf("Storage format: %lS\n", format.raw());
1014
1015 if (!unknown)
1016 {
1017 com::SafeGUIDArray machineIds;
1018 hardDisk->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
1019 for (size_t j = 0; j < machineIds.size(); ++ j)
1020 {
1021 ComPtr<IMachine> machine;
1022 CHECK_ERROR(a->virtualBox, GetMachine(machineIds[j], machine.asOutParam()));
1023 ASSERT(machine);
1024 Bstr name;
1025 machine->COMGETTER(Name)(name.asOutParam());
1026 machine->COMGETTER(Id)(uuid.asOutParam());
1027 RTPrintf("%s%lS (UUID: %RTuuid)\n",
1028 j == 0 ? "In use by VMs: " : " ",
1029 name.raw(), &machineIds[j]);
1030 }
1031 /// @todo NEWMEDIA check usage in snapshots too
1032 /// @todo NEWMEDIA also list children
1033 }
1034
1035 Bstr loc;
1036 hardDisk->COMGETTER(Location)(loc.asOutParam());
1037 RTPrintf("Location: %lS\n", loc.raw());
1038
1039 /* print out information specific for differencing hard disks */
1040 if (!parent.isNull())
1041 {
1042 BOOL autoReset = FALSE;
1043 hardDisk->COMGETTER(AutoReset)(&autoReset);
1044 RTPrintf("Auto-Reset: %s\n", autoReset ? "on" : "off");
1045 }
1046 }
1047 while (0);
1048
1049 if (unknown)
1050 {
1051 /* close the unknown hard disk to forget it again */
1052 hardDisk->Close();
1053 }
1054
1055 return SUCCEEDED(rc) ? 0 : 1;
1056}
1057
1058int handleOpenMedium(HandlerArg *a)
1059{
1060 HRESULT rc;
1061
1062 if (a->argc < 2)
1063 return errorSyntax(USAGE_REGISTERIMAGE, "Not enough parameters");
1064
1065 Bstr filepath(a->argv[1]);
1066
1067 if (strcmp(a->argv[0], "disk") == 0)
1068 {
1069 const char *type = NULL;
1070 /* there can be a type parameter */
1071 if ((a->argc > 2) && (a->argc != 4))
1072 return errorSyntax(USAGE_REGISTERIMAGE, "Incorrect number of parameters");
1073 if (a->argc == 4)
1074 {
1075 if (strcmp(a->argv[2], "-type") != 0)
1076 return errorSyntax(USAGE_REGISTERIMAGE, "Invalid parameter '%s'", Utf8Str(a->argv[2]).raw());
1077 if ( (strcmp(a->argv[3], "normal") != 0)
1078 && (strcmp(a->argv[3], "immutable") != 0)
1079 && (strcmp(a->argv[3], "writethrough") != 0))
1080 return errorArgument("Invalid hard disk type '%s' specified", Utf8Str(a->argv[3]).raw());
1081 type = a->argv[3];
1082 }
1083
1084 ComPtr<IHardDisk> hardDisk;
1085 CHECK_ERROR(a->virtualBox, OpenHardDisk(filepath, AccessMode_ReadWrite, hardDisk.asOutParam()));
1086 if (SUCCEEDED(rc) && hardDisk)
1087 {
1088 /* change the type if requested */
1089 if (type)
1090 {
1091 if (strcmp(type, "normal") == 0)
1092 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Normal));
1093 else if (strcmp(type, "immutable") == 0)
1094 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Immutable));
1095 else if (strcmp(type, "writethrough") == 0)
1096 CHECK_ERROR(hardDisk, COMSETTER(Type)(HardDiskType_Writethrough));
1097 }
1098 }
1099 }
1100 else if (strcmp(a->argv[0], "dvd") == 0)
1101 {
1102 ComPtr<IDVDImage> dvdImage;
1103 CHECK_ERROR(a->virtualBox, OpenDVDImage(filepath, Guid(), dvdImage.asOutParam()));
1104 }
1105 else if (strcmp(a->argv[0], "floppy") == 0)
1106 {
1107 ComPtr<IFloppyImage> floppyImage;
1108 CHECK_ERROR(a->virtualBox, OpenFloppyImage(filepath, Guid(), floppyImage.asOutParam()));
1109 }
1110 else
1111 return errorSyntax(USAGE_REGISTERIMAGE, "Invalid parameter '%s'", Utf8Str(a->argv[1]).raw());
1112
1113 return SUCCEEDED(rc) ? 0 : 1;
1114}
1115
1116int handleCloseMedium(HandlerArg *a)
1117{
1118 HRESULT rc;
1119
1120 if (a->argc != 2)
1121 return errorSyntax(USAGE_UNREGISTERIMAGE, "Incorrect number of parameters");
1122
1123 /* first guess is that it's a UUID */
1124 Guid uuid(a->argv[1]);
1125
1126 if (strcmp(a->argv[0], "disk") == 0)
1127 {
1128 ComPtr<IHardDisk> hardDisk;
1129 rc = a->virtualBox->GetHardDisk(uuid, hardDisk.asOutParam());
1130 /* not a UUID or not registered? Then it must be a filename */
1131 if (!hardDisk)
1132 {
1133 CHECK_ERROR(a->virtualBox, FindHardDisk(Bstr(a->argv[1]), hardDisk.asOutParam()));
1134 }
1135 if (SUCCEEDED(rc) && hardDisk)
1136 {
1137 CHECK_ERROR(hardDisk, Close());
1138 }
1139 }
1140 else
1141 if (strcmp(a->argv[0], "dvd") == 0)
1142 {
1143 ComPtr<IDVDImage> dvdImage;
1144 rc = a->virtualBox->GetDVDImage(uuid, dvdImage.asOutParam());
1145 /* not a UUID or not registered? Then it must be a filename */
1146 if (!dvdImage)
1147 {
1148 CHECK_ERROR(a->virtualBox, FindDVDImage(Bstr(a->argv[1]), dvdImage.asOutParam()));
1149 }
1150 if (SUCCEEDED(rc) && dvdImage)
1151 {
1152 CHECK_ERROR(dvdImage, Close());
1153 }
1154 }
1155 else
1156 if (strcmp(a->argv[0], "floppy") == 0)
1157 {
1158 ComPtr<IFloppyImage> floppyImage;
1159 rc = a->virtualBox->GetFloppyImage(uuid, floppyImage.asOutParam());
1160 /* not a UUID or not registered? Then it must be a filename */
1161 if (!floppyImage)
1162 {
1163 CHECK_ERROR(a->virtualBox, FindFloppyImage(Bstr(a->argv[1]), floppyImage.asOutParam()));
1164 }
1165 if (SUCCEEDED(rc) && floppyImage)
1166 {
1167 CHECK_ERROR(floppyImage, Close());
1168 }
1169 }
1170 else
1171 return errorSyntax(USAGE_UNREGISTERIMAGE, "Invalid parameter '%s'", Utf8Str(a->argv[1]).raw());
1172
1173 return SUCCEEDED(rc) ? 0 : 1;
1174}
1175#endif /* !VBOX_ONLY_DOCS */
Note: See TracBrowser for help on using the repository browser.

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