VirtualBox

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

Last change on this file since 10658 was 9975, checked in by vboxsync, 17 years ago

Fix incorrect 63 sector minimum logical partition start offset. Also separate sorting from consistency checking.

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