VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxInternalManage.cpp@ 32701

最後變更 在這個檔案從32701是 32701,由 vboxsync 提交於 15 年 前

Frontends/VBoxManage: Error printing cleanup, use stderr and consistent formatting. Small cleanups (like using Keyboard::PutScancodes instead of the more clumsy Keyboard::PutScancode and fixing the incorrect comment which attracted my attention).

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 67.2 KB
 
1/* $Id: VBoxInternalManage.cpp 32701 2010-09-22 17:12:01Z vboxsync $ */
2/** @file
3 * VBoxManage - The 'internalcommands' command.
4 *
5 * VBoxInternalManage used to be a second CLI for doing special tricks,
6 * not intended for general usage, only for assisting VBox developers.
7 * It is now integrated into VBoxManage.
8 */
9
10/*
11 * Copyright (C) 2006-2010 Oracle Corporation
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.alldomusa.eu.org. This file is free software;
15 * you can redistribute it and/or modify it under the terms of the GNU
16 * General Public License (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 */
21
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#include <VBox/com/com.h>
28#include <VBox/com/string.h>
29#include <VBox/com/Guid.h>
30#include <VBox/com/ErrorInfo.h>
31#include <VBox/com/errorprint.h>
32
33#include <VBox/com/VirtualBox.h>
34
35#include <VBox/VBoxHDD.h>
36#include <VBox/sup.h>
37#include <VBox/err.h>
38#include <VBox/log.h>
39
40#include <iprt/file.h>
41#include <iprt/getopt.h>
42#include <iprt/stream.h>
43#include <iprt/string.h>
44#include <iprt/uuid.h>
45
46
47#include "VBoxManage.h"
48
49/* Includes for the raw disk stuff. */
50#ifdef RT_OS_WINDOWS
51# include <windows.h>
52# include <winioctl.h>
53#elif defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) \
54 || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
55# include <errno.h>
56# include <sys/ioctl.h>
57# include <sys/types.h>
58# include <sys/stat.h>
59# include <fcntl.h>
60# include <unistd.h>
61#endif
62#ifdef RT_OS_LINUX
63# include <sys/utsname.h>
64# include <linux/hdreg.h>
65# include <linux/fs.h>
66# include <stdlib.h> /* atoi() */
67#endif /* RT_OS_LINUX */
68#ifdef RT_OS_DARWIN
69# include <sys/disk.h>
70#endif /* RT_OS_DARWIN */
71#ifdef RT_OS_SOLARIS
72# include <stropts.h>
73# include <sys/dkio.h>
74# include <sys/vtoc.h>
75#endif /* RT_OS_SOLARIS */
76#ifdef RT_OS_FREEBSD
77# include <sys/disk.h>
78#endif /* RT_OS_FREEBSD */
79
80using namespace com;
81
82
83/** Macro for checking whether a partition is of extended type or not. */
84#define PARTTYPE_IS_EXTENDED(x) ((x) == 0x05 || (x) == 0x0f || (x) == 0x85)
85
86/** Maximum number of partitions we can deal with.
87 * Ridiculously large number, but the memory consumption is rather low so who
88 * cares about never using most entries. */
89#define HOSTPARTITION_MAX 100
90
91
92typedef struct HOSTPARTITION
93{
94 unsigned uIndex;
95 /** partition type */
96 unsigned uType;
97 /** CHS/cylinder of the first sector */
98 unsigned uStartCylinder;
99 /** CHS/head of the first sector */
100 unsigned uStartHead;
101 /** CHS/head of the first sector */
102 unsigned uStartSector;
103 /** CHS/cylinder of the last sector */
104 unsigned uEndCylinder;
105 /** CHS/head of the last sector */
106 unsigned uEndHead;
107 /** CHS/sector of the last sector */
108 unsigned uEndSector;
109 /** start sector of this partition relative to the beginning of the hard
110 * disk or relative to the beginning of the extended partition table */
111 uint64_t uStart;
112 /** numer of sectors of the partition */
113 uint64_t uSize;
114 /** start sector of this partition _table_ */
115 uint64_t uPartDataStart;
116 /** numer of sectors of this partition _table_ */
117 uint64_t cPartDataSectors;
118} HOSTPARTITION, *PHOSTPARTITION;
119
120typedef struct HOSTPARTITIONS
121{
122 unsigned cPartitions;
123 HOSTPARTITION aPartitions[HOSTPARTITION_MAX];
124} HOSTPARTITIONS, *PHOSTPARTITIONS;
125
126/** flag whether we're in internal mode */
127bool g_fInternalMode;
128
129/**
130 * Print the usage info.
131 */
132void printUsageInternal(USAGECATEGORY u64Cmd)
133{
134 RTStrmPrintf(g_pStdErr,
135 "Usage: VBoxManage internalcommands <command> [command arguments]\n"
136 "\n"
137 "Commands:\n"
138 "\n"
139 "%s%s%s%s%s%s%s%s%s%s%s%s"
140 "WARNING: This is a development tool and shall only be used to analyse\n"
141 " problems. It is completely unsupported and will change in\n"
142 " incompatible ways without warning.\n",
143
144 (u64Cmd & USAGE_LOADSYMS)
145 ? " loadsyms <vmname>|<uuid> <symfile> [delta] [module] [module address]\n"
146 " This will instruct DBGF to load the given symbolfile\n"
147 " during initialization.\n"
148 "\n"
149 : "",
150 (u64Cmd & USAGE_UNLOADSYMS)
151 ? " unloadsyms <vmname>|<uuid> <symfile>\n"
152 " Removes <symfile> from the list of symbol files that\n"
153 " should be loaded during DBF initialization.\n"
154 "\n"
155 : "",
156 (u64Cmd & USAGE_SETHDUUID)
157 ? " sethduuid <filepath> [<uuid>]\n"
158 " Assigns a new UUID to the given image file. This way, multiple copies\n"
159 " of a container can be registered.\n"
160 "\n"
161 : "",
162 (u64Cmd & USAGE_SETHDPARENTUUID)
163 ? " sethdparentuuid <filepath> <uuid>\n"
164 " Assigns a new parent UUID to the given image file.\n"
165 "\n"
166 : "",
167 (u64Cmd & USAGE_DUMPHDINFO)
168 ? " dumphdinfo <filepath>\n"
169 " Prints information about the image at the given location.\n"
170 "\n"
171 : "",
172 (u64Cmd & USAGE_LISTPARTITIONS)
173 ? " listpartitions -rawdisk <diskname>\n"
174 " Lists all partitions on <diskname>.\n"
175 "\n"
176 : "",
177 (u64Cmd & USAGE_CREATERAWVMDK)
178 ? " createrawvmdk -filename <filename> -rawdisk <diskname>\n"
179 " [-partitions <list of partition numbers> [-mbr <filename>] ]\n"
180 " [-register] [-relative]\n"
181 " Creates a new VMDK image which gives access to an entite host disk (if\n"
182 " the parameter -partitions is not specified) or some partitions of a\n"
183 " host disk. If access to individual partitions is granted, then the\n"
184 " parameter -mbr can be used to specify an alternative MBR to be used\n"
185 " (the partitioning information in the MBR file is ignored).\n"
186 " The diskname is on Linux e.g. /dev/sda, and on Windows e.g.\n"
187 " \\\\.\\PhysicalDrive0).\n"
188 " On Linux host the parameter -relative causes a VMDK file to be created\n"
189 " which refers to individual partitions instead to the entire disk.\n"
190 " Optionally the created image can be immediately registered.\n"
191 " The necessary partition numbers can be queried with\n"
192 " VBoxManage internalcommands listpartitions\n"
193 "\n"
194 : "",
195 (u64Cmd & USAGE_RENAMEVMDK)
196 ? " renamevmdk -from <filename> -to <filename>\n"
197 " Renames an existing VMDK image, including the base file and all its extents.\n"
198 "\n"
199 : "",
200 (u64Cmd & USAGE_CONVERTTORAW)
201 ? " converttoraw [-format <fileformat>] <filename> <outputfile>"
202#ifdef ENABLE_CONVERT_RAW_TO_STDOUT
203 "|stdout"
204#endif /* ENABLE_CONVERT_RAW_TO_STDOUT */
205 "\n"
206 " Convert image to raw, writing to file"
207#ifdef ENABLE_CONVERT_RAW_TO_STDOUT
208 " or stdout"
209#endif /* ENABLE_CONVERT_RAW_TO_STDOUT */
210 ".\n"
211 "\n"
212 : "",
213 (u64Cmd & USAGE_CONVERTHD)
214 ? " converthd [-srcformat VDI|VMDK|VHD|RAW]\n"
215 " [-dstformat VDI|VMDK|VHD|RAW]\n"
216 " <inputfile> <outputfile>\n"
217 " converts hard disk images between formats\n"
218 "\n"
219 : "",
220#ifdef RT_OS_WINDOWS
221 (u64Cmd & USAGE_MODINSTALL)
222 ? " modinstall\n"
223 " Installs the neccessary driver for the host OS\n"
224 "\n"
225 : "",
226 (u64Cmd & USAGE_MODUNINSTALL)
227 ? " moduninstall\n"
228 " Deinstalls the driver\n"
229 "\n"
230 : "",
231#else
232 "",
233 "",
234#endif
235 (u64Cmd & USAGE_DEBUGLOG)
236 ? " debuglog <vmname>|<uuid> [--enable|--disable] [--flags todo]\n"
237 " [--groups todo] [--destinations todo]\n"
238 " Controls debug logging.\n"
239 "\n"
240 : ""
241 );
242}
243
244/** @todo this is no longer necessary, we can enumerate extra data */
245/**
246 * Finds a new unique key name.
247 *
248 * I don't think this is 100% race condition proof, but we assumes
249 * the user is not trying to push this point.
250 *
251 * @returns Result from the insert.
252 * @param pMachine The Machine object.
253 * @param pszKeyBase The base key.
254 * @param rKey Reference to the string object in which we will return the key.
255 */
256static HRESULT NewUniqueKey(ComPtr<IMachine> pMachine, const char *pszKeyBase, Utf8Str &rKey)
257{
258 Bstr Keys;
259 HRESULT hrc = pMachine->GetExtraData(Bstr(pszKeyBase), Keys.asOutParam());
260 if (FAILED(hrc))
261 return hrc;
262
263 /* if there are no keys, it's simple. */
264 if (Keys.isEmpty())
265 {
266 rKey = "1";
267 return pMachine->SetExtraData(Bstr(pszKeyBase), Bstr("1"));
268 }
269
270 /* find a unique number - brute force rulez. */
271 Utf8Str KeysUtf8(Keys);
272 const char *pszKeys = RTStrStripL(KeysUtf8.c_str());
273 for (unsigned i = 1; i < 1000000; i++)
274 {
275 char szKey[32];
276 size_t cchKey = RTStrPrintf(szKey, sizeof(szKey), "%#x", i);
277 const char *psz = strstr(pszKeys, szKey);
278 while (psz)
279 {
280 if ( ( psz == pszKeys
281 || psz[-1] == ' ')
282 && ( psz[cchKey] == ' '
283 || !psz[cchKey])
284 )
285 break;
286 psz = strstr(psz + cchKey, szKey);
287 }
288 if (!psz)
289 {
290 rKey = szKey;
291 Utf8StrFmt NewKeysUtf8("%s %s", pszKeys, szKey);
292 return pMachine->SetExtraData(Bstr(pszKeyBase), Bstr(NewKeysUtf8));
293 }
294 }
295 RTMsgError("Cannot find unique key for '%s'!", pszKeyBase);
296 return E_FAIL;
297}
298
299
300#if 0
301/**
302 * Remove a key.
303 *
304 * I don't think this isn't 100% race condition proof, but we assumes
305 * the user is not trying to push this point.
306 *
307 * @returns Result from the insert.
308 * @param pMachine The machine object.
309 * @param pszKeyBase The base key.
310 * @param pszKey The key to remove.
311 */
312static HRESULT RemoveKey(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey)
313{
314 Bstr Keys;
315 HRESULT hrc = pMachine->GetExtraData(Bstr(pszKeyBase), Keys.asOutParam());
316 if (FAILED(hrc))
317 return hrc;
318
319 /* if there are no keys, it's simple. */
320 if (Keys.isEmpty())
321 return S_OK;
322
323 char *pszKeys;
324 int rc = RTUtf16ToUtf8(Keys.raw(), &pszKeys);
325 if (RT_SUCCESS(rc))
326 {
327 /* locate it */
328 size_t cchKey = strlen(pszKey);
329 char *psz = strstr(pszKeys, pszKey);
330 while (psz)
331 {
332 if ( ( psz == pszKeys
333 || psz[-1] == ' ')
334 && ( psz[cchKey] == ' '
335 || !psz[cchKey])
336 )
337 break;
338 psz = strstr(psz + cchKey, pszKey);
339 }
340 if (psz)
341 {
342 /* remove it */
343 char *pszNext = RTStrStripL(psz + cchKey);
344 if (*pszNext)
345 memmove(psz, pszNext, strlen(pszNext) + 1);
346 else
347 *psz = '\0';
348 psz = RTStrStrip(pszKeys);
349
350 /* update */
351 hrc = pMachine->SetExtraData(Bstr(pszKeyBase), Bstr(psz));
352 }
353
354 RTStrFree(pszKeys);
355 return hrc;
356 }
357 else
358 RTMsgError("Failed to delete key '%s' from '%s', string conversion error %Rrc!",
359 pszKey, pszKeyBase, rc);
360
361 return E_FAIL;
362}
363#endif
364
365
366/**
367 * Sets a key value, does necessary error bitching.
368 *
369 * @returns COM status code.
370 * @param pMachine The Machine object.
371 * @param pszKeyBase The key base.
372 * @param pszKey The key.
373 * @param pszAttribute The attribute name.
374 * @param pszValue The string value.
375 */
376static HRESULT SetString(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey, const char *pszAttribute, const char *pszValue)
377{
378 HRESULT hrc = pMachine->SetExtraData(Bstr(Utf8StrFmt("%s/%s/%s", pszKeyBase, pszKey, pszAttribute)), Bstr(pszValue));
379 if (FAILED(hrc))
380 RTMsgError("Failed to set '%s/%s/%s' to '%s'! hrc=%#x",
381 pszKeyBase, pszKey, pszAttribute, pszValue, hrc);
382 return hrc;
383}
384
385
386/**
387 * Sets a key value, does necessary error bitching.
388 *
389 * @returns COM status code.
390 * @param pMachine The Machine object.
391 * @param pszKeyBase The key base.
392 * @param pszKey The key.
393 * @param pszAttribute The attribute name.
394 * @param u64Value The value.
395 */
396static HRESULT SetUInt64(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey, const char *pszAttribute, uint64_t u64Value)
397{
398 char szValue[64];
399 RTStrPrintf(szValue, sizeof(szValue), "%#RX64", u64Value);
400 return SetString(pMachine, pszKeyBase, pszKey, pszAttribute, szValue);
401}
402
403
404/**
405 * Sets a key value, does necessary error bitching.
406 *
407 * @returns COM status code.
408 * @param pMachine The Machine object.
409 * @param pszKeyBase The key base.
410 * @param pszKey The key.
411 * @param pszAttribute The attribute name.
412 * @param i64Value The value.
413 */
414static HRESULT SetInt64(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey, const char *pszAttribute, int64_t i64Value)
415{
416 char szValue[64];
417 RTStrPrintf(szValue, sizeof(szValue), "%RI64", i64Value);
418 return SetString(pMachine, pszKeyBase, pszKey, pszAttribute, szValue);
419}
420
421
422/**
423 * Identical to the 'loadsyms' command.
424 */
425static int CmdLoadSyms(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
426{
427 HRESULT rc;
428
429 /*
430 * Get the VM
431 */
432 ComPtr<IMachine> machine;
433 /* assume it's a UUID */
434 rc = aVirtualBox->GetMachine(Bstr(argv[0]), machine.asOutParam());
435 if (FAILED(rc) || !machine)
436 {
437 /* must be a name */
438 CHECK_ERROR_RET(aVirtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()), 1);
439 }
440
441 /*
442 * Parse the command.
443 */
444 const char *pszFilename;
445 int64_t offDelta = 0;
446 const char *pszModule = NULL;
447 uint64_t ModuleAddress = ~0;
448 uint64_t ModuleSize = 0;
449
450 /* filename */
451 if (argc < 2)
452 return errorArgument("Missing the filename argument!\n");
453 pszFilename = argv[1];
454
455 /* offDelta */
456 if (argc >= 3)
457 {
458 int irc = RTStrToInt64Ex(argv[2], NULL, 0, &offDelta);
459 if (RT_FAILURE(irc))
460 return errorArgument(argv[0], "Failed to read delta '%s', rc=%Rrc\n", argv[2], rc);
461 }
462
463 /* pszModule */
464 if (argc >= 4)
465 pszModule = argv[3];
466
467 /* ModuleAddress */
468 if (argc >= 5)
469 {
470 int irc = RTStrToUInt64Ex(argv[4], NULL, 0, &ModuleAddress);
471 if (RT_FAILURE(irc))
472 return errorArgument(argv[0], "Failed to read module address '%s', rc=%Rrc\n", argv[4], rc);
473 }
474
475 /* ModuleSize */
476 if (argc >= 6)
477 {
478 int irc = RTStrToUInt64Ex(argv[5], NULL, 0, &ModuleSize);
479 if (RT_FAILURE(irc))
480 return errorArgument(argv[0], "Failed to read module size '%s', rc=%Rrc\n", argv[5], rc);
481 }
482
483 /*
484 * Add extra data.
485 */
486 Utf8Str KeyStr;
487 HRESULT hrc = NewUniqueKey(machine, "VBoxInternal/DBGF/loadsyms", KeyStr);
488 if (SUCCEEDED(hrc))
489 hrc = SetString(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "Filename", pszFilename);
490 if (SUCCEEDED(hrc) && argc >= 3)
491 hrc = SetInt64(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "Delta", offDelta);
492 if (SUCCEEDED(hrc) && argc >= 4)
493 hrc = SetString(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "Module", pszModule);
494 if (SUCCEEDED(hrc) && argc >= 5)
495 hrc = SetUInt64(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "ModuleAddress", ModuleAddress);
496 if (SUCCEEDED(hrc) && argc >= 6)
497 hrc = SetUInt64(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "ModuleSize", ModuleSize);
498
499 return FAILED(hrc);
500}
501
502
503static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
504{
505 RTMsgErrorV(pszFormat, va);
506 RTMsgError("Error code %Rrc at %s(%u) in function %s", rc, RT_SRC_POS_ARGS);
507}
508
509static int handleVDMessage(void *pvUser, const char *pszFormat, va_list va)
510{
511 NOREF(pvUser);
512 return RTPrintfV(pszFormat, va);
513}
514
515static int CmdSetHDUUID(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
516{
517 Guid uuid;
518 RTUUID rtuuid;
519 enum eUuidType {
520 HDUUID,
521 HDPARENTUUID
522 } uuidType;
523
524 if (!strcmp(argv[0], "sethduuid"))
525 {
526 uuidType = HDUUID;
527 if (argc != 3 && argc != 2)
528 return errorSyntax(USAGE_SETHDUUID, "Not enough parameters");
529 /* if specified, take UUID, otherwise generate a new one */
530 if (argc == 3)
531 {
532 if (RT_FAILURE(RTUuidFromStr(&rtuuid, argv[2])))
533 return errorSyntax(USAGE_SETHDUUID, "Invalid UUID parameter");
534 uuid = argv[2];
535 } else
536 uuid.create();
537 }
538 else if (!strcmp(argv[0], "sethdparentuuid"))
539 {
540 uuidType = HDPARENTUUID;
541 if (argc != 3)
542 return errorSyntax(USAGE_SETHDPARENTUUID, "Not enough parameters");
543 if (RT_FAILURE(RTUuidFromStr(&rtuuid, argv[2])))
544 return errorSyntax(USAGE_SETHDPARENTUUID, "Invalid UUID parameter");
545 uuid = argv[2];
546 }
547 else
548 return errorSyntax(USAGE_SETHDUUID, "Invalid invocation");
549
550 /* just try it */
551 char *pszFormat = NULL;
552 int rc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
553 argv[1], &pszFormat);
554 if (RT_FAILURE(rc))
555 {
556 RTMsgError("Format autodetect failed: %Rrc", rc);
557 return 1;
558 }
559
560 PVBOXHDD pDisk = NULL;
561
562 PVDINTERFACE pVDIfs = NULL;
563 VDINTERFACE vdInterfaceError;
564 VDINTERFACEERROR vdInterfaceErrorCallbacks;
565 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
566 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
567 vdInterfaceErrorCallbacks.pfnError = handleVDError;
568 vdInterfaceErrorCallbacks.pfnMessage = handleVDMessage;
569
570 rc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
571 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
572 AssertRC(rc);
573
574 rc = VDCreate(pVDIfs, &pDisk);
575 if (RT_FAILURE(rc))
576 {
577 RTMsgError("Cannot create the virtual disk container: %Rrc", rc);
578 return 1;
579 }
580
581 /* Open the image */
582 rc = VDOpen(pDisk, pszFormat, argv[1], VD_OPEN_FLAGS_NORMAL, NULL);
583 if (RT_FAILURE(rc))
584 {
585 RTMsgError("Cannot open the image: %Rrc", rc);
586 return 1;
587 }
588
589 if (uuidType == HDUUID)
590 rc = VDSetUuid(pDisk, VD_LAST_IMAGE, uuid.raw());
591 else
592 rc = VDSetParentUuid(pDisk, VD_LAST_IMAGE, uuid.raw());
593 if (RT_FAILURE(rc))
594 RTMsgError("Cannot set a new UUID: %Rrc", rc);
595 else
596 RTPrintf("UUID changed to: %s\n", uuid.toString().c_str());
597
598 VDCloseAll(pDisk);
599
600 return RT_FAILURE(rc);
601}
602
603
604static int CmdDumpHDInfo(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
605{
606 /* we need exactly one parameter: the image file */
607 if (argc != 1)
608 {
609 return errorSyntax(USAGE_DUMPHDINFO, "Not enough parameters");
610 }
611
612 /* just try it */
613 char *pszFormat = NULL;
614 int rc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
615 argv[0], &pszFormat);
616 if (RT_FAILURE(rc))
617 {
618 RTMsgError("Format autodetect failed: %Rrc", rc);
619 return 1;
620 }
621
622 PVBOXHDD pDisk = NULL;
623
624 PVDINTERFACE pVDIfs = NULL;
625 VDINTERFACE vdInterfaceError;
626 VDINTERFACEERROR vdInterfaceErrorCallbacks;
627 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
628 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
629 vdInterfaceErrorCallbacks.pfnError = handleVDError;
630 vdInterfaceErrorCallbacks.pfnMessage = handleVDMessage;
631
632 rc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
633 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
634 AssertRC(rc);
635
636 rc = VDCreate(pVDIfs, &pDisk);
637 if (RT_FAILURE(rc))
638 {
639 RTMsgError("Cannot create the virtual disk container: %Rrc", rc);
640 return 1;
641 }
642
643 /* Open the image */
644 rc = VDOpen(pDisk, pszFormat, argv[0], VD_OPEN_FLAGS_INFO, NULL);
645 if (RT_FAILURE(rc))
646 {
647 RTMsgError("Cannot open the image: %Rrc", rc);
648 return 1;
649 }
650
651 VDDumpImages(pDisk);
652
653 VDCloseAll(pDisk);
654
655 return RT_FAILURE(rc);
656}
657
658static int partRead(RTFILE File, PHOSTPARTITIONS pPart)
659{
660 uint8_t aBuffer[512];
661 int rc;
662
663 pPart->cPartitions = 0;
664 memset(pPart->aPartitions, '\0', sizeof(pPart->aPartitions));
665 rc = RTFileReadAt(File, 0, &aBuffer, sizeof(aBuffer), NULL);
666 if (RT_FAILURE(rc))
667 return rc;
668 if (aBuffer[510] != 0x55 || aBuffer[511] != 0xaa)
669 return VERR_INVALID_PARAMETER;
670
671 unsigned uExtended = (unsigned)-1;
672
673 for (unsigned i = 0; i < 4; i++)
674 {
675 uint8_t *p = &aBuffer[0x1be + i * 16];
676 if (p[4] == 0)
677 continue;
678 PHOSTPARTITION pCP = &pPart->aPartitions[pPart->cPartitions++];
679 pCP->uIndex = i + 1;
680 pCP->uType = p[4];
681 pCP->uStartCylinder = (uint32_t)p[3] + ((uint32_t)(p[2] & 0xc0) << 2);
682 pCP->uStartHead = p[1];
683 pCP->uStartSector = p[2] & 0x3f;
684 pCP->uEndCylinder = (uint32_t)p[7] + ((uint32_t)(p[6] & 0xc0) << 2);
685 pCP->uEndHead = p[5];
686 pCP->uEndSector = p[6] & 0x3f;
687 pCP->uStart = RT_MAKE_U32_FROM_U8(p[8], p[9], p[10], p[11]);
688 pCP->uSize = RT_MAKE_U32_FROM_U8(p[12], p[13], p[14], p[15]);
689 pCP->uPartDataStart = 0; /* will be filled out later properly. */
690 pCP->cPartDataSectors = 0;
691
692 if (PARTTYPE_IS_EXTENDED(p[4]))
693 {
694 if (uExtended == (unsigned)-1)
695 uExtended = (unsigned)(pCP - pPart->aPartitions);
696 else
697 {
698 RTMsgError("More than one extended partition");
699 return VERR_INVALID_PARAMETER;
700 }
701 }
702 }
703
704 if (uExtended != (unsigned)-1)
705 {
706 unsigned uIndex = 5;
707 uint64_t uStart = pPart->aPartitions[uExtended].uStart;
708 uint64_t uOffset = 0;
709 if (!uStart)
710 {
711 RTMsgError("Inconsistency for logical partition start");
712 return VERR_INVALID_PARAMETER;
713 }
714
715 do
716 {
717 rc = RTFileReadAt(File, (uStart + uOffset) * 512, &aBuffer, sizeof(aBuffer), NULL);
718 if (RT_FAILURE(rc))
719 return rc;
720
721 if (aBuffer[510] != 0x55 || aBuffer[511] != 0xaa)
722 {
723 RTMsgError("Logical partition without magic");
724 return VERR_INVALID_PARAMETER;
725 }
726 uint8_t *p = &aBuffer[0x1be];
727
728 if (p[4] == 0)
729 {
730 RTMsgError("Logical partition with type 0 encountered");
731 return VERR_INVALID_PARAMETER;
732 }
733
734 PHOSTPARTITION pCP = &pPart->aPartitions[pPart->cPartitions++];
735 pCP->uIndex = uIndex;
736 pCP->uType = p[4];
737 pCP->uStartCylinder = (uint32_t)p[3] + ((uint32_t)(p[2] & 0xc0) << 2);
738 pCP->uStartHead = p[1];
739 pCP->uStartSector = p[2] & 0x3f;
740 pCP->uEndCylinder = (uint32_t)p[7] + ((uint32_t)(p[6] & 0xc0) << 2);
741 pCP->uEndHead = p[5];
742 pCP->uEndSector = p[6] & 0x3f;
743 uint32_t uStartOffset = RT_MAKE_U32_FROM_U8(p[8], p[9], p[10], p[11]);
744 if (!uStartOffset)
745 {
746 RTMsgError("Invalid partition start offset");
747 return VERR_INVALID_PARAMETER;
748 }
749 pCP->uStart = uStart + uOffset + uStartOffset;
750 pCP->uSize = RT_MAKE_U32_FROM_U8(p[12], p[13], p[14], p[15]);
751 /* Fill out partitioning location info for EBR. */
752 pCP->uPartDataStart = uStart + uOffset;
753 pCP->cPartDataSectors = uStartOffset;
754 p += 16;
755 if (p[4] == 0)
756 uExtended = (unsigned)-1;
757 else if (PARTTYPE_IS_EXTENDED(p[4]))
758 {
759 uExtended = uIndex++;
760 uOffset = RT_MAKE_U32_FROM_U8(p[8], p[9], p[10], p[11]);
761 }
762 else
763 {
764 RTMsgError("Logical partition chain broken");
765 return VERR_INVALID_PARAMETER;
766 }
767 } while (uExtended != (unsigned)-1);
768 }
769
770 /* Sort partitions in ascending order of start sector, plus a trivial
771 * bit of consistency checking. */
772 for (unsigned i = 0; i < pPart->cPartitions-1; i++)
773 {
774 unsigned uMinIdx = i;
775 uint64_t uMinVal = pPart->aPartitions[i].uStart;
776 for (unsigned j = i + 1; j < pPart->cPartitions; j++)
777 {
778 if (pPart->aPartitions[j].uStart < uMinVal)
779 {
780 uMinIdx = j;
781 uMinVal = pPart->aPartitions[j].uStart;
782 }
783 else if (pPart->aPartitions[j].uStart == uMinVal)
784 {
785 RTMsgError("Two partitions start at the same place");
786 return VERR_INVALID_PARAMETER;
787 }
788 else if (pPart->aPartitions[j].uStart == 0)
789 {
790 RTMsgError("Partition starts at sector 0");
791 return VERR_INVALID_PARAMETER;
792 }
793 }
794 if (uMinIdx != i)
795 {
796 /* Swap entries at index i and uMinIdx. */
797 memcpy(&pPart->aPartitions[pPart->cPartitions],
798 &pPart->aPartitions[i], sizeof(HOSTPARTITION));
799 memcpy(&pPart->aPartitions[i],
800 &pPart->aPartitions[uMinIdx], sizeof(HOSTPARTITION));
801 memcpy(&pPart->aPartitions[uMinIdx],
802 &pPart->aPartitions[pPart->cPartitions], sizeof(HOSTPARTITION));
803 }
804 }
805
806 /* Fill out partitioning location info for MBR. */
807 pPart->aPartitions[0].uPartDataStart = 0;
808 pPart->aPartitions[0].cPartDataSectors = pPart->aPartitions[0].uStart;
809
810 /* Now do a some partition table consistency checking, to reject the most
811 * obvious garbage which can lead to trouble later. */
812 uint64_t uPrevEnd = 0;
813 for (unsigned i = 0; i < pPart->cPartitions-1; i++)
814 {
815 if (pPart->aPartitions[i].cPartDataSectors)
816 uPrevEnd = pPart->aPartitions[i].uPartDataStart + pPart->aPartitions[i].cPartDataSectors;
817 if (pPart->aPartitions[i].uStart < uPrevEnd)
818 {
819 RTMsgError("Overlapping partitions");
820 return VERR_INVALID_PARAMETER;
821 }
822 if (!PARTTYPE_IS_EXTENDED(pPart->aPartitions[i].uType))
823 uPrevEnd = pPart->aPartitions[i].uStart + pPart->aPartitions[i].uSize;
824 }
825
826 return VINF_SUCCESS;
827}
828
829static int CmdListPartitions(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
830{
831 Utf8Str rawdisk;
832
833 /* let's have a closer look at the arguments */
834 for (int i = 0; i < argc; i++)
835 {
836 if (strcmp(argv[i], "-rawdisk") == 0)
837 {
838 if (argc <= i + 1)
839 {
840 return errorArgument("Missing argument to '%s'", argv[i]);
841 }
842 i++;
843 rawdisk = argv[i];
844 }
845 else
846 {
847 return errorSyntax(USAGE_LISTPARTITIONS, "Invalid parameter '%s'", argv[i]);
848 }
849 }
850
851 if (rawdisk.isEmpty())
852 return errorSyntax(USAGE_LISTPARTITIONS, "Mandatory parameter -rawdisk missing");
853
854 RTFILE RawFile;
855 int vrc = RTFileOpen(&RawFile, rawdisk.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
856 if (RT_FAILURE(vrc))
857 {
858 RTMsgError("Cannnot open the raw disk: %Rrc", vrc);
859 return vrc;
860 }
861
862 HOSTPARTITIONS partitions;
863 vrc = partRead(RawFile, &partitions);
864 /* Don't bail out on errors, print the table and return the result code. */
865
866 RTPrintf("Number Type StartCHS EndCHS Size (MiB) Start (Sect)\n");
867 for (unsigned i = 0; i < partitions.cPartitions; i++)
868 {
869 /* Don't show the extended partition, otherwise users might think they
870 * can add it to the list of partitions for raw partition access. */
871 if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
872 continue;
873
874 RTPrintf("%-7u %#04x %-4u/%-3u/%-2u %-4u/%-3u/%-2u %10llu %10llu\n",
875 partitions.aPartitions[i].uIndex,
876 partitions.aPartitions[i].uType,
877 partitions.aPartitions[i].uStartCylinder,
878 partitions.aPartitions[i].uStartHead,
879 partitions.aPartitions[i].uStartSector,
880 partitions.aPartitions[i].uEndCylinder,
881 partitions.aPartitions[i].uEndHead,
882 partitions.aPartitions[i].uEndSector,
883 partitions.aPartitions[i].uSize / 2048,
884 partitions.aPartitions[i].uStart);
885 }
886
887 return vrc;
888}
889
890static PVBOXHDDRAWPARTDESC appendPartDesc(uint32_t *pcPartDescs, PVBOXHDDRAWPARTDESC *ppPartDescs)
891{
892 (*pcPartDescs)++;
893 PVBOXHDDRAWPARTDESC p;
894 p = (PVBOXHDDRAWPARTDESC)RTMemRealloc(*ppPartDescs,
895 *pcPartDescs * sizeof(VBOXHDDRAWPARTDESC));
896 *ppPartDescs = p;
897 if (p)
898 {
899 p = p + *pcPartDescs - 1;
900 memset(p, '\0', sizeof(VBOXHDDRAWPARTDESC));
901 }
902
903 return p;
904}
905
906static int CmdCreateRawVMDK(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
907{
908 HRESULT rc = S_OK;
909 Utf8Str filename;
910 const char *pszMBRFilename = NULL;
911 Utf8Str rawdisk;
912 const char *pszPartitions = NULL;
913 bool fRegister = false;
914 bool fRelative = false;
915
916 uint64_t cbSize = 0;
917 PVBOXHDD pDisk = NULL;
918 VBOXHDDRAW RawDescriptor;
919 PVDINTERFACE pVDIfs = NULL;
920
921 /* let's have a closer look at the arguments */
922 for (int i = 0; i < argc; i++)
923 {
924 if (strcmp(argv[i], "-filename") == 0)
925 {
926 if (argc <= i + 1)
927 {
928 return errorArgument("Missing argument to '%s'", argv[i]);
929 }
930 i++;
931 filename = argv[i];
932 }
933 else if (strcmp(argv[i], "-mbr") == 0)
934 {
935 if (argc <= i + 1)
936 {
937 return errorArgument("Missing argument to '%s'", argv[i]);
938 }
939 i++;
940 pszMBRFilename = argv[i];
941 }
942 else if (strcmp(argv[i], "-rawdisk") == 0)
943 {
944 if (argc <= i + 1)
945 {
946 return errorArgument("Missing argument to '%s'", argv[i]);
947 }
948 i++;
949 rawdisk = argv[i];
950 }
951 else if (strcmp(argv[i], "-partitions") == 0)
952 {
953 if (argc <= i + 1)
954 {
955 return errorArgument("Missing argument to '%s'", argv[i]);
956 }
957 i++;
958 pszPartitions = argv[i];
959 }
960 else if (strcmp(argv[i], "-register") == 0)
961 {
962 fRegister = true;
963 }
964#ifdef RT_OS_LINUX
965 else if (strcmp(argv[i], "-relative") == 0)
966 {
967 fRelative = true;
968 }
969#endif /* RT_OS_LINUX */
970 else
971 return errorSyntax(USAGE_CREATERAWVMDK, "Invalid parameter '%s'", argv[i]);
972 }
973
974 if (filename.isEmpty())
975 return errorSyntax(USAGE_CREATERAWVMDK, "Mandatory parameter -filename missing");
976 if (rawdisk.isEmpty())
977 return errorSyntax(USAGE_CREATERAWVMDK, "Mandatory parameter -rawdisk missing");
978 if (!pszPartitions && pszMBRFilename)
979 return errorSyntax(USAGE_CREATERAWVMDK, "The parameter -mbr is only valid when the parameter -partitions is also present");
980
981#ifdef RT_OS_DARWIN
982 fRelative = true;
983#endif /* RT_OS_DARWIN */
984 RTFILE RawFile;
985 int vrc = RTFileOpen(&RawFile, rawdisk.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
986 if (RT_FAILURE(vrc))
987 {
988 RTMsgError("Cannot open the raw disk '%s': %Rrc", rawdisk.c_str(), vrc);
989 goto out;
990 }
991
992#ifdef RT_OS_WINDOWS
993 /* Windows NT has no IOCTL_DISK_GET_LENGTH_INFORMATION ioctl. This was
994 * added to Windows XP, so we have to use the available info from DriveGeo.
995 * Note that we cannot simply use IOCTL_DISK_GET_DRIVE_GEOMETRY as it
996 * yields a slightly different result than IOCTL_DISK_GET_LENGTH_INFO.
997 * We call IOCTL_DISK_GET_DRIVE_GEOMETRY first as we need to check the media
998 * type anyway, and if IOCTL_DISK_GET_LENGTH_INFORMATION is supported
999 * we will later override cbSize.
1000 */
1001 DISK_GEOMETRY DriveGeo;
1002 DWORD cbDriveGeo;
1003 if (DeviceIoControl((HANDLE)RawFile,
1004 IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
1005 &DriveGeo, sizeof(DriveGeo), &cbDriveGeo, NULL))
1006 {
1007 if ( DriveGeo.MediaType == FixedMedia
1008 || DriveGeo.MediaType == RemovableMedia)
1009 {
1010 cbSize = DriveGeo.Cylinders.QuadPart
1011 * DriveGeo.TracksPerCylinder
1012 * DriveGeo.SectorsPerTrack
1013 * DriveGeo.BytesPerSector;
1014 }
1015 else
1016 {
1017 RTMsgError("File '%s' is no fixed/removable medium device", rawdisk.c_str());
1018 vrc = VERR_INVALID_PARAMETER;
1019 goto out;
1020 }
1021
1022 GET_LENGTH_INFORMATION DiskLenInfo;
1023 DWORD junk;
1024 if (DeviceIoControl((HANDLE)RawFile,
1025 IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
1026 &DiskLenInfo, sizeof(DiskLenInfo), &junk, (LPOVERLAPPED)NULL))
1027 {
1028 /* IOCTL_DISK_GET_LENGTH_INFO is supported -- override cbSize. */
1029 cbSize = DiskLenInfo.Length.QuadPart;
1030 }
1031 }
1032 else
1033 {
1034 vrc = RTErrConvertFromWin32(GetLastError());
1035 RTMsgError("Cannot get the geometry of the raw disk '%s': %Rrc", rawdisk.c_str(), vrc);
1036 goto out;
1037 }
1038#elif defined(RT_OS_LINUX)
1039 struct stat DevStat;
1040 if (!fstat(RawFile, &DevStat) && S_ISBLK(DevStat.st_mode))
1041 {
1042#ifdef BLKGETSIZE64
1043 /* BLKGETSIZE64 is broken up to 2.4.17 and in many 2.5.x. In 2.6.0
1044 * it works without problems. */
1045 struct utsname utsname;
1046 if ( uname(&utsname) == 0
1047 && ( (strncmp(utsname.release, "2.5.", 4) == 0 && atoi(&utsname.release[4]) >= 18)
1048 || (strncmp(utsname.release, "2.", 2) == 0 && atoi(&utsname.release[2]) >= 6)))
1049 {
1050 uint64_t cbBlk;
1051 if (!ioctl(RawFile, BLKGETSIZE64, &cbBlk))
1052 cbSize = cbBlk;
1053 }
1054#endif /* BLKGETSIZE64 */
1055 if (!cbSize)
1056 {
1057 long cBlocks;
1058 if (!ioctl(RawFile, BLKGETSIZE, &cBlocks))
1059 cbSize = (uint64_t)cBlocks << 9;
1060 else
1061 {
1062 vrc = RTErrConvertFromErrno(errno);
1063 RTMsgError("Cannot get the size of the raw disk '%s': %Rrc", rawdisk.c_str(), vrc);
1064 goto out;
1065 }
1066 }
1067 }
1068 else
1069 {
1070 RTMsgError("File '%s' is no block device", rawdisk.c_str());
1071 vrc = VERR_INVALID_PARAMETER;
1072 goto out;
1073 }
1074#elif defined(RT_OS_DARWIN)
1075 struct stat DevStat;
1076 if (!fstat(RawFile, &DevStat) && S_ISBLK(DevStat.st_mode))
1077 {
1078 uint64_t cBlocks;
1079 uint32_t cbBlock;
1080 if (!ioctl(RawFile, DKIOCGETBLOCKCOUNT, &cBlocks))
1081 {
1082 if (!ioctl(RawFile, DKIOCGETBLOCKSIZE, &cbBlock))
1083 cbSize = cBlocks * cbBlock;
1084 else
1085 {
1086 RTMsgError("Cannot get the block size for file '%s': %Rrc", rawdisk.c_str(), vrc);
1087 vrc = RTErrConvertFromErrno(errno);
1088 goto out;
1089 }
1090 }
1091 else
1092 {
1093 vrc = RTErrConvertFromErrno(errno);
1094 RTMsgError("Cannot get the block count for file '%s': %Rrc", rawdisk.c_str(), vrc);
1095 goto out;
1096 }
1097 }
1098 else
1099 {
1100 RTMsgError("File '%s' is no block device", rawdisk.c_str());
1101 vrc = VERR_INVALID_PARAMETER;
1102 goto out;
1103 }
1104#elif defined(RT_OS_SOLARIS)
1105 struct stat DevStat;
1106 if (!fstat(RawFile, &DevStat) && ( S_ISBLK(DevStat.st_mode)
1107 || S_ISCHR(DevStat.st_mode)))
1108 {
1109 struct dk_minfo mediainfo;
1110 if (!ioctl(RawFile, DKIOCGMEDIAINFO, &mediainfo))
1111 cbSize = mediainfo.dki_capacity * mediainfo.dki_lbsize;
1112 else
1113 {
1114 vrc = RTErrConvertFromErrno(errno);
1115 RTMsgError("Cannot get the size of the raw disk '%s': %Rrc", rawdisk.c_str(), vrc);
1116 goto out;
1117 }
1118 }
1119 else
1120 {
1121 RTMsgError("File '%s' is no block or char device", rawdisk.c_str());
1122 vrc = VERR_INVALID_PARAMETER;
1123 goto out;
1124 }
1125#elif defined(RT_OS_FREEBSD)
1126 struct stat DevStat;
1127 if (!fstat(RawFile, &DevStat) && S_ISCHR(DevStat.st_mode))
1128 {
1129 off_t cbMedia = 0;
1130 if (!ioctl(RawFile, DIOCGMEDIASIZE, &cbMedia))
1131 {
1132 cbSize = cbMedia;
1133 }
1134 else
1135 {
1136 vrc = RTErrConvertFromErrno(errno);
1137 RTMsgError("Cannot get the block count for file '%s': %Rrc", rawdisk.c_str(), vrc);
1138 goto out;
1139 }
1140 }
1141 else
1142 {
1143 RTMsgError("File '%s' is no character device", rawdisk.c_str());
1144 vrc = VERR_INVALID_PARAMETER;
1145 goto out;
1146 }
1147#else /* all unrecognized OSes */
1148 /* Hopefully this works on all other hosts. If it doesn't, it'll just fail
1149 * creating the VMDK, so no real harm done. */
1150 vrc = RTFileGetSize(RawFile, &cbSize);
1151 if (RT_FAILURE(vrc))
1152 {
1153 RTMsgError("Cannot get the size of the raw disk '%s': %Rrc", rawdisk.c_str(), vrc);
1154 goto out;
1155 }
1156#endif
1157
1158 /* Check whether cbSize is actually sensible. */
1159 if (!cbSize || cbSize % 512)
1160 {
1161 RTMsgError("Detected size of raw disk '%s' is %s, an invalid value", rawdisk.c_str(), cbSize);
1162 vrc = VERR_INVALID_PARAMETER;
1163 goto out;
1164 }
1165
1166 RawDescriptor.szSignature[0] = 'R';
1167 RawDescriptor.szSignature[1] = 'A';
1168 RawDescriptor.szSignature[2] = 'W';
1169 RawDescriptor.szSignature[3] = '\0';
1170 if (!pszPartitions)
1171 {
1172 RawDescriptor.fRawDisk = true;
1173 RawDescriptor.pszRawDisk = rawdisk.c_str();
1174 }
1175 else
1176 {
1177 RawDescriptor.fRawDisk = false;
1178 RawDescriptor.pszRawDisk = NULL;
1179 RawDescriptor.cPartDescs = 0;
1180 RawDescriptor.pPartDescs = NULL;
1181
1182 uint32_t uPartitions = 0;
1183
1184 const char *p = pszPartitions;
1185 char *pszNext;
1186 uint32_t u32;
1187 while (*p != '\0')
1188 {
1189 vrc = RTStrToUInt32Ex(p, &pszNext, 0, &u32);
1190 if (RT_FAILURE(vrc))
1191 {
1192 RTMsgError("Incorrect value in partitions parameter");
1193 goto out;
1194 }
1195 uPartitions |= RT_BIT(u32);
1196 p = pszNext;
1197 if (*p == ',')
1198 p++;
1199 else if (*p != '\0')
1200 {
1201 RTMsgError("Incorrect separator in partitions parameter");
1202 vrc = VERR_INVALID_PARAMETER;
1203 goto out;
1204 }
1205 }
1206
1207 HOSTPARTITIONS partitions;
1208 vrc = partRead(RawFile, &partitions);
1209 if (RT_FAILURE(vrc))
1210 {
1211 RTMsgError("Cannot read the partition information from '%s'", rawdisk.c_str());
1212 goto out;
1213 }
1214
1215 for (unsigned i = 0; i < partitions.cPartitions; i++)
1216 {
1217 if ( uPartitions & RT_BIT(partitions.aPartitions[i].uIndex)
1218 && PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
1219 {
1220 /* Some ignorant user specified an extended partition.
1221 * Bad idea, as this would trigger an overlapping
1222 * partitions error later during VMDK creation. So warn
1223 * here and ignore what the user requested. */
1224 RTMsgWarning("It is not possible (and necessary) to explicitly give access to the "
1225 "extended partition %u. If required, enable access to all logical "
1226 "partitions inside this extended partition.",
1227 partitions.aPartitions[i].uIndex);
1228 uPartitions &= ~RT_BIT(partitions.aPartitions[i].uIndex);
1229 }
1230 }
1231
1232 for (unsigned i = 0; i < partitions.cPartitions; i++)
1233 {
1234 PVBOXHDDRAWPARTDESC pPartDesc = NULL;
1235
1236 /* first dump the MBR/EPT data area */
1237 if (partitions.aPartitions[i].cPartDataSectors)
1238 {
1239 pPartDesc = appendPartDesc(&RawDescriptor.cPartDescs,
1240 &RawDescriptor.pPartDescs);
1241 if (!pPartDesc)
1242 {
1243 RTMsgError("Out of memory allocating the partition list for '%s'", rawdisk.c_str());
1244 vrc = VERR_NO_MEMORY;
1245 goto out;
1246 }
1247
1248 /** @todo the clipping below isn't 100% accurate, as it should
1249 * actually clip to the track size. However that's easier said
1250 * than done as figuring out the track size is heuristics. In
1251 * any case the clipping is adjusted later after sorting, to
1252 * prevent overlapping data areas on the resulting image. */
1253 pPartDesc->cbData = RT_MIN(partitions.aPartitions[i].cPartDataSectors, 63) * 512;
1254 pPartDesc->uStart = partitions.aPartitions[i].uPartDataStart * 512;
1255 Assert(pPartDesc->cbData - (size_t)pPartDesc->cbData == 0);
1256 void *pPartData = RTMemAlloc((size_t)pPartDesc->cbData);
1257 if (!pPartData)
1258 {
1259 RTMsgError("Out of memory allocating the partition descriptor for '%s'", rawdisk.c_str());
1260 vrc = VERR_NO_MEMORY;
1261 goto out;
1262 }
1263 vrc = RTFileReadAt(RawFile, partitions.aPartitions[i].uPartDataStart * 512,
1264 pPartData, (size_t)pPartDesc->cbData, NULL);
1265 if (RT_FAILURE(vrc))
1266 {
1267 RTMsgError("Cannot read partition data from raw device '%s': %Rrc", rawdisk.c_str(), vrc);
1268 goto out;
1269 }
1270 /* Splice in the replacement MBR code if specified. */
1271 if ( partitions.aPartitions[i].uPartDataStart == 0
1272 && pszMBRFilename)
1273 {
1274 RTFILE MBRFile;
1275 vrc = RTFileOpen(&MBRFile, pszMBRFilename, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
1276 if (RT_FAILURE(vrc))
1277 {
1278 RTMsgError("Cannot open replacement MBR file '%s' specified with -mbr: %Rrc", pszMBRFilename, vrc);
1279 goto out;
1280 }
1281 vrc = RTFileReadAt(MBRFile, 0, pPartData, 0x1be, NULL);
1282 RTFileClose(MBRFile);
1283 if (RT_FAILURE(vrc))
1284 {
1285 RTMsgError("Cannot read replacement MBR file '%s': %Rrc", pszMBRFilename, vrc);
1286 goto out;
1287 }
1288 }
1289 pPartDesc->pvPartitionData = pPartData;
1290 }
1291
1292 if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
1293 {
1294 /* Suppress exporting the actual extended partition. Only
1295 * logical partitions should be processed. However completely
1296 * ignoring it leads to leaving out the EBR data. */
1297 continue;
1298 }
1299
1300 /* set up values for non-relative device names */
1301 const char *pszRawName = rawdisk.c_str();
1302 uint64_t uStartOffset = partitions.aPartitions[i].uStart * 512;
1303
1304 pPartDesc = appendPartDesc(&RawDescriptor.cPartDescs,
1305 &RawDescriptor.pPartDescs);
1306 if (!pPartDesc)
1307 {
1308 RTMsgError("Out of memory allocating the partition list for '%s'", rawdisk.c_str());
1309 vrc = VERR_NO_MEMORY;
1310 goto out;
1311 }
1312
1313 if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
1314 {
1315 if (fRelative)
1316 {
1317#ifdef RT_OS_LINUX
1318 /* Refer to the correct partition and use offset 0. */
1319 char *psz;
1320 vrc = RTStrAPrintf(&psz, "%s%u", rawdisk.c_str(),
1321 partitions.aPartitions[i].uIndex);
1322 if (RT_FAILURE(vrc))
1323 {
1324 RTMsgError("Cannot create reference to individual partition %u, rc=%Rrc",
1325 partitions.aPartitions[i].uIndex, vrc);
1326 goto out;
1327 }
1328 pszRawName = psz;
1329 uStartOffset = 0;
1330#elif defined(RT_OS_DARWIN)
1331 /* Refer to the correct partition and use offset 0. */
1332 char *psz;
1333 vrc = RTStrAPrintf(&psz, "%ss%u", rawdisk.c_str(),
1334 partitions.aPartitions[i].uIndex);
1335 if (RT_FAILURE(vrc))
1336 {
1337 RTMsgError("Cannot create reference to individual partition %u, rc=%Rrc",
1338 partitions.aPartitions[i].uIndex, vrc);
1339 goto out;
1340 }
1341 pszRawName = psz;
1342 uStartOffset = 0;
1343#else
1344 /** @todo not implemented for other hosts. Treat just like
1345 * not specified (this code is actually never reached). */
1346#endif
1347 }
1348
1349 pPartDesc->pszRawDevice = pszRawName;
1350 pPartDesc->uStartOffset = uStartOffset;
1351 }
1352 else
1353 {
1354 pPartDesc->pszRawDevice = NULL;
1355 pPartDesc->uStartOffset = 0;
1356 }
1357
1358 pPartDesc->uStart = partitions.aPartitions[i].uStart * 512;
1359 pPartDesc->cbData = partitions.aPartitions[i].uSize * 512;
1360 }
1361
1362 /* Sort data areas in ascending order of start. */
1363 for (unsigned i = 0; i < RawDescriptor.cPartDescs-1; i++)
1364 {
1365 unsigned uMinIdx = i;
1366 uint64_t uMinVal = RawDescriptor.pPartDescs[i].uStart;
1367 for (unsigned j = i + 1; j < RawDescriptor.cPartDescs; j++)
1368 {
1369 if (RawDescriptor.pPartDescs[j].uStart < uMinVal)
1370 {
1371 uMinIdx = j;
1372 uMinVal = RawDescriptor.pPartDescs[j].uStart;
1373 }
1374 }
1375 if (uMinIdx != i)
1376 {
1377 /* Swap entries at index i and uMinIdx. */
1378 VBOXHDDRAWPARTDESC tmp;
1379 memcpy(&tmp, &RawDescriptor.pPartDescs[i], sizeof(tmp));
1380 memcpy(&RawDescriptor.pPartDescs[i], &RawDescriptor.pPartDescs[uMinIdx], sizeof(tmp));
1381 memcpy(&RawDescriptor.pPartDescs[uMinIdx], &tmp, sizeof(tmp));
1382 }
1383 }
1384
1385 /* Have a second go at MBR/EPT area clipping. Now that the data areas
1386 * are sorted this is much easier to get 100% right. */
1387 for (unsigned i = 0; i < RawDescriptor.cPartDescs-1; i++)
1388 {
1389 if (RawDescriptor.pPartDescs[i].pvPartitionData)
1390 {
1391 RawDescriptor.pPartDescs[i].cbData = RT_MIN(RawDescriptor.pPartDescs[i+1].uStart - RawDescriptor.pPartDescs[i].uStart, RawDescriptor.pPartDescs[i].cbData);
1392 if (!RawDescriptor.pPartDescs[i].cbData)
1393 {
1394 RTMsgError("MBR/EPT overlaps with data area");
1395 vrc = VERR_INVALID_PARAMETER;
1396 goto out;
1397 }
1398 }
1399 }
1400 }
1401
1402 RTFileClose(RawFile);
1403
1404#ifdef DEBUG_klaus
1405 RTPrintf("# start length startoffset partdataptr device\n");
1406 for (unsigned i = 0; i < RawDescriptor.cPartDescs; i++)
1407 {
1408 RTPrintf("%2u %14RU64 %14RU64 %14RU64 %#18p %s\n", i,
1409 RawDescriptor.pPartDescs[i].uStart,
1410 RawDescriptor.pPartDescs[i].cbData,
1411 RawDescriptor.pPartDescs[i].uStartOffset,
1412 RawDescriptor.pPartDescs[i].pvPartitionData,
1413 RawDescriptor.pPartDescs[i].pszRawDevice);
1414 }
1415#endif
1416
1417 VDINTERFACE vdInterfaceError;
1418 VDINTERFACEERROR vdInterfaceErrorCallbacks;
1419 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1420 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1421 vdInterfaceErrorCallbacks.pfnError = handleVDError;
1422 vdInterfaceErrorCallbacks.pfnMessage = handleVDMessage;
1423
1424 vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1425 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
1426 AssertRC(vrc);
1427
1428 vrc = VDCreate(pVDIfs, &pDisk);
1429 if (RT_FAILURE(vrc))
1430 {
1431 RTMsgError("Cannot create the virtual disk container: %Rrc", vrc);
1432 goto out;
1433 }
1434
1435 Assert(RT_MIN(cbSize / 512 / 16 / 63, 16383) -
1436 (unsigned int)RT_MIN(cbSize / 512 / 16 / 63, 16383) == 0);
1437 VDGEOMETRY PCHS, LCHS;
1438 PCHS.cCylinders = (unsigned int)RT_MIN(cbSize / 512 / 16 / 63, 16383);
1439 PCHS.cHeads = 16;
1440 PCHS.cSectors = 63;
1441 LCHS.cCylinders = 0;
1442 LCHS.cHeads = 0;
1443 LCHS.cSectors = 0;
1444 vrc = VDCreateBase(pDisk, "VMDK", filename.c_str(), cbSize,
1445 VD_IMAGE_FLAGS_FIXED | VD_VMDK_IMAGE_FLAGS_RAWDISK,
1446 (char *)&RawDescriptor, &PCHS, &LCHS, NULL,
1447 VD_OPEN_FLAGS_NORMAL, NULL, NULL);
1448 if (RT_FAILURE(vrc))
1449 {
1450 RTMsgError("Cannot create the raw disk VMDK: %Rrc", vrc);
1451 goto out;
1452 }
1453 RTPrintf("RAW host disk access VMDK file %s created successfully.\n", filename.c_str());
1454
1455 VDCloseAll(pDisk);
1456
1457 /* Clean up allocated memory etc. */
1458 if (pszPartitions)
1459 {
1460 for (unsigned i = 0; i < RawDescriptor.cPartDescs; i++)
1461 {
1462 /* Free memory allocated for relative device name. */
1463 if (fRelative && RawDescriptor.pPartDescs[i].pszRawDevice)
1464 RTStrFree((char *)(void *)RawDescriptor.pPartDescs[i].pszRawDevice);
1465 if (RawDescriptor.pPartDescs[i].pvPartitionData)
1466 RTMemFree((void *)RawDescriptor.pPartDescs[i].pvPartitionData);
1467 }
1468 if (RawDescriptor.pPartDescs)
1469 RTMemFree(RawDescriptor.pPartDescs);
1470 }
1471
1472 if (fRegister)
1473 {
1474 ComPtr<IMedium> hardDisk;
1475 CHECK_ERROR(aVirtualBox, OpenMedium(Bstr(filename), DeviceType_HardDisk, AccessMode_ReadWrite, hardDisk.asOutParam()));
1476 }
1477
1478 return SUCCEEDED(rc) ? 0 : 1;
1479
1480out:
1481 RTMsgError("The raw disk vmdk file was not created");
1482 return RT_SUCCESS(vrc) ? 0 : 1;
1483}
1484
1485static int CmdRenameVMDK(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
1486{
1487 Utf8Str src;
1488 Utf8Str dst;
1489 /* Parse the arguments. */
1490 for (int i = 0; i < argc; i++)
1491 {
1492 if (strcmp(argv[i], "-from") == 0)
1493 {
1494 if (argc <= i + 1)
1495 {
1496 return errorArgument("Missing argument to '%s'", argv[i]);
1497 }
1498 i++;
1499 src = argv[i];
1500 }
1501 else if (strcmp(argv[i], "-to") == 0)
1502 {
1503 if (argc <= i + 1)
1504 {
1505 return errorArgument("Missing argument to '%s'", argv[i]);
1506 }
1507 i++;
1508 dst = argv[i];
1509 }
1510 else
1511 {
1512 return errorSyntax(USAGE_RENAMEVMDK, "Invalid parameter '%s'", argv[i]);
1513 }
1514 }
1515
1516 if (src.isEmpty())
1517 return errorSyntax(USAGE_RENAMEVMDK, "Mandatory parameter -from missing");
1518 if (dst.isEmpty())
1519 return errorSyntax(USAGE_RENAMEVMDK, "Mandatory parameter -to missing");
1520
1521 PVBOXHDD pDisk = NULL;
1522
1523 PVDINTERFACE pVDIfs = NULL;
1524 VDINTERFACE vdInterfaceError;
1525 VDINTERFACEERROR vdInterfaceErrorCallbacks;
1526 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1527 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1528 vdInterfaceErrorCallbacks.pfnError = handleVDError;
1529 vdInterfaceErrorCallbacks.pfnMessage = handleVDMessage;
1530
1531 int vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1532 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
1533 AssertRC(vrc);
1534
1535 vrc = VDCreate(pVDIfs, &pDisk);
1536 if (RT_FAILURE(vrc))
1537 {
1538 RTMsgError("Cannot create the virtual disk container: %Rrc", vrc);
1539 return vrc;
1540 }
1541 else
1542 {
1543 vrc = VDOpen(pDisk, "VMDK", src.c_str(), VD_OPEN_FLAGS_NORMAL, NULL);
1544 if (RT_FAILURE(vrc))
1545 {
1546 RTMsgError("Cannot create the source image: %Rrc", vrc);
1547 }
1548 else
1549 {
1550 vrc = VDCopy(pDisk, 0, pDisk, "VMDK", dst.c_str(), true, 0, VD_IMAGE_FLAGS_NONE, NULL, NULL, NULL, NULL);
1551 if (RT_FAILURE(vrc))
1552 {
1553 RTMsgError("Cannot rename the image: %Rrc", vrc);
1554 }
1555 }
1556 }
1557 VDCloseAll(pDisk);
1558 return vrc;
1559}
1560
1561static int CmdConvertToRaw(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
1562{
1563 Utf8Str srcformat;
1564 Utf8Str src;
1565 Utf8Str dst;
1566 bool fWriteToStdOut = false;
1567
1568 /* Parse the arguments. */
1569 for (int i = 0; i < argc; i++)
1570 {
1571 if (strcmp(argv[i], "-format") == 0)
1572 {
1573 if (argc <= i + 1)
1574 {
1575 return errorArgument("Missing argument to '%s'", argv[i]);
1576 }
1577 i++;
1578 srcformat = argv[i];
1579 }
1580 else if (src.isEmpty())
1581 {
1582 src = argv[i];
1583 }
1584 else if (dst.isEmpty())
1585 {
1586 dst = argv[i];
1587#ifdef ENABLE_CONVERT_RAW_TO_STDOUT
1588 if (!strcmp(argv[i], "stdout"))
1589 fWriteToStdOut = true;
1590#endif /* ENABLE_CONVERT_RAW_TO_STDOUT */
1591 }
1592 else
1593 {
1594 return errorSyntax(USAGE_CONVERTTORAW, "Invalid parameter '%s'", argv[i]);
1595 }
1596 }
1597
1598 if (src.isEmpty())
1599 return errorSyntax(USAGE_CONVERTTORAW, "Mandatory filename parameter missing");
1600 if (dst.isEmpty())
1601 return errorSyntax(USAGE_CONVERTTORAW, "Mandatory outputfile parameter missing");
1602
1603 PVBOXHDD pDisk = NULL;
1604
1605 PVDINTERFACE pVDIfs = NULL;
1606 VDINTERFACE vdInterfaceError;
1607 VDINTERFACEERROR vdInterfaceErrorCallbacks;
1608 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1609 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1610 vdInterfaceErrorCallbacks.pfnError = handleVDError;
1611 vdInterfaceErrorCallbacks.pfnMessage = handleVDMessage;
1612
1613 int vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1614 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
1615 AssertRC(vrc);
1616
1617 vrc = VDCreate(pVDIfs, &pDisk);
1618 if (RT_FAILURE(vrc))
1619 {
1620 RTMsgError("Cannot create the virtual disk container: %Rrc", vrc);
1621 return 1;
1622 }
1623
1624 /* Open raw output file. */
1625 RTFILE outFile;
1626 vrc = VINF_SUCCESS;
1627 if (fWriteToStdOut)
1628 outFile = 1;
1629 else
1630 vrc = RTFileOpen(&outFile, dst.c_str(), RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_ALL);
1631 if (RT_FAILURE(vrc))
1632 {
1633 VDCloseAll(pDisk);
1634 RTMsgError("Cannot create destination file \"%s\": %Rrc", dst.c_str(), vrc);
1635 return 1;
1636 }
1637
1638 if (srcformat.isEmpty())
1639 {
1640 char *pszFormat = NULL;
1641 vrc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
1642 src.c_str(), &pszFormat);
1643 if (RT_FAILURE(vrc))
1644 {
1645 VDCloseAll(pDisk);
1646 if (!fWriteToStdOut)
1647 {
1648 RTFileClose(outFile);
1649 RTFileDelete(dst.c_str());
1650 }
1651 RTMsgError("No file format specified and autodetect failed - please specify format: %Rrc", vrc);
1652 return 1;
1653 }
1654 srcformat = pszFormat;
1655 RTStrFree(pszFormat);
1656 }
1657 vrc = VDOpen(pDisk, srcformat.c_str(), src.c_str(), VD_OPEN_FLAGS_READONLY, NULL);
1658 if (RT_FAILURE(vrc))
1659 {
1660 VDCloseAll(pDisk);
1661 if (!fWriteToStdOut)
1662 {
1663 RTFileClose(outFile);
1664 RTFileDelete(dst.c_str());
1665 }
1666 RTMsgError("Cannot open the source image: %Rrc", vrc);
1667 return 1;
1668 }
1669
1670 uint64_t cbSize = VDGetSize(pDisk, VD_LAST_IMAGE);
1671 uint64_t offFile = 0;
1672#define RAW_BUFFER_SIZE _128K
1673 size_t cbBuf = RAW_BUFFER_SIZE;
1674 void *pvBuf = RTMemAlloc(cbBuf);
1675 if (pvBuf)
1676 {
1677 RTStrmPrintf(g_pStdErr, "Converting image \"%s\" with size %RU64 bytes (%RU64MB) to raw...\n", src.c_str(), cbSize, (cbSize + _1M - 1) / _1M);
1678 while (offFile < cbSize)
1679 {
1680 size_t cb = (size_t)RT_MIN(cbSize - offFile, cbBuf);
1681 vrc = VDRead(pDisk, offFile, pvBuf, cb);
1682 if (RT_FAILURE(vrc))
1683 break;
1684 vrc = RTFileWrite(outFile, pvBuf, cb, NULL);
1685 if (RT_FAILURE(vrc))
1686 break;
1687 offFile += cb;
1688 }
1689 if (RT_FAILURE(vrc))
1690 {
1691 VDCloseAll(pDisk);
1692 if (!fWriteToStdOut)
1693 {
1694 RTFileClose(outFile);
1695 RTFileDelete(dst.c_str());
1696 }
1697 RTMsgError("Cannot copy image data: %Rrc", vrc);
1698 return 1;
1699 }
1700 }
1701 else
1702 {
1703 vrc = VERR_NO_MEMORY;
1704 VDCloseAll(pDisk);
1705 if (!fWriteToStdOut)
1706 {
1707 RTFileClose(outFile);
1708 RTFileDelete(dst.c_str());
1709 }
1710 RTMsgError("Out of memory allocating read buffer");
1711 return 1;
1712 }
1713
1714 if (!fWriteToStdOut)
1715 RTFileClose(outFile);
1716 VDCloseAll(pDisk);
1717 return 0;
1718}
1719
1720static int CmdConvertHardDisk(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
1721{
1722 Utf8Str srcformat;
1723 Utf8Str dstformat;
1724 Utf8Str src;
1725 Utf8Str dst;
1726 int vrc;
1727 PVBOXHDD pSrcDisk = NULL;
1728 PVBOXHDD pDstDisk = NULL;
1729
1730 /* Parse the arguments. */
1731 for (int i = 0; i < argc; i++)
1732 {
1733 if (strcmp(argv[i], "-srcformat") == 0)
1734 {
1735 if (argc <= i + 1)
1736 {
1737 return errorArgument("Missing argument to '%s'", argv[i]);
1738 }
1739 i++;
1740 srcformat = argv[i];
1741 }
1742 else if (strcmp(argv[i], "-dstformat") == 0)
1743 {
1744 if (argc <= i + 1)
1745 {
1746 return errorArgument("Missing argument to '%s'", argv[i]);
1747 }
1748 i++;
1749 dstformat = argv[i];
1750 }
1751 else if (src.isEmpty())
1752 {
1753 src = argv[i];
1754 }
1755 else if (dst.isEmpty())
1756 {
1757 dst = argv[i];
1758 }
1759 else
1760 {
1761 return errorSyntax(USAGE_CONVERTHD, "Invalid parameter '%s'", argv[i]);
1762 }
1763 }
1764
1765 if (src.isEmpty())
1766 return errorSyntax(USAGE_CONVERTHD, "Mandatory input image parameter missing");
1767 if (dst.isEmpty())
1768 return errorSyntax(USAGE_CONVERTHD, "Mandatory output image parameter missing");
1769
1770
1771 PVDINTERFACE pVDIfs = NULL;
1772 VDINTERFACE vdInterfaceError;
1773 VDINTERFACEERROR vdInterfaceErrorCallbacks;
1774 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1775 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1776 vdInterfaceErrorCallbacks.pfnError = handleVDError;
1777 vdInterfaceErrorCallbacks.pfnMessage = handleVDMessage;
1778
1779 vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1780 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
1781 AssertRC(vrc);
1782
1783 do
1784 {
1785 /* Try to determine input image format */
1786 if (srcformat.isEmpty())
1787 {
1788 char *pszFormat = NULL;
1789 vrc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
1790 src.c_str(), &pszFormat);
1791 if (RT_FAILURE(vrc))
1792 {
1793 RTMsgError("No file format specified and autodetect failed - please specify format: %Rrc", vrc);
1794 break;
1795 }
1796 srcformat = pszFormat;
1797 RTStrFree(pszFormat);
1798 }
1799
1800 vrc = VDCreate(pVDIfs, &pSrcDisk);
1801 if (RT_FAILURE(vrc))
1802 {
1803 RTMsgError("Cannot create the source virtual disk container: %Rrc", vrc);
1804 break;
1805 }
1806
1807 /* Open the input image */
1808 vrc = VDOpen(pSrcDisk, srcformat.c_str(), src.c_str(), VD_OPEN_FLAGS_READONLY, NULL);
1809 if (RT_FAILURE(vrc))
1810 {
1811 RTMsgError("Cannot open the source image: %Rrc", vrc);
1812 break;
1813 }
1814
1815 /* Output format defaults to VDI */
1816 if (dstformat.isEmpty())
1817 dstformat = "VDI";
1818
1819 vrc = VDCreate(pVDIfs, &pDstDisk);
1820 if (RT_FAILURE(vrc))
1821 {
1822 RTMsgError("Cannot create the destination virtual disk container: %Rrc", vrc);
1823 break;
1824 }
1825
1826 uint64_t cbSize = VDGetSize(pSrcDisk, VD_LAST_IMAGE);
1827 RTStrmPrintf(g_pStdErr, "Converting image \"%s\" with size %RU64 bytes (%RU64MB)...\n", src.c_str(), cbSize, (cbSize + _1M - 1) / _1M);
1828
1829 /* Create the output image */
1830 vrc = VDCopy(pSrcDisk, VD_LAST_IMAGE, pDstDisk, dstformat.c_str(),
1831 dst.c_str(), false, 0, VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED,
1832 NULL, NULL, NULL, NULL);
1833 if (RT_FAILURE(vrc))
1834 {
1835 RTMsgError("Cannot copy the image: %Rrc", vrc);
1836 break;
1837 }
1838 }
1839 while (0);
1840 if (pDstDisk)
1841 VDCloseAll(pDstDisk);
1842 if (pSrcDisk)
1843 VDCloseAll(pSrcDisk);
1844
1845 return RT_SUCCESS(vrc) ? 0 : 1;
1846}
1847
1848/**
1849 * Unloads the neccessary driver.
1850 *
1851 * @returns VBox status code
1852 */
1853int CmdModUninstall(void)
1854{
1855 int rc;
1856
1857 rc = SUPR3Uninstall();
1858 if (RT_SUCCESS(rc))
1859 return 0;
1860 if (rc == VERR_NOT_IMPLEMENTED)
1861 return 0;
1862 return E_FAIL;
1863}
1864
1865/**
1866 * Loads the neccessary driver.
1867 *
1868 * @returns VBox status code
1869 */
1870int CmdModInstall(void)
1871{
1872 int rc;
1873
1874 rc = SUPR3Install();
1875 if (RT_SUCCESS(rc))
1876 return 0;
1877 if (rc == VERR_NOT_IMPLEMENTED)
1878 return 0;
1879 return E_FAIL;
1880}
1881
1882int CmdDebugLog(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
1883{
1884 /*
1885 * The first parameter is the name or UUID of a VM with a direct session
1886 * that we wish to open.
1887 */
1888 if (argc < 1)
1889 return errorSyntax(USAGE_DEBUGLOG, "Missing VM name/UUID");
1890
1891 ComPtr<IMachine> ptrMachine;
1892 HRESULT rc = aVirtualBox->GetMachine(Bstr(argv[0]), ptrMachine.asOutParam());
1893 if (FAILED(rc) || ptrMachine.isNull())
1894 CHECK_ERROR_RET(aVirtualBox, FindMachine(Bstr(argv[0]), ptrMachine.asOutParam()), 1);
1895
1896 CHECK_ERROR_RET(ptrMachine, LockMachine(aSession, LockType_Shared), 1);
1897
1898 /*
1899 * Get the debugger interface.
1900 */
1901 ComPtr<IConsole> ptrConsole;
1902 CHECK_ERROR_RET(aSession, COMGETTER(Console)(ptrConsole.asOutParam()), 1);
1903
1904 ComPtr<IMachineDebugger> ptrDebugger;
1905 CHECK_ERROR_RET(ptrConsole, COMGETTER(Debugger)(ptrDebugger.asOutParam()), 1);
1906
1907 /*
1908 * Parse the command.
1909 */
1910 bool fEnablePresent = false;
1911 bool fEnable = false;
1912 bool fFlagsPresent = false;
1913 iprt::MiniString strFlags;
1914 bool fGroupsPresent = false;
1915 iprt::MiniString strGroups;
1916 bool fDestsPresent = false;
1917 iprt::MiniString strDests;
1918
1919 static const RTGETOPTDEF s_aOptions[] =
1920 {
1921 { "--disable", 'E', RTGETOPT_REQ_NOTHING },
1922 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
1923 { "--flags", 'f', RTGETOPT_REQ_STRING },
1924 { "--groups", 'g', RTGETOPT_REQ_STRING },
1925 { "--destinations", 'd', RTGETOPT_REQ_STRING }
1926 };
1927
1928 int ch;
1929 RTGETOPTUNION ValueUnion;
1930 RTGETOPTSTATE GetState;
1931 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
1932 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1933 {
1934 switch (ch)
1935 {
1936 case 'e':
1937 fEnablePresent = true;
1938 fEnable = true;
1939 break;
1940
1941 case 'E':
1942 fEnablePresent = true;
1943 fEnable = false;
1944 break;
1945
1946 case 'f':
1947 fFlagsPresent = true;
1948 if (*ValueUnion.psz)
1949 {
1950 if (strFlags.isNotEmpty())
1951 strFlags.append(' ');
1952 strFlags.append(ValueUnion.psz);
1953 }
1954 break;
1955
1956 case 'g':
1957 fGroupsPresent = true;
1958 if (*ValueUnion.psz)
1959 {
1960 if (strGroups.isNotEmpty())
1961 strGroups.append(' ');
1962 strGroups.append(ValueUnion.psz);
1963 }
1964 break;
1965
1966 case 'd':
1967 fDestsPresent = true;
1968 if (*ValueUnion.psz)
1969 {
1970 if (strDests.isNotEmpty())
1971 strDests.append(' ');
1972 strDests.append(ValueUnion.psz);
1973 }
1974 break;
1975
1976 default:
1977 return errorGetOpt(USAGE_DEBUGLOG , ch, &ValueUnion);
1978 }
1979 }
1980
1981 /*
1982 * Do the job.
1983 */
1984 if (fEnablePresent && !fEnable)
1985 CHECK_ERROR_RET(ptrDebugger, COMSETTER(LogEnabled)(FALSE), 1);
1986
1987 /** @todo flags, groups destination. */
1988 if (fFlagsPresent || fGroupsPresent || fDestsPresent)
1989 RTMsgWarning("One or more of the requested features are not implemented! Feel free to do this.");
1990
1991 if (fEnablePresent && fEnable)
1992 CHECK_ERROR_RET(ptrDebugger, COMSETTER(LogEnabled)(TRUE), 1);
1993 return 0;
1994}
1995
1996/**
1997 * Wrapper for handling internal commands
1998 */
1999int handleInternalCommands(HandlerArg *a)
2000{
2001 g_fInternalMode = true;
2002
2003 /* at least a command is required */
2004 if (a->argc < 1)
2005 return errorSyntax(USAGE_ALL, "Command missing");
2006
2007 /*
2008 * The 'string switch' on command name.
2009 */
2010 const char *pszCmd = a->argv[0];
2011 if (!strcmp(pszCmd, "loadsyms"))
2012 return CmdLoadSyms(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
2013 //if (!strcmp(pszCmd, "unloadsyms"))
2014 // return CmdUnloadSyms(argc - 1 , &a->argv[1]);
2015 if (!strcmp(pszCmd, "sethduuid") || !strcmp(pszCmd, "sethdparentuuid"))
2016 return CmdSetHDUUID(a->argc, &a->argv[0], a->virtualBox, a->session);
2017 if (!strcmp(pszCmd, "dumphdinfo"))
2018 return CmdDumpHDInfo(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
2019 if (!strcmp(pszCmd, "listpartitions"))
2020 return CmdListPartitions(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
2021 if (!strcmp(pszCmd, "createrawvmdk"))
2022 return CmdCreateRawVMDK(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
2023 if (!strcmp(pszCmd, "renamevmdk"))
2024 return CmdRenameVMDK(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
2025 if (!strcmp(pszCmd, "converttoraw"))
2026 return CmdConvertToRaw(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
2027 if (!strcmp(pszCmd, "converthd"))
2028 return CmdConvertHardDisk(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
2029 if (!strcmp(pszCmd, "modinstall"))
2030 return CmdModInstall();
2031 if (!strcmp(pszCmd, "moduninstall"))
2032 return CmdModUninstall();
2033 if (!strcmp(pszCmd, "debuglog"))
2034 return CmdDebugLog(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
2035
2036 /* default: */
2037 return errorSyntax(USAGE_ALL, "Invalid command '%s'", a->argv[0]);
2038}
2039
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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