VirtualBox

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

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

Storage: Eradicated the last bits using the old VDI only backend, keeping only the testcases for now (no longer built).

Completely removed old iSCSI driver.

Added intnet option to addiscsidisk and adjusted documentation.

Made backend name comparisons case-insensitive.

Detect VMDK files not according to VMDK 1.0 and reject with clear error message.

Changed format probing logic to not fall through to the "unsupported" case if it's a known format, i.e. has valid header.

VBoxManage converthd generic format converter made official.

Added format flag to VBoxManage createhd, allows creating VMDK files.

VBoxManage convertdd reimplemented based on new framework, supporting any image format.

VBoxManage internalcommands sethduuid reimplemented based on new framework, supporting any image format.

Cleaned up error codes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 52.3 KB
Line 
1/* $Id: VBoxInternalManage.cpp 15366 2008-12-12 13:50:32Z 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-2007 Sun Microsystems, Inc.
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.virtualbox.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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
22 * Clara, CA 95054 USA or visit http://www.sun.com if you need
23 * additional information or have any questions.
24 */
25
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <VBox/com/com.h>
32#include <VBox/com/string.h>
33#include <VBox/com/Guid.h>
34#include <VBox/com/ErrorInfo.h>
35
36#include <VBox/com/VirtualBox.h>
37
38#include <VBox/VBoxHDD-new.h>
39#include <VBox/sup.h>
40#include <VBox/err.h>
41#include <VBox/log.h>
42
43#include <iprt/file.h>
44#include <iprt/initterm.h>
45#include <iprt/stream.h>
46#include <iprt/string.h>
47#include <iprt/uuid.h>
48
49
50#include "VBoxManage.h"
51
52/* Includes for the raw disk stuff. */
53#ifdef RT_OS_WINDOWS
54# include <windows.h>
55# include <winioctl.h>
56#elif defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
57# include <errno.h>
58# include <sys/ioctl.h>
59# include <sys/types.h>
60# include <sys/stat.h>
61# include <fcntl.h>
62# include <unistd.h>
63#endif
64#ifdef RT_OS_LINUX
65# include <sys/utsname.h>
66# include <linux/hdreg.h>
67# include <linux/fs.h>
68# include <stdlib.h> /* atoi() */
69#endif /* RT_OS_LINUX */
70#ifdef RT_OS_DARWIN
71# include <sys/disk.h>
72#endif /* RT_OS_DARWIN */
73#ifdef RT_OS_SOLARIS
74# include <stropts.h>
75# include <sys/dkio.h>
76# include <sys/vtoc.h>
77#endif /* RT_OS_SOLARIS */
78
79using namespace com;
80
81
82/** Macro for checking whether a partition is of extended type or not. */
83#define PARTTYPE_IS_EXTENDED(x) ((x) == 0x05 || (x) == 0x0f || (x) == 0x85)
84
85/* Maximum number of partitions we can deal with. Ridiculously large number,
86 * but the memory consumption is rather low so who cares about never using
87 * most entries. */
88#define HOSTPARTITION_MAX 100
89
90
91typedef struct HOSTPARTITION
92{
93 unsigned uIndex;
94 unsigned uType;
95 unsigned uStartCylinder;
96 unsigned uStartHead;
97 unsigned uStartSector;
98 unsigned uEndCylinder;
99 unsigned uEndHead;
100 unsigned uEndSector;
101 uint64_t uStart;
102 uint64_t uSize;
103 uint64_t uPartDataStart;
104 uint64_t cPartDataSectors;
105} HOSTPARTITION, *PHOSTPARTITION;
106
107typedef struct HOSTPARTITIONS
108{
109 unsigned cPartitions;
110 HOSTPARTITION aPartitions[HOSTPARTITION_MAX];
111} HOSTPARTITIONS, *PHOSTPARTITIONS;
112
113/** flag whether we're in internal mode */
114bool g_fInternalMode;
115
116/**
117 * Print the usage info.
118 */
119void printUsageInternal(USAGECATEGORY u64Cmd)
120{
121 RTPrintf("Usage: VBoxManage internalcommands <command> [command arguments]\n"
122 "\n"
123 "Commands:\n"
124 "\n"
125 "%s%s%s%s%s%s%s%s"
126 "WARNING: This is a development tool and shall only be used to analyse\n"
127 " problems. It is completely unsupported and will change in\n"
128 " incompatible ways without warning.\n",
129 (u64Cmd & USAGE_LOADSYMS) ?
130 " loadsyms <vmname>|<uuid> <symfile> [delta] [module] [module address]\n"
131 " This will instruct DBGF to load the given symbolfile\n"
132 " during initialization.\n"
133 "\n"
134 : "",
135 (u64Cmd & USAGE_UNLOADSYMS) ?
136 " unloadsyms <vmname>|<uuid> <symfile>\n"
137 " Removes <symfile> from the list of symbol files that\n"
138 " should be loaded during DBF initialization.\n"
139 "\n"
140 : "",
141 (u64Cmd & USAGE_SETHDUUID) ?
142 " sethduuid <filepath>\n"
143 " Assigns a new UUID to the given image file. This way, multiple copies\n"
144 " of a container can be registered.\n"
145 "\n"
146 : "",
147 (u64Cmd & USAGE_LISTPARTITIONS) ?
148 " listpartitions -rawdisk <diskname>\n"
149 " Lists all partitions on <diskname>.\n"
150 "\n"
151 : "",
152 (u64Cmd & USAGE_CREATERAWVMDK) ?
153 " createrawvmdk -filename <filename> -rawdisk <diskname>\n"
154 " [-partitions <list of partition numbers> [-mbr <filename>] ]\n"
155 " [-register] [-relative]\n"
156 " Creates a new VMDK image which gives access to an entite host disk (if\n"
157 " the parameter -partitions is not specified) or some partitions of a\n"
158 " host disk. If access to individual partitions is granted, then the\n"
159 " parameter -mbr can be used to specify an alternative MBR to be used\n"
160 " (the partitioning information in the MBR file is ignored).\n"
161 " The diskname is on Linux e.g. /dev/sda, and on Windows e.g.\n"
162 " \\\\.\\PhysicalDrive0).\n"
163 " On Linux host the parameter -relative causes a VMDK file to be created\n"
164 " which refers to individual partitions instead to the entire disk.\n"
165 " Optionally the created image can be immediately registered.\n"
166 " The necessary partition numbers can be queried with\n"
167 " VBoxManage internalcommands listpartitions\n"
168 "\n"
169 : "",
170 (u64Cmd & USAGE_RENAMEVMDK) ?
171 " renamevmdk -from <filename> -to <filename>\n"
172 " Renames an existing VMDK image, including the base file and all its extents.\n"
173 "\n"
174 : "",
175 (u64Cmd & USAGE_CONVERTTORAW) ?
176 " converttoraw [-format <fileformat>] <filename> <outputfile>"
177#ifdef ENABLE_CONVERT_RAW_TO_STDOUT
178 "|stdout"
179#endif /* ENABLE_CONVERT_RAW_TO_STDOUT */
180 "\n"
181 " Convert image to raw, writing to file"
182#ifdef ENABLE_CONVERT_RAW_TO_STDOUT
183 " or stdout"
184#endif /* ENABLE_CONVERT_RAW_TO_STDOUT */
185 ".\n"
186 "\n"
187 : "",
188#ifdef RT_OS_WINDOWS
189 (u64Cmd & USAGE_MODINSTALL) ?
190 " modinstall\n"
191 " Installs the neccessary driver for the host OS\n"
192 "\n"
193 : "",
194 (u64Cmd & USAGE_MODUNINSTALL) ?
195 " moduninstall\n"
196 " Deinstalls the driver\n"
197 "\n"
198 : ""
199#else
200 "",
201 ""
202#endif
203 );
204}
205
206/** @todo this is no longer necessary, we can enumerate extra data */
207/**
208 * Finds a new unique key name.
209 *
210 * I don't think this is 100% race condition proof, but we assumes
211 * the user is not trying to push this point.
212 *
213 * @returns Result from the insert.
214 * @param pMachine The Machine object.
215 * @param pszKeyBase The base key.
216 * @param rKey Reference to the string object in which we will return the key.
217 */
218static HRESULT NewUniqueKey(ComPtr<IMachine> pMachine, const char *pszKeyBase, Utf8Str &rKey)
219{
220 Bstr Keys;
221 HRESULT hrc = pMachine->GetExtraData(Bstr(pszKeyBase), Keys.asOutParam());
222 if (FAILED(hrc))
223 return hrc;
224
225 /* if there are no keys, it's simple. */
226 if (Keys.isEmpty())
227 {
228 rKey = "1";
229 return pMachine->SetExtraData(Bstr(pszKeyBase), Bstr("1"));
230 }
231
232 /* find a unique number - brute force rulez. */
233 Utf8Str KeysUtf8(Keys);
234 const char *pszKeys = RTStrStripL(KeysUtf8.raw());
235 for (unsigned i = 1; i < 1000000; i++)
236 {
237 char szKey[32];
238 size_t cchKey = RTStrPrintf(szKey, sizeof(szKey), "%#x", i);
239 const char *psz = strstr(pszKeys, szKey);
240 while (psz)
241 {
242 if ( ( psz == pszKeys
243 || psz[-1] == ' ')
244 && ( psz[cchKey] == ' '
245 || !psz[cchKey])
246 )
247 break;
248 psz = strstr(psz + cchKey, szKey);
249 }
250 if (!psz)
251 {
252 rKey = szKey;
253 Utf8StrFmt NewKeysUtf8("%s %s", pszKeys, szKey);
254 return pMachine->SetExtraData(Bstr(pszKeyBase), Bstr(NewKeysUtf8));
255 }
256 }
257 RTPrintf("Error: Cannot find unique key for '%s'!\n", pszKeyBase);
258 return E_FAIL;
259}
260
261
262#if 0
263/**
264 * Remove a key.
265 *
266 * I don't think this isn't 100% race condition proof, but we assumes
267 * the user is not trying to push this point.
268 *
269 * @returns Result from the insert.
270 * @param pMachine The machine object.
271 * @param pszKeyBase The base key.
272 * @param pszKey The key to remove.
273 */
274static HRESULT RemoveKey(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey)
275{
276 Bstr Keys;
277 HRESULT hrc = pMachine->GetExtraData(Bstr(pszKeyBase), Keys.asOutParam());
278 if (FAILED(hrc))
279 return hrc;
280
281 /* if there are no keys, it's simple. */
282 if (Keys.isEmpty())
283 return S_OK;
284
285 char *pszKeys;
286 int rc = RTUtf16ToUtf8(Keys.raw(), &pszKeys);
287 if (RT_SUCCESS(rc))
288 {
289 /* locate it */
290 size_t cchKey = strlen(pszKey);
291 char *psz = strstr(pszKeys, pszKey);
292 while (psz)
293 {
294 if ( ( psz == pszKeys
295 || psz[-1] == ' ')
296 && ( psz[cchKey] == ' '
297 || !psz[cchKey])
298 )
299 break;
300 psz = strstr(psz + cchKey, pszKey);
301 }
302 if (psz)
303 {
304 /* remove it */
305 char *pszNext = RTStrStripL(psz + cchKey);
306 if (*pszNext)
307 memmove(psz, pszNext, strlen(pszNext) + 1);
308 else
309 *psz = '\0';
310 psz = RTStrStrip(pszKeys);
311
312 /* update */
313 hrc = pMachine->SetExtraData(Bstr(pszKeyBase), Bstr(psz));
314 }
315
316 RTStrFree(pszKeys);
317 return hrc;
318 }
319 else
320 RTPrintf("error: failed to delete key '%s' from '%s', string conversion error %Rrc!\n",
321 pszKey, pszKeyBase, rc);
322
323 return E_FAIL;
324}
325#endif
326
327
328/**
329 * Sets a key value, does necessary error bitching.
330 *
331 * @returns COM status code.
332 * @param pMachine The Machine object.
333 * @param pszKeyBase The key base.
334 * @param pszKey The key.
335 * @param pszAttribute The attribute name.
336 * @param pszValue The string value.
337 */
338static HRESULT SetString(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey, const char *pszAttribute, const char *pszValue)
339{
340 HRESULT hrc = pMachine->SetExtraData(Bstr(Utf8StrFmt("%s/%s/%s", pszKeyBase, pszKey, pszAttribute)), Bstr(pszValue));
341 if (FAILED(hrc))
342 RTPrintf("error: Failed to set '%s/%s/%s' to '%s'! hrc=%#x\n",
343 pszKeyBase, pszKey, pszAttribute, pszValue, hrc);
344 return hrc;
345}
346
347
348/**
349 * Sets a key value, does necessary error bitching.
350 *
351 * @returns COM status code.
352 * @param pMachine The Machine object.
353 * @param pszKeyBase The key base.
354 * @param pszKey The key.
355 * @param pszAttribute The attribute name.
356 * @param u64Value The value.
357 */
358static HRESULT SetUInt64(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey, const char *pszAttribute, uint64_t u64Value)
359{
360 char szValue[64];
361 RTStrPrintf(szValue, sizeof(szValue), "%#RX64", u64Value);
362 return SetString(pMachine, pszKeyBase, pszKey, pszAttribute, szValue);
363}
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 i64Value The value.
375 */
376static HRESULT SetInt64(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey, const char *pszAttribute, int64_t i64Value)
377{
378 char szValue[64];
379 RTStrPrintf(szValue, sizeof(szValue), "%RI64", i64Value);
380 return SetString(pMachine, pszKeyBase, pszKey, pszAttribute, szValue);
381}
382
383
384/**
385 * Identical to the 'loadsyms' command.
386 */
387static int CmdLoadSyms(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
388{
389 HRESULT rc;
390
391 /*
392 * Get the VM
393 */
394 ComPtr<IMachine> machine;
395 /* assume it's a UUID */
396 rc = aVirtualBox->GetMachine(Guid(argv[0]), machine.asOutParam());
397 if (FAILED(rc) || !machine)
398 {
399 /* must be a name */
400 CHECK_ERROR_RET(aVirtualBox, FindMachine(Bstr(argv[0]), machine.asOutParam()), 1);
401 }
402
403 /*
404 * Parse the command.
405 */
406 const char *pszFilename;
407 int64_t offDelta = 0;
408 const char *pszModule = NULL;
409 uint64_t ModuleAddress = ~0;
410 uint64_t ModuleSize = 0;
411
412 /* filename */
413 if (argc < 2)
414 return errorArgument("Missing the filename argument!\n");
415 pszFilename = argv[1];
416
417 /* offDelta */
418 if (argc >= 3)
419 {
420 int rc = RTStrToInt64Ex(argv[2], NULL, 0, &offDelta);
421 if (RT_FAILURE(rc))
422 return errorArgument(argv[0], "Failed to read delta '%s', rc=%Rrc\n", argv[2], rc);
423 }
424
425 /* pszModule */
426 if (argc >= 4)
427 pszModule = argv[3];
428
429 /* ModuleAddress */
430 if (argc >= 5)
431 {
432 int rc = RTStrToUInt64Ex(argv[4], NULL, 0, &ModuleAddress);
433 if (RT_FAILURE(rc))
434 return errorArgument(argv[0], "Failed to read module address '%s', rc=%Rrc\n", argv[4], rc);
435 }
436
437 /* ModuleSize */
438 if (argc >= 6)
439 {
440 int rc = RTStrToUInt64Ex(argv[5], NULL, 0, &ModuleSize);
441 if (RT_FAILURE(rc))
442 return errorArgument(argv[0], "Failed to read module size '%s', rc=%Rrc\n", argv[5], rc);
443 }
444
445 /*
446 * Add extra data.
447 */
448 Utf8Str KeyStr;
449 HRESULT hrc = NewUniqueKey(machine, "VBoxInternal/DBGF/loadsyms", KeyStr);
450 if (SUCCEEDED(hrc))
451 hrc = SetString(machine, "VBoxInternal/DBGF/loadsyms", KeyStr, "Filename", pszFilename);
452 if (SUCCEEDED(hrc) && argc >= 3)
453 hrc = SetInt64(machine, "VBoxInternal/DBGF/loadsyms", KeyStr, "Delta", offDelta);
454 if (SUCCEEDED(hrc) && argc >= 4)
455 hrc = SetString(machine, "VBoxInternal/DBGF/loadsyms", KeyStr, "Module", pszModule);
456 if (SUCCEEDED(hrc) && argc >= 5)
457 hrc = SetUInt64(machine, "VBoxInternal/DBGF/loadsyms", KeyStr, "ModuleAddress", ModuleAddress);
458 if (SUCCEEDED(hrc) && argc >= 6)
459 hrc = SetUInt64(machine, "VBoxInternal/DBGF/loadsyms", KeyStr, "ModuleSize", ModuleSize);
460
461 return FAILED(hrc);
462}
463
464
465static DECLCALLBACK(void) handleVDError(void *pvUser, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
466{
467 RTPrintf("ERROR: ");
468 RTPrintfV(pszFormat, va);
469 RTPrintf("\n");
470 RTPrintf("Error code %Rrc at %s(%u) in function %s\n", rc, RT_SRC_POS_ARGS);
471}
472
473static int handleSetHDUUID(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
474{
475 /* we need exactly one parameter: the image file */
476 if (argc != 1)
477 {
478 return errorSyntax(USAGE_SETHDUUID, "Not enough parameters");
479 }
480
481 /* generate a new UUID */
482 Guid uuid;
483 uuid.create();
484
485 /* just try it */
486 char *pszFormat = NULL;
487 int rc = VDGetFormat(argv[0], &pszFormat);
488 if (RT_FAILURE(rc))
489 {
490 RTPrintf("Format autodetect failed: %Rrc\n", rc);
491 return 1;
492 }
493
494 PVBOXHDD pDisk = NULL;
495
496 PVDINTERFACE pVDIfs = NULL;
497 VDINTERFACE vdInterfaceError;
498 VDINTERFACEERROR vdInterfaceErrorCallbacks;
499 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
500 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
501 vdInterfaceErrorCallbacks.pfnError = handleVDError;
502
503 rc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
504 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
505 AssertRC(rc);
506
507 rc = VDCreate(pVDIfs, &pDisk);
508 if (RT_FAILURE(rc))
509 {
510 RTPrintf("Error while creating the virtual disk container: %Rrc\n", rc);
511 return 1;
512 }
513
514 /* Open the image */
515 rc = VDOpen(pDisk, pszFormat, argv[0], VD_OPEN_FLAGS_NORMAL, NULL);
516 if (RT_FAILURE(rc))
517 {
518 RTPrintf("Error while opening the image: %Rrc\n", rc);
519 return 1;
520 }
521
522 rc = VDSetUuid(pDisk, VD_LAST_IMAGE, uuid.raw());
523 if (RT_FAILURE(rc))
524 RTPrintf("Error while setting a new UUID: %Rrc\n", rc);
525 else
526 RTPrintf("UUID changed to: %s\n", uuid.toString().raw());
527
528 VDCloseAll(pDisk);
529
530 return RT_FAILURE(rc);
531}
532
533static int partRead(RTFILE File, PHOSTPARTITIONS pPart)
534{
535 uint8_t aBuffer[512];
536 int rc;
537
538 pPart->cPartitions = 0;
539 memset(pPart->aPartitions, '\0', sizeof(pPart->aPartitions));
540 rc = RTFileReadAt(File, 0, &aBuffer, sizeof(aBuffer), NULL);
541 if (RT_FAILURE(rc))
542 return rc;
543 if (aBuffer[510] != 0x55 || aBuffer[511] != 0xaa)
544 return VERR_INVALID_PARAMETER;
545
546 unsigned uExtended = (unsigned)-1;
547
548 for (unsigned i = 0; i < 4; i++)
549 {
550 uint8_t *p = &aBuffer[0x1be + i * 16];
551 if (p[4] == 0)
552 continue;
553 PHOSTPARTITION pCP = &pPart->aPartitions[pPart->cPartitions++];
554 pCP->uIndex = i + 1;
555 pCP->uType = p[4];
556 pCP->uStartCylinder = (uint32_t)p[3] + ((uint32_t)(p[2] & 0xc0) << 2);
557 pCP->uStartHead = p[1];
558 pCP->uStartSector = p[2] & 0x3f;
559 pCP->uEndCylinder = (uint32_t)p[7] + ((uint32_t)(p[6] & 0xc0) << 2);
560 pCP->uEndHead = p[5];
561 pCP->uEndSector = p[6] & 0x3f;
562 pCP->uStart = RT_MAKE_U32_FROM_U8(p[8], p[9], p[10], p[11]);
563 pCP->uSize = RT_MAKE_U32_FROM_U8(p[12], p[13], p[14], p[15]);
564 pCP->uPartDataStart = 0; /* will be filled out later properly. */
565 pCP->cPartDataSectors = 0;
566
567 if (PARTTYPE_IS_EXTENDED(p[4]))
568 {
569 if (uExtended == (unsigned)-1)
570 uExtended = pCP - pPart->aPartitions;
571 else
572 {
573 RTPrintf("More than one extended partition. Aborting\n");
574 return VERR_INVALID_PARAMETER;
575 }
576 }
577 }
578
579 if (uExtended != (unsigned)-1)
580 {
581 unsigned uIndex = 5;
582 uint64_t uStart = pPart->aPartitions[uExtended].uStart;
583 uint64_t uOffset = 0;
584 if (!uStart)
585 {
586 RTPrintf("Inconsistency for logical partition start. Aborting\n");
587 return VERR_INVALID_PARAMETER;
588 }
589
590 do
591 {
592 rc = RTFileReadAt(File, (uStart + uOffset) * 512, &aBuffer, sizeof(aBuffer), NULL);
593 if (RT_FAILURE(rc))
594 return rc;
595
596 if (aBuffer[510] != 0x55 || aBuffer[511] != 0xaa)
597 {
598 RTPrintf("Logical partition without magic. Aborting\n");
599 return VERR_INVALID_PARAMETER;
600 }
601 uint8_t *p = &aBuffer[0x1be];
602
603 if (p[4] == 0)
604 {
605 RTPrintf("Logical partition with type 0 encountered. Aborting\n");
606 return VERR_INVALID_PARAMETER;
607 }
608
609 PHOSTPARTITION pCP = &pPart->aPartitions[pPart->cPartitions++];
610 pCP->uIndex = uIndex;
611 pCP->uType = p[4];
612 pCP->uStartCylinder = (uint32_t)p[3] + ((uint32_t)(p[2] & 0xc0) << 2);
613 pCP->uStartHead = p[1];
614 pCP->uStartSector = p[2] & 0x3f;
615 pCP->uEndCylinder = (uint32_t)p[7] + ((uint32_t)(p[6] & 0xc0) << 2);
616 pCP->uEndHead = p[5];
617 pCP->uEndSector = p[6] & 0x3f;
618 uint32_t uStartOffset = RT_MAKE_U32_FROM_U8(p[8], p[9], p[10], p[11]);
619 if (!uStartOffset)
620 {
621 RTPrintf("Invalid partition start offset. Aborting\n");
622 return VERR_INVALID_PARAMETER;
623 }
624 pCP->uStart = uStart + uOffset + uStartOffset;
625 pCP->uSize = RT_MAKE_U32_FROM_U8(p[12], p[13], p[14], p[15]);
626 /* Fill out partitioning location info for EBR. */
627 pCP->uPartDataStart = uStart + uOffset;
628 pCP->cPartDataSectors = uStartOffset;
629 p += 16;
630 if (p[4] == 0)
631 uExtended = (unsigned)-1;
632 else if (PARTTYPE_IS_EXTENDED(p[4]))
633 {
634 uExtended = uIndex++;
635 uOffset = RT_MAKE_U32_FROM_U8(p[8], p[9], p[10], p[11]);
636 }
637 else
638 {
639 RTPrintf("Logical partition chain broken. Aborting\n");
640 return VERR_INVALID_PARAMETER;
641 }
642 } while (uExtended != (unsigned)-1);
643 }
644
645 /* Sort partitions in ascending order of start sector, plus a trivial
646 * bit of consistency checking. */
647 for (unsigned i = 0; i < pPart->cPartitions-1; i++)
648 {
649 unsigned uMinIdx = i;
650 uint64_t uMinVal = pPart->aPartitions[i].uStart;
651 for (unsigned j = i + 1; j < pPart->cPartitions; j++)
652 {
653 if (pPart->aPartitions[j].uStart < uMinVal)
654 {
655 uMinIdx = j;
656 uMinVal = pPart->aPartitions[j].uStart;
657 }
658 else if (pPart->aPartitions[j].uStart == uMinVal)
659 {
660 RTPrintf("Two partitions start at the same place. Aborting\n");
661 return VERR_INVALID_PARAMETER;
662 } else if (pPart->aPartitions[j].uStart == 0)
663 {
664 RTPrintf("Partition starts at sector 0. Aborting\n");
665 return VERR_INVALID_PARAMETER;
666 }
667 }
668 if (uMinIdx != i)
669 {
670 /* Swap entries at index i and uMinIdx. */
671 memcpy(&pPart->aPartitions[pPart->cPartitions],
672 &pPart->aPartitions[i], sizeof(HOSTPARTITION));
673 memcpy(&pPart->aPartitions[i],
674 &pPart->aPartitions[uMinIdx], sizeof(HOSTPARTITION));
675 memcpy(&pPart->aPartitions[uMinIdx],
676 &pPart->aPartitions[pPart->cPartitions], sizeof(HOSTPARTITION));
677 }
678 }
679
680 /* Now do a lot of consistency checking. */
681 uint64_t uPrevEnd = 0;
682 for (unsigned i = 0; i < pPart->cPartitions-1; i++)
683 {
684 if (pPart->aPartitions[i].cPartDataSectors)
685 {
686 if (pPart->aPartitions[i].uPartDataStart < uPrevEnd)
687 {
688 RTPrintf("Overlapping partition description areas. Aborting\n");
689 return VERR_INVALID_PARAMETER;
690 }
691 uPrevEnd = pPart->aPartitions[i].uPartDataStart + pPart->aPartitions[i].cPartDataSectors;
692 }
693 if (pPart->aPartitions[i].uStart < uPrevEnd)
694 {
695 RTPrintf("Overlapping partitions. Aborting\n");
696 return VERR_INVALID_PARAMETER;
697 }
698 if (!PARTTYPE_IS_EXTENDED(pPart->aPartitions[i].uType))
699 uPrevEnd = pPart->aPartitions[i].uStart + pPart->aPartitions[i].uSize;
700 }
701
702 /* Fill out partitioning location info for MBR. */
703 pPart->aPartitions[0].uPartDataStart = 0;
704 pPart->aPartitions[0].cPartDataSectors = pPart->aPartitions[0].uStart;
705
706 return VINF_SUCCESS;
707}
708
709static int CmdListPartitions(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
710{
711 Utf8Str rawdisk;
712
713 /* let's have a closer look at the arguments */
714 for (int i = 0; i < argc; i++)
715 {
716 if (strcmp(argv[i], "-rawdisk") == 0)
717 {
718 if (argc <= i + 1)
719 {
720 return errorArgument("Missing argument to '%s'", argv[i]);
721 }
722 i++;
723 rawdisk = argv[i];
724 }
725 else
726 {
727 return errorSyntax(USAGE_LISTPARTITIONS, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
728 }
729 }
730
731 if (rawdisk.isEmpty())
732 return errorSyntax(USAGE_LISTPARTITIONS, "Mandatory parameter -rawdisk missing");
733
734 RTFILE RawFile;
735 int vrc = RTFileOpen(&RawFile, rawdisk.raw(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
736 if (RT_FAILURE(vrc))
737 {
738 RTPrintf("Error opening the raw disk: %Rrc\n", vrc);
739 return vrc;
740 }
741
742 HOSTPARTITIONS partitions;
743 vrc = partRead(RawFile, &partitions);
744 if (RT_FAILURE(vrc))
745 return vrc;
746
747 RTPrintf("Number Type StartCHS EndCHS Size (MiB) Start (Sect)\n");
748 for (unsigned i = 0; i < partitions.cPartitions; i++)
749 {
750 /* Suppress printing the extended partition. Otherwise people
751 * might add it to the list of partitions for raw partition
752 * access (which is not good). */
753 if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
754 continue;
755
756 RTPrintf("%-7u %#04x %-4u/%-3u/%-2u %-4u/%-3u/%-2u %10llu %10llu\n",
757 partitions.aPartitions[i].uIndex,
758 partitions.aPartitions[i].uType,
759 partitions.aPartitions[i].uStartCylinder,
760 partitions.aPartitions[i].uStartHead,
761 partitions.aPartitions[i].uStartSector,
762 partitions.aPartitions[i].uEndCylinder,
763 partitions.aPartitions[i].uEndHead,
764 partitions.aPartitions[i].uEndSector,
765 partitions.aPartitions[i].uSize / 2048,
766 partitions.aPartitions[i].uStart);
767 }
768
769 return 0;
770}
771
772static int CmdCreateRawVMDK(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
773{
774 HRESULT rc = S_OK;
775 Bstr filename;
776 const char *pszMBRFilename = NULL;
777 Utf8Str rawdisk;
778 const char *pszPartitions = NULL;
779 bool fRegister = false;
780 bool fRelative = false;
781
782 uint64_t cbSize = 0;
783 PVBOXHDD pDisk = NULL;
784 VBOXHDDRAW RawDescriptor;
785 HOSTPARTITIONS partitions;
786 uint32_t uPartitions = 0;
787 PVDINTERFACE pVDIfs = NULL;
788
789 /* let's have a closer look at the arguments */
790 for (int i = 0; i < argc; i++)
791 {
792 if (strcmp(argv[i], "-filename") == 0)
793 {
794 if (argc <= i + 1)
795 {
796 return errorArgument("Missing argument to '%s'", argv[i]);
797 }
798 i++;
799 filename = argv[i];
800 }
801 else if (strcmp(argv[i], "-mbr") == 0)
802 {
803 if (argc <= i + 1)
804 {
805 return errorArgument("Missing argument to '%s'", argv[i]);
806 }
807 i++;
808 pszMBRFilename = argv[i];
809 }
810 else if (strcmp(argv[i], "-rawdisk") == 0)
811 {
812 if (argc <= i + 1)
813 {
814 return errorArgument("Missing argument to '%s'", argv[i]);
815 }
816 i++;
817 rawdisk = argv[i];
818 }
819 else if (strcmp(argv[i], "-partitions") == 0)
820 {
821 if (argc <= i + 1)
822 {
823 return errorArgument("Missing argument to '%s'", argv[i]);
824 }
825 i++;
826 pszPartitions = argv[i];
827 }
828 else if (strcmp(argv[i], "-register") == 0)
829 {
830 fRegister = true;
831 }
832#ifdef RT_OS_LINUX
833 else if (strcmp(argv[i], "-relative") == 0)
834 {
835 fRelative = true;
836 }
837#endif /* RT_OS_LINUX */
838 else
839 {
840 return errorSyntax(USAGE_CREATERAWVMDK, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
841 }
842 }
843
844 if (filename.isEmpty())
845 return errorSyntax(USAGE_CREATERAWVMDK, "Mandatory parameter -filename missing");
846 if (rawdisk.isEmpty())
847 return errorSyntax(USAGE_CREATERAWVMDK, "Mandatory parameter -rawdisk missing");
848 if (!pszPartitions && pszMBRFilename)
849 return errorSyntax(USAGE_CREATERAWVMDK, "The parameter -mbr is only valid when the parameter -partitions is also present");
850
851 RTFILE RawFile;
852 int vrc = RTFileOpen(&RawFile, rawdisk.raw(), RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
853 if (RT_FAILURE(vrc))
854 {
855 RTPrintf("Error opening the raw disk '%s': %Rrc\n", rawdisk.raw(), vrc);
856 goto out;
857 }
858
859#ifdef RT_OS_WINDOWS
860 /* Windows NT has no IOCTL_DISK_GET_LENGTH_INFORMATION ioctl. This was
861 * added to Windows XP, so we have to use the available info from DriveGeo.
862 * Note that we cannot simply use IOCTL_DISK_GET_DRIVE_GEOMETRY as it
863 * yields a slightly different result than IOCTL_DISK_GET_LENGTH_INFO.
864 * We call IOCTL_DISK_GET_DRIVE_GEOMETRY first as we need to check the media
865 * type anyway, and if IOCTL_DISK_GET_LENGTH_INFORMATION is supported
866 * we will later override cbSize.
867 */
868 DISK_GEOMETRY DriveGeo;
869 DWORD cbDriveGeo;
870 if (DeviceIoControl((HANDLE)RawFile,
871 IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
872 &DriveGeo, sizeof(DriveGeo), &cbDriveGeo, NULL))
873 {
874 if ( DriveGeo.MediaType == FixedMedia
875 || DriveGeo.MediaType == RemovableMedia)
876 {
877 cbSize = DriveGeo.Cylinders.QuadPart
878 * DriveGeo.TracksPerCylinder
879 * DriveGeo.SectorsPerTrack
880 * DriveGeo.BytesPerSector;
881 }
882 else
883 {
884 RTPrintf("File '%s' is no fixed/removable medium device\n", rawdisk.raw());
885 vrc = VERR_INVALID_PARAMETER;
886 goto out;
887 }
888
889 GET_LENGTH_INFORMATION DiskLenInfo;
890 DWORD junk;
891 if (DeviceIoControl((HANDLE)RawFile,
892 IOCTL_DISK_GET_LENGTH_INFO, NULL, 0,
893 &DiskLenInfo, sizeof(DiskLenInfo), &junk, (LPOVERLAPPED)NULL))
894 {
895 /* IOCTL_DISK_GET_LENGTH_INFO is supported -- override cbSize. */
896 cbSize = DiskLenInfo.Length.QuadPart;
897 }
898 }
899 else
900 {
901 vrc = RTErrConvertFromWin32(GetLastError());
902 RTPrintf("Error getting the geometry of the raw disk '%s': %Rrc\n", rawdisk.raw(), vrc);
903 goto out;
904 }
905#elif defined(RT_OS_LINUX)
906 struct stat DevStat;
907 if (!fstat(RawFile, &DevStat) && S_ISBLK(DevStat.st_mode))
908 {
909#ifdef BLKGETSIZE64
910 /* BLKGETSIZE64 is broken up to 2.4.17 and in many 2.5.x. In 2.6.0
911 * it works without problems. */
912 struct utsname utsname;
913 if ( uname(&utsname) == 0
914 && ( (strncmp(utsname.release, "2.5.", 4) == 0 && atoi(&utsname.release[4]) >= 18)
915 || (strncmp(utsname.release, "2.", 2) == 0 && atoi(&utsname.release[2]) >= 6)))
916 {
917 uint64_t cbBlk;
918 if (!ioctl(RawFile, BLKGETSIZE64, &cbBlk))
919 cbSize = cbBlk;
920 }
921#endif /* BLKGETSIZE64 */
922 if (!cbSize)
923 {
924 long cBlocks;
925 if (!ioctl(RawFile, BLKGETSIZE, &cBlocks))
926 cbSize = (uint64_t)cBlocks << 9;
927 else
928 {
929 vrc = RTErrConvertFromErrno(errno);
930 RTPrintf("Error getting the size of the raw disk '%s': %Rrc\n", rawdisk.raw(), vrc);
931 goto out;
932 }
933 }
934 }
935 else
936 {
937 RTPrintf("File '%s' is no block device\n", rawdisk.raw());
938 vrc = VERR_INVALID_PARAMETER;
939 goto out;
940 }
941#elif defined(RT_OS_DARWIN)
942 struct stat DevStat;
943 if (!fstat(RawFile, &DevStat) && S_ISBLK(DevStat.st_mode))
944 {
945 uint64_t cBlocks;
946 uint32_t cbBlock;
947 if (!ioctl(RawFile, DKIOCGETBLOCKCOUNT, &cBlocks))
948 {
949 if (!ioctl(RawFile, DKIOCGETBLOCKSIZE, &cbBlock))
950 cbSize = cBlocks * cbBlock;
951 else
952 {
953 RTPrintf("Cannot get the block size for file '%s': %Rrc", rawdisk.raw(), vrc);
954 vrc = RTErrConvertFromErrno(errno);
955 goto out;
956 }
957 }
958 else
959 {
960 vrc = RTErrConvertFromErrno(errno);
961 RTPrintf("Cannot get the block count for file '%s': %Rrc", rawdisk.raw(), vrc);
962 goto out;
963 }
964 }
965 else
966 {
967 RTPrintf("File '%s' is no block device\n", rawdisk.raw());
968 vrc = VERR_INVALID_PARAMETER;
969 goto out;
970 }
971#elif defined(RT_OS_SOLARIS)
972 struct stat DevStat;
973 if (!fstat(RawFile, &DevStat) && ( S_ISBLK(DevStat.st_mode)
974 || S_ISCHR(DevStat.st_mode)))
975 {
976 struct dk_minfo mediainfo;
977 if (!ioctl(RawFile, DKIOCGMEDIAINFO, &mediainfo))
978 cbSize = mediainfo.dki_capacity * mediainfo.dki_lbsize;
979 else
980 {
981 vrc = RTErrConvertFromErrno(errno);
982 RTPrintf("Error getting the size of the raw disk '%s': %Rrc\n", rawdisk.raw(), vrc);
983 goto out;
984 }
985 }
986 else
987 {
988 RTPrintf("File '%s' is no block or char device\n", rawdisk.raw());
989 vrc = VERR_INVALID_PARAMETER;
990 goto out;
991 }
992#else /* all unrecognized OSes */
993 /* Hopefully this works on all other hosts. If it doesn't, it'll just fail
994 * creating the VMDK, so no real harm done. */
995 vrc = RTFileGetSize(RawFile, &cbSize);
996 if (RT_FAILURE(vrc))
997 {
998 RTPrintf("Error getting the size of the raw disk '%s': %Rrc\n", rawdisk.raw(), vrc);
999 goto out;
1000 }
1001#endif
1002
1003 /* Check whether cbSize is actually sensible. */
1004 if (!cbSize || cbSize % 512)
1005 {
1006 RTPrintf("Detected size of raw disk '%s' is %s, an invalid value\n", rawdisk.raw(), cbSize);
1007 vrc = VERR_INVALID_PARAMETER;
1008 goto out;
1009 }
1010
1011 RawDescriptor.szSignature[0] = 'R';
1012 RawDescriptor.szSignature[1] = 'A';
1013 RawDescriptor.szSignature[2] = 'W';
1014 RawDescriptor.szSignature[3] = '\0';
1015 if (!pszPartitions)
1016 {
1017 RawDescriptor.fRawDisk = true;
1018 RawDescriptor.pszRawDisk = rawdisk.raw();
1019 }
1020 else
1021 {
1022 RawDescriptor.fRawDisk = false;
1023 RawDescriptor.pszRawDisk = NULL;
1024 RawDescriptor.cPartitions = 0;
1025
1026 const char *p = pszPartitions;
1027 char *pszNext;
1028 uint32_t u32;
1029 while (*p != '\0')
1030 {
1031 vrc = RTStrToUInt32Ex(p, &pszNext, 0, &u32);
1032 if (RT_FAILURE(vrc))
1033 {
1034 RTPrintf("Incorrect value in partitions parameter\n");
1035 goto out;
1036 }
1037 uPartitions |= RT_BIT(u32);
1038 p = pszNext;
1039 if (*p == ',')
1040 p++;
1041 else if (*p != '\0')
1042 {
1043 RTPrintf("Incorrect separator in partitions parameter\n");
1044 vrc = VERR_INVALID_PARAMETER;
1045 goto out;
1046 }
1047 }
1048
1049 vrc = partRead(RawFile, &partitions);
1050 if (RT_FAILURE(vrc))
1051 {
1052 RTPrintf("Error reading the partition information from '%s'\n", rawdisk.raw());
1053 goto out;
1054 }
1055
1056 for (unsigned i = 0; i < partitions.cPartitions; i++)
1057 {
1058 if ( uPartitions & RT_BIT(partitions.aPartitions[i].uIndex)
1059 && PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
1060 {
1061 /* Some ignorant user specified an extended partition.
1062 * Bad idea, as this would trigger an overlapping
1063 * partitions error later during VMDK creation. So warn
1064 * here and ignore what the user requested. */
1065 RTPrintf("Warning: it is not possible (and necessary) to explicitly give access to the\n"
1066 " extended partition %u. If required, enable access to all logical\n"
1067 " partitions inside this extended partition.\n", partitions.aPartitions[i].uIndex);
1068 uPartitions &= ~RT_BIT(partitions.aPartitions[i].uIndex);
1069 }
1070 }
1071
1072 RawDescriptor.cPartitions = partitions.cPartitions;
1073 RawDescriptor.pPartitions = (PVBOXHDDRAWPART)RTMemAllocZ(partitions.cPartitions * sizeof(VBOXHDDRAWPART));
1074 if (!RawDescriptor.pPartitions)
1075 {
1076 RTPrintf("Out of memory allocating the partition list for '%s'\n", rawdisk.raw());
1077 vrc = VERR_NO_MEMORY;
1078 goto out;
1079 }
1080 for (unsigned i = 0; i < partitions.cPartitions; i++)
1081 {
1082 if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
1083 {
1084 if (fRelative)
1085 {
1086#ifdef RT_OS_LINUX
1087 /* Refer to the correct partition and use offset 0. */
1088 char *pszRawName;
1089 vrc = RTStrAPrintf(&pszRawName, "%s%u", rawdisk.raw(),
1090 partitions.aPartitions[i].uIndex);
1091 if (RT_FAILURE(vrc))
1092 {
1093 RTPrintf("Error creating reference to individual partition %u, rc=%Rrc\n",
1094 partitions.aPartitions[i].uIndex, vrc);
1095 goto out;
1096 }
1097 RawDescriptor.pPartitions[i].pszRawDevice = pszRawName;
1098 RawDescriptor.pPartitions[i].uPartitionStartOffset = 0;
1099 RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
1100#else
1101 /** @todo not implemented yet for Windows host. Treat just
1102 * like not specified (this code is actually never reached). */
1103 RawDescriptor.pPartitions[i].pszRawDevice = rawdisk.raw();
1104 RawDescriptor.pPartitions[i].uPartitionStartOffset = partitions.aPartitions[i].uStart * 512;
1105 RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
1106#endif
1107 }
1108 else
1109 {
1110 /* This is the "everything refers to the base raw device"
1111 * variant. This requires opening the base device in RW
1112 * mode even for creation. */
1113 RawDescriptor.pPartitions[i].pszRawDevice = rawdisk.raw();
1114 RawDescriptor.pPartitions[i].uPartitionStartOffset = partitions.aPartitions[i].uStart * 512;
1115 RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
1116 }
1117 }
1118 else
1119 {
1120 /* Suppress access to this partition. */
1121 RawDescriptor.pPartitions[i].pszRawDevice = NULL;
1122 RawDescriptor.pPartitions[i].uPartitionStartOffset = 0;
1123 /* This is used in the plausibility check in the creation
1124 * code. In theory it's a dummy, but I don't want to make
1125 * the VMDK creatiion any more complicated than what it needs
1126 * to be. */
1127 RawDescriptor.pPartitions[i].uPartitionStart = partitions.aPartitions[i].uStart * 512;
1128 }
1129 if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
1130 {
1131 /* Suppress exporting the actual extended partition. Only
1132 * logical partitions should be processed. However completely
1133 * ignoring it leads to leaving out the MBR data. */
1134 RawDescriptor.pPartitions[i].cbPartition = 0;
1135 }
1136 else
1137 RawDescriptor.pPartitions[i].cbPartition = partitions.aPartitions[i].uSize * 512;
1138 RawDescriptor.pPartitions[i].uPartitionDataStart = partitions.aPartitions[i].uPartDataStart * 512;
1139 RawDescriptor.pPartitions[i].cbPartitionData = partitions.aPartitions[i].cPartDataSectors * 512;
1140 if (RawDescriptor.pPartitions[i].cbPartitionData)
1141 {
1142 Assert (RawDescriptor.pPartitions[i].cbPartitionData -
1143 (size_t)RawDescriptor.pPartitions[i].cbPartitionData == 0);
1144 void *pPartData = RTMemAlloc((size_t)RawDescriptor.pPartitions[i].cbPartitionData);
1145 if (!pPartData)
1146 {
1147 RTPrintf("Out of memory allocating the partition descriptor for '%s'\n", rawdisk.raw());
1148 vrc = VERR_NO_MEMORY;
1149 goto out;
1150 }
1151 vrc = RTFileReadAt(RawFile, partitions.aPartitions[i].uPartDataStart * 512, pPartData, (size_t)RawDescriptor.pPartitions[i].cbPartitionData, NULL);
1152 if (RT_FAILURE(vrc))
1153 {
1154 RTPrintf("Cannot read partition data from raw device '%s': %Rrc\n", rawdisk.raw(), vrc);
1155 goto out;
1156 }
1157 /* Splice in the replacement MBR code if specified. */
1158 if ( partitions.aPartitions[i].uPartDataStart == 0
1159 && pszMBRFilename)
1160 {
1161 RTFILE MBRFile;
1162 vrc = RTFileOpen(&MBRFile, pszMBRFilename, RTFILE_O_OPEN | RTFILE_O_READ | RTFILE_O_DENY_WRITE);
1163 if (RT_FAILURE(vrc))
1164 {
1165 RTPrintf("Cannot open replacement MBR file '%s' specified with -mbr: %Rrc\n", pszMBRFilename, vrc);
1166 goto out;
1167 }
1168 vrc = RTFileReadAt(MBRFile, 0, pPartData, 0x1be, NULL);
1169 RTFileClose(MBRFile);
1170 if (RT_FAILURE(vrc))
1171 {
1172 RTPrintf("Cannot read replacement MBR file '%s': %Rrc\n", pszMBRFilename, vrc);
1173 goto out;
1174 }
1175 }
1176 RawDescriptor.pPartitions[i].pvPartitionData = pPartData;
1177 }
1178 }
1179 }
1180
1181 RTFileClose(RawFile);
1182
1183 VDINTERFACE vdInterfaceError;
1184 VDINTERFACEERROR vdInterfaceErrorCallbacks;
1185 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1186 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1187 vdInterfaceErrorCallbacks.pfnError = handleVDError;
1188
1189 vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1190 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
1191 AssertRC(vrc);
1192
1193 vrc = VDCreate(pVDIfs, &pDisk);
1194 if (RT_FAILURE(vrc))
1195 {
1196 RTPrintf("Error while creating the virtual disk container: %Rrc\n", vrc);
1197 goto out;
1198 }
1199
1200 Assert(RT_MIN(cbSize / 512 / 16 / 63, 16383) -
1201 (unsigned int)RT_MIN(cbSize / 512 / 16 / 63, 16383) == 0);
1202 PDMMEDIAGEOMETRY PCHS, LCHS;
1203 PCHS.cCylinders = (unsigned int)RT_MIN(cbSize / 512 / 16 / 63, 16383);
1204 PCHS.cHeads = 16;
1205 PCHS.cSectors = 63;
1206 LCHS.cCylinders = 0;
1207 LCHS.cHeads = 0;
1208 LCHS.cSectors = 0;
1209 vrc = VDCreateBase(pDisk, "VMDK", Utf8Str(filename).raw(),
1210 VD_IMAGE_TYPE_FIXED, cbSize,
1211 VD_VMDK_IMAGE_FLAGS_RAWDISK, (char *)&RawDescriptor,
1212 &PCHS, &LCHS, NULL, VD_OPEN_FLAGS_NORMAL, NULL, NULL);
1213 if (RT_FAILURE(vrc))
1214 {
1215 RTPrintf("Error while creating the raw disk VMDK: %Rrc\n", vrc);
1216 goto out;
1217 }
1218 RTPrintf("RAW host disk access VMDK file %s created successfully.\n", Utf8Str(filename).raw());
1219
1220 VDCloseAll(pDisk);
1221
1222 /* Clean up allocated memory etc. */
1223 if (pszPartitions)
1224 {
1225 for (unsigned i = 0; i < partitions.cPartitions; i++)
1226 {
1227 if (uPartitions & RT_BIT(partitions.aPartitions[i].uIndex))
1228 {
1229 if (fRelative)
1230 {
1231#ifdef RT_OS_LINUX
1232 /* Free memory allocated above. */
1233 RTStrFree((char *)(void *)RawDescriptor.pPartitions[i].pszRawDevice);
1234#endif /* RT_OS_LINUX */
1235 }
1236 }
1237 }
1238 }
1239
1240 if (fRegister)
1241 {
1242 ComPtr<IHardDisk2> hardDisk;
1243 CHECK_ERROR(aVirtualBox, OpenHardDisk2(filename, hardDisk.asOutParam()));
1244 }
1245
1246 return SUCCEEDED(rc) ? 0 : 1;
1247
1248out:
1249 RTPrintf("The raw disk vmdk file was not created\n");
1250 return RT_SUCCESS(vrc) ? 0 : 1;
1251}
1252
1253static int CmdRenameVMDK(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
1254{
1255 Bstr src;
1256 Bstr dst;
1257 /* Parse the arguments. */
1258 for (int i = 0; i < argc; i++)
1259 {
1260 if (strcmp(argv[i], "-from") == 0)
1261 {
1262 if (argc <= i + 1)
1263 {
1264 return errorArgument("Missing argument to '%s'", argv[i]);
1265 }
1266 i++;
1267 src = argv[i];
1268 }
1269 else if (strcmp(argv[i], "-to") == 0)
1270 {
1271 if (argc <= i + 1)
1272 {
1273 return errorArgument("Missing argument to '%s'", argv[i]);
1274 }
1275 i++;
1276 dst = argv[i];
1277 }
1278 else
1279 {
1280 return errorSyntax(USAGE_RENAMEVMDK, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
1281 }
1282 }
1283
1284 if (src.isEmpty())
1285 return errorSyntax(USAGE_RENAMEVMDK, "Mandatory parameter -from missing");
1286 if (dst.isEmpty())
1287 return errorSyntax(USAGE_RENAMEVMDK, "Mandatory parameter -to missing");
1288
1289 PVBOXHDD pDisk = NULL;
1290
1291 PVDINTERFACE pVDIfs = NULL;
1292 VDINTERFACE vdInterfaceError;
1293 VDINTERFACEERROR vdInterfaceErrorCallbacks;
1294 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1295 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1296 vdInterfaceErrorCallbacks.pfnError = handleVDError;
1297
1298 int vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1299 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
1300 AssertRC(vrc);
1301
1302 vrc = VDCreate(pVDIfs, &pDisk);
1303 if (RT_FAILURE(vrc))
1304 {
1305 RTPrintf("Error while creating the virtual disk container: %Rrc\n", vrc);
1306 return vrc;
1307 }
1308 else
1309 {
1310 vrc = VDOpen(pDisk, "VMDK", Utf8Str(src).raw(), VD_OPEN_FLAGS_NORMAL, NULL);
1311 if (RT_FAILURE(vrc))
1312 {
1313 RTPrintf("Error while opening the source image: %Rrc\n", vrc);
1314 }
1315 else
1316 {
1317 vrc = VDCopy(pDisk, 0, pDisk, "VMDK", Utf8Str(dst).raw(), true, 0, NULL, NULL, NULL);
1318 if (RT_FAILURE(vrc))
1319 {
1320 RTPrintf("Error while renaming the image: %Rrc\n", vrc);
1321 }
1322 }
1323 }
1324 VDCloseAll(pDisk);
1325 return vrc;
1326}
1327
1328static int CmdConvertToRaw(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
1329{
1330 Bstr srcformat;
1331 Bstr src;
1332 Bstr dst;
1333 bool fWriteToStdOut = false;
1334
1335 /* Parse the arguments. */
1336 for (int i = 0; i < argc; i++)
1337 {
1338 if (strcmp(argv[i], "-format") == 0)
1339 {
1340 if (argc <= i + 1)
1341 {
1342 return errorArgument("Missing argument to '%s'", argv[i]);
1343 }
1344 i++;
1345 srcformat = argv[i];
1346 }
1347 else if (src.isEmpty())
1348 {
1349 src = argv[i];
1350 }
1351 else if (dst.isEmpty())
1352 {
1353 dst = argv[i];
1354#ifdef ENABLE_CONVERT_RAW_TO_STDOUT
1355 if (!strcmp(argv[i], "stdout"))
1356 fWriteToStdOut = true;
1357#endif /* ENABLE_CONVERT_RAW_TO_STDOUT */
1358 }
1359 else
1360 {
1361 return errorSyntax(USAGE_CONVERTTORAW, "Invalid parameter '%s'", Utf8Str(argv[i]).raw());
1362 }
1363 }
1364
1365 if (src.isEmpty())
1366 return errorSyntax(USAGE_CONVERTTORAW, "Mandatory filename parameter missing");
1367 if (dst.isEmpty())
1368 return errorSyntax(USAGE_CONVERTTORAW, "Mandatory outputfile parameter missing");
1369
1370 PVBOXHDD pDisk = NULL;
1371
1372 PVDINTERFACE pVDIfs = NULL;
1373 VDINTERFACE vdInterfaceError;
1374 VDINTERFACEERROR vdInterfaceErrorCallbacks;
1375 vdInterfaceErrorCallbacks.cbSize = sizeof(VDINTERFACEERROR);
1376 vdInterfaceErrorCallbacks.enmInterface = VDINTERFACETYPE_ERROR;
1377 vdInterfaceErrorCallbacks.pfnError = handleVDError;
1378
1379 int vrc = VDInterfaceAdd(&vdInterfaceError, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1380 &vdInterfaceErrorCallbacks, NULL, &pVDIfs);
1381 AssertRC(vrc);
1382
1383 vrc = VDCreate(pVDIfs, &pDisk);
1384 if (RT_FAILURE(vrc))
1385 {
1386 RTPrintf("Error while creating the virtual disk container: %Rrc\n", vrc);
1387 return 1;
1388 }
1389
1390 /* Open raw output file. */
1391 RTFILE outFile;
1392 vrc = VINF_SUCCESS;
1393 if (fWriteToStdOut)
1394 outFile = 1;
1395 else
1396 vrc = RTFileOpen(&outFile, Utf8Str(dst).raw(), RTFILE_O_OPEN | RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL);
1397 if (RT_FAILURE(vrc))
1398 {
1399 VDCloseAll(pDisk);
1400 RTPrintf("Error while creating destination file \"%s\": %Rrc\n", Utf8Str(dst).raw(), vrc);
1401 return 1;
1402 }
1403
1404 if (srcformat.isEmpty())
1405 {
1406 char *pszFormat = NULL;
1407 vrc = VDGetFormat(Utf8Str(src).raw(), &pszFormat);
1408 if (RT_FAILURE(vrc))
1409 {
1410 VDCloseAll(pDisk);
1411 if (!fWriteToStdOut)
1412 {
1413 RTFileClose(outFile);
1414 RTFileDelete(Utf8Str(dst).raw());
1415 }
1416 RTPrintf("No file format specified and autodetect failed - please specify format: %Rrc\n", vrc);
1417 return 1;
1418 }
1419 srcformat = pszFormat;
1420 RTStrFree(pszFormat);
1421 }
1422 vrc = VDOpen(pDisk, Utf8Str(srcformat).raw(), Utf8Str(src).raw(), VD_OPEN_FLAGS_READONLY, NULL);
1423 if (RT_FAILURE(vrc))
1424 {
1425 VDCloseAll(pDisk);
1426 if (!fWriteToStdOut)
1427 {
1428 RTFileClose(outFile);
1429 RTFileDelete(Utf8Str(dst).raw());
1430 }
1431 RTPrintf("Error while opening the source image: %Rrc\n", vrc);
1432 return 1;
1433 }
1434
1435 uint64_t cbSize = VDGetSize(pDisk, VD_LAST_IMAGE);
1436 uint64_t offFile = 0;
1437#define RAW_BUFFER_SIZE _128K
1438 uint64_t cbBuf = RAW_BUFFER_SIZE;
1439 void *pvBuf = RTMemAlloc(cbBuf);
1440 if (pvBuf)
1441 {
1442 RTPrintf("Converting image \"%s\" with size %RU64 bytes (%RU64MB) to raw...\n", Utf8Str(src).raw(), cbSize, (cbSize + _1M - 1) / _1M);
1443 while (offFile < cbSize)
1444 {
1445 size_t cb = cbSize - offFile >= (uint64_t)cbBuf ? cbBuf : (size_t)(cbSize - offFile);
1446 vrc = VDRead(pDisk, offFile, pvBuf, cb);
1447 if (RT_FAILURE(vrc))
1448 break;
1449 vrc = RTFileWrite(outFile, pvBuf, cb, NULL);
1450 if (RT_FAILURE(vrc))
1451 break;
1452 offFile += cb;
1453 }
1454 if (RT_FAILURE(vrc))
1455 {
1456 VDCloseAll(pDisk);
1457 if (!fWriteToStdOut)
1458 {
1459 RTFileClose(outFile);
1460 RTFileDelete(Utf8Str(dst).raw());
1461 }
1462 RTPrintf("Error copying image data: %Rrc\n", vrc);
1463 return 1;
1464 }
1465 }
1466 else
1467 {
1468 vrc = VERR_NO_MEMORY;
1469 VDCloseAll(pDisk);
1470 if (!fWriteToStdOut)
1471 {
1472 RTFileClose(outFile);
1473 RTFileDelete(Utf8Str(dst).raw());
1474 }
1475 RTPrintf("Error allocating read buffer: %Rrc\n", vrc);
1476 return 1;
1477 }
1478
1479 if (!fWriteToStdOut)
1480 RTFileClose(outFile);
1481 VDCloseAll(pDisk);
1482 return 0;
1483}
1484
1485/**
1486 * Unloads the neccessary driver.
1487 *
1488 * @returns VBox status code
1489 */
1490int CmdModUninstall(void)
1491{
1492 int rc;
1493
1494 rc = SUPUninstall();
1495 if (RT_SUCCESS(rc))
1496 return 0;
1497 if (rc == VERR_NOT_IMPLEMENTED)
1498 return 0;
1499 return E_FAIL;
1500}
1501
1502/**
1503 * Loads the neccessary driver.
1504 *
1505 * @returns VBox status code
1506 */
1507int CmdModInstall(void)
1508{
1509 int rc;
1510
1511 rc = SUPInstall();
1512 if (RT_SUCCESS(rc))
1513 return 0;
1514 if (rc == VERR_NOT_IMPLEMENTED)
1515 return 0;
1516 return E_FAIL;
1517}
1518
1519/**
1520 * Wrapper for handling internal commands
1521 */
1522int handleInternalCommands(int argc, char *argv[],
1523 ComPtr <IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
1524{
1525 g_fInternalMode = true;
1526
1527 /* at least a command is required */
1528 if (argc < 1)
1529 return errorSyntax(USAGE_ALL, "Command missing");
1530
1531 /*
1532 * The 'string switch' on command name.
1533 */
1534 const char *pszCmd = argv[0];
1535 if (!strcmp(pszCmd, "loadsyms"))
1536 return CmdLoadSyms(argc - 1, &argv[1], aVirtualBox, aSession);
1537 //if (!strcmp(pszCmd, "unloadsyms"))
1538 // return CmdUnloadSyms(argc - 1 , &argv[1]);
1539 if (!strcmp(pszCmd, "sethduuid") || !strcmp(pszCmd, "setvdiuuid"))
1540 return handleSetHDUUID(argc - 1, &argv[1], aVirtualBox, aSession);
1541 if (!strcmp(pszCmd, "listpartitions"))
1542 return CmdListPartitions(argc - 1, &argv[1], aVirtualBox, aSession);
1543 if (!strcmp(pszCmd, "createrawvmdk"))
1544 return CmdCreateRawVMDK(argc - 1, &argv[1], aVirtualBox, aSession);
1545 if (!strcmp(pszCmd, "renamevmdk"))
1546 return CmdRenameVMDK(argc - 1, &argv[1], aVirtualBox, aSession);
1547 if (!strcmp(pszCmd, "converttoraw"))
1548 return CmdConvertToRaw(argc - 1, &argv[1], aVirtualBox, aSession);
1549
1550 if (!strcmp(pszCmd, "modinstall"))
1551 return CmdModInstall();
1552 if (!strcmp(pszCmd, "moduninstall"))
1553 return CmdModUninstall();
1554
1555 /* default: */
1556 return errorSyntax(USAGE_ALL, "Invalid command '%s'", Utf8Str(argv[0]).raw());
1557}
1558
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