VirtualBox

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

Last change on this file was 99739, checked in by vboxsync, 12 months ago

*: doxygen corrections (mostly about removing @returns from functions returning void).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 75.0 KB
RevLine 
[14831]1/* $Id: VBoxInternalManage.cpp 99739 2023-05-11 01:01:08Z vboxsync $ */
[1]2/** @file
[14732]3 * VBoxManage - The 'internalcommands' command.
[1]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/*
[98103]11 * Copyright (C) 2006-2023 Oracle and/or its affiliates.
[1]12 *
[96407]13 * This file is part of VirtualBox base platform packages, as
14 * available from https://www.virtualbox.org.
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation, in version 3 of the
19 * License.
20 *
21 * This program is distributed in the hope that it will be useful, but
22 * WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
24 * General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, see <https://www.gnu.org/licenses>.
28 *
29 * SPDX-License-Identifier: GPL-3.0-only
[1]30 */
31
32
33
[57358]34/*********************************************************************************************************************************
35* Header Files *
36*********************************************************************************************************************************/
[1]37#include <VBox/com/com.h>
38#include <VBox/com/string.h>
39#include <VBox/com/Guid.h>
40#include <VBox/com/ErrorInfo.h>
[20928]41#include <VBox/com/errorprint.h>
[1]42
43#include <VBox/com/VirtualBox.h>
44
[33567]45#include <VBox/vd.h>
[14831]46#include <VBox/sup.h>
47#include <VBox/log.h>
[94240]48#include <VBox/version.h>
[14831]49
[94240]50#include <iprt/buildconfig.h>
[60025]51#include <iprt/ctype.h>
[14831]52#include <iprt/file.h>
[30319]53#include <iprt/getopt.h>
[1]54#include <iprt/stream.h>
55#include <iprt/string.h>
56#include <iprt/uuid.h>
[33228]57#include <iprt/sha.h>
[1]58
59#include "VBoxManage.h"
60
[8230]61/* Includes for the raw disk stuff. */
62#ifdef RT_OS_WINDOWS
[62679]63# include <iprt/win/windows.h>
[14732]64# include <winioctl.h>
[27133]65#elif defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) \
66 || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD)
[14732]67# include <errno.h>
68# include <sys/ioctl.h>
69# include <sys/types.h>
70# include <sys/stat.h>
71# include <fcntl.h>
72# include <unistd.h>
[8811]73#endif
74#ifdef RT_OS_LINUX
[14732]75# include <sys/utsname.h>
76# include <linux/hdreg.h>
77# include <linux/fs.h>
[14838]78# include <stdlib.h> /* atoi() */
[8811]79#endif /* RT_OS_LINUX */
80#ifdef RT_OS_DARWIN
[14732]81# include <sys/disk.h>
[8811]82#endif /* RT_OS_DARWIN */
[8835]83#ifdef RT_OS_SOLARIS
[14732]84# include <stropts.h>
85# include <sys/dkio.h>
86# include <sys/vtoc.h>
[8835]87#endif /* RT_OS_SOLARIS */
[27133]88#ifdef RT_OS_FREEBSD
89# include <sys/disk.h>
90#endif /* RT_OS_FREEBSD */
[2675]91
[1]92using namespace com;
93
[8230]94
95/** Macro for checking whether a partition is of extended type or not. */
96#define PARTTYPE_IS_EXTENDED(x) ((x) == 0x05 || (x) == 0x0f || (x) == 0x85)
97
[30319]98/** Maximum number of partitions we can deal with.
99 * Ridiculously large number, but the memory consumption is rather low so who
100 * cares about never using most entries. */
[8230]101#define HOSTPARTITION_MAX 100
102
[92372]103DECLARE_TRANSLATION_CONTEXT(Internal);
[8230]104
[92372]105
[8230]106typedef struct HOSTPARTITION
107{
[43207]108 /** partition number */
[8230]109 unsigned uIndex;
[56918]110 /** partition number (internal only, windows specific numbering) */
111 unsigned uIndexWin;
[18164]112 /** partition type */
[8230]113 unsigned uType;
[18164]114 /** CHS/cylinder of the first sector */
[8230]115 unsigned uStartCylinder;
[18164]116 /** CHS/head of the first sector */
[8230]117 unsigned uStartHead;
[18164]118 /** CHS/head of the first sector */
[8230]119 unsigned uStartSector;
[18164]120 /** CHS/cylinder of the last sector */
[8230]121 unsigned uEndCylinder;
[18164]122 /** CHS/head of the last sector */
[8230]123 unsigned uEndHead;
[18164]124 /** CHS/sector of the last sector */
[8230]125 unsigned uEndSector;
[18164]126 /** start sector of this partition relative to the beginning of the hard
127 * disk or relative to the beginning of the extended partition table */
[8230]128 uint64_t uStart;
[18164]129 /** numer of sectors of the partition */
[8230]130 uint64_t uSize;
[18164]131 /** start sector of this partition _table_ */
[8230]132 uint64_t uPartDataStart;
[18164]133 /** numer of sectors of this partition _table_ */
[8230]134 uint64_t cPartDataSectors;
135} HOSTPARTITION, *PHOSTPARTITION;
136
137typedef struct HOSTPARTITIONS
138{
[42860]139 /** partitioning type - MBR or GPT */
[85221]140 VDISKPARTTYPE uPartitioningType;
[8230]141 unsigned cPartitions;
142 HOSTPARTITION aPartitions[HOSTPARTITION_MAX];
143} HOSTPARTITIONS, *PHOSTPARTITIONS;
144
[1]145
[94290]146/** @name Syntax diagram category, i.e. the command.
147 * @{ */
148typedef enum
149{
150 USAGE_INVALID = 0,
151 USAGE_I_LOADSYMS,
152 USAGE_I_LOADMAP,
153 USAGE_I_SETHDUUID,
154 USAGE_I_LISTPARTITIONS,
155 USAGE_I_CREATERAWVMDK,
156 USAGE_I_MODINSTALL,
157 USAGE_I_MODUNINSTALL,
158 USAGE_I_RENAMEVMDK,
159 USAGE_I_CONVERTTORAW,
160 USAGE_I_CONVERTHD,
161 USAGE_I_DUMPHDINFO,
162 USAGE_I_DEBUGLOG,
163 USAGE_I_SETHDPARENTUUID,
164 USAGE_I_PASSWORDHASH,
165 USAGE_I_GUESTSTATS,
166 USAGE_I_REPAIRHD,
167 USAGE_I_ALL
168} USAGECATEGORY;
169/** @} */
170
171
[1]172/**
173 * Print the usage info.
174 */
[94240]175static void printUsageInternal(USAGECATEGORY enmCommand, PRTSTREAM pStrm)
[1]176{
[77595]177 Assert(enmCommand != USAGE_INVALID);
[32709]178 RTStrmPrintf(pStrm,
[92372]179 Internal::tr(
180 "Usage: VBoxManage internalcommands <command> [command arguments]\n"
181 "\n"
182 "Commands:\n"
183 "\n"
184 "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
[97313]185 "WARNING: This is a development tool and should only be used to analyse\n"
[92372]186 " problems. It is completely unsupported and will change in\n"
187 " incompatible ways without warning.\n"),
[30319]188
[94290]189 (enmCommand == USAGE_I_LOADMAP || enmCommand == USAGE_I_ALL)
[92372]190 ? Internal::tr(
191 " loadmap <vmname|uuid> <symfile> <address> [module] [subtrahend] [segment]\n"
192 " This will instruct DBGF to load the given map file\n"
193 " during initialization. (See also loadmap in the debugger.)\n"
194 "\n")
[39477]195 : "",
[94290]196 (enmCommand == USAGE_I_LOADSYMS || enmCommand == USAGE_I_ALL)
[92372]197 ? Internal::tr(
198 " loadsyms <vmname|uuid> <symfile> [delta] [module] [module address]\n"
199 " This will instruct DBGF to load the given symbol file\n"
200 " during initialization.\n"
201 "\n")
[32701]202 : "",
[94290]203 (enmCommand == USAGE_I_SETHDUUID || enmCommand == USAGE_I_ALL)
[92372]204 ? Internal::tr(
205 " sethduuid <filepath> [<uuid>]\n"
206 " Assigns a new UUID to the given image file. This way, multiple copies\n"
207 " of a container can be registered.\n"
208 "\n")
[32701]209 : "",
[94290]210 (enmCommand == USAGE_I_SETHDPARENTUUID || enmCommand == USAGE_I_ALL)
[92372]211 ? Internal::tr(
212 " sethdparentuuid <filepath> <uuid>\n"
213 " Assigns a new parent UUID to the given image file.\n"
214 "\n")
[32701]215 : "",
[94290]216 (enmCommand == USAGE_I_DUMPHDINFO || enmCommand == USAGE_I_ALL)
[92372]217 ? Internal::tr(
218 " dumphdinfo <filepath>\n"
[32701]219 " Prints information about the image at the given location.\n"
[92372]220 "\n")
[32701]221 : "",
[94290]222 (enmCommand == USAGE_I_LISTPARTITIONS || enmCommand == USAGE_I_ALL)
[92372]223 ? Internal::tr(
224 " listpartitions -rawdisk <diskname>\n"
225 " Lists all partitions on <diskname>.\n"
226 "\n")
[32701]227 : "",
[94290]228 (enmCommand == USAGE_I_CREATERAWVMDK || enmCommand == USAGE_I_ALL)
[92372]229 ? Internal::tr(
[97313]230 " createrawvmdk --filename <filename> --rawdisk <diskname>\n"
231 " [--partitions <list of partition numbers> [--mbr <filename>] ]\n"
232 " [--relative]\n"
233 " Creates a new VMDK image which gives direct access to a physical hard\n"
234 " disk on the host. The entire disk can be presented to the guest or\n"
235 " just specific partitions specified using the --partitions parameter.\n"
236 " If access to individual partitions is granted, then the --mbr parameter\n"
237 " can be used to specify an alternative Master Boot Record (MBR) (note\n"
238 " that the partitioning information in the MBR file is ignored). The\n"
239 " format of the diskname argument for the --rawdisk parameter varies by\n"
240 " platform but can be determined using the command:\n"
241 " VBoxManage list hostdrives\n"
242 " The output lists the available drives and their partitions along with\n"
243 " their partition types and sizes.\n"
244 " On Linux, FreeBSD, and Windows hosts the --relative parameter creates a\n"
245 " VMDK image file which references the specified individual partitions\n"
246 " directly instead of referencing the partitions by their offset from\n"
247 " the start of the physical disk.\n"
248 "\n"
249 " Nota Bene: The 'createrawvdk' subcommand is deprecated. The equivalent\n"
250 " functionality is available using the 'VBoxManage createmedium' command\n"
251 " and should be used instead. See 'VBoxManage help createmedium' for\n"
252 " details.\n"
[92372]253 "\n")
[32701]254 : "",
[94290]255 (enmCommand == USAGE_I_RENAMEVMDK || enmCommand == USAGE_I_ALL)
[92372]256 ? Internal::tr(
257 " renamevmdk -from <filename> -to <filename>\n"
258 " Renames an existing VMDK image, including the base file and all its extents.\n"
259 "\n")
[32701]260 : "",
[94290]261 (enmCommand == USAGE_I_CONVERTTORAW || enmCommand == USAGE_I_ALL)
[11066]262#ifdef ENABLE_CONVERT_RAW_TO_STDOUT
[92372]263 ? Internal::tr(
264 " converttoraw [-format <fileformat>] <filename> <outputfile>|stdout"
265 "\n"
266 " Convert image to raw, writing to file or stdout.\n"
267 "\n")
268#else
269 ? Internal::tr(
270 " converttoraw [-format <fileformat>] <filename> <outputfile>"
271 "\n"
272 " Convert image to raw, writing to file.\n"
273 "\n")
274#endif
[32701]275 : "",
[94290]276 (enmCommand == USAGE_I_CONVERTHD || enmCommand == USAGE_I_ALL)
[92372]277 ? Internal::tr(
278 " converthd [-srcformat VDI|VMDK|VHD|RAW]\n"
279 " [-dstformat VDI|VMDK|VHD|RAW]\n"
280 " <inputfile> <outputfile>\n"
281 " converts hard disk images between formats\n"
282 "\n")
[32701]283 : "",
[94290]284 (enmCommand == USAGE_I_REPAIRHD || enmCommand == USAGE_I_ALL)
[92372]285 ? Internal::tr(
286 " repairhd [-dry-run]\n"
287 " [-format VDI|VMDK|VHD|...]\n"
288 " <filename>\n"
289 " Tries to repair corrupted disk images\n"
290 "\n")
[39576]291 : "",
[5896]292#ifdef RT_OS_WINDOWS
[94290]293 (enmCommand == USAGE_I_MODINSTALL || enmCommand == USAGE_I_ALL)
[92372]294 ? Internal::tr(
295 " modinstall\n"
296 " Installs the necessary driver for the host OS\n"
297 "\n")
[32701]298 : "",
[94290]299 (enmCommand == USAGE_I_MODUNINSTALL || enmCommand == USAGE_I_ALL)
[92372]300 ? Internal::tr(
301 " moduninstall\n"
302 " Deinstalls the driver\n"
303 "\n")
[32701]304 : "",
[5896]305#else
[32701]306 "",
307 "",
[5896]308#endif
[94290]309 (enmCommand == USAGE_I_DEBUGLOG || enmCommand == USAGE_I_ALL)
[92372]310 ? Internal::tr(
311 " debuglog <vmname|uuid> [--enable|--disable] [--flags todo]\n"
312 " [--groups todo] [--destinations todo]\n"
313 " Controls debug logging.\n"
314 "\n")
[33228]315 : "",
[94290]316 (enmCommand == USAGE_I_PASSWORDHASH || enmCommand == USAGE_I_ALL)
[92372]317 ? Internal::tr(
318 " passwordhash <password>\n"
319 " Generates a password hash.\n"
320 "\n")
[36067]321 : "",
[94290]322 (enmCommand == USAGE_I_GUESTSTATS || enmCommand == USAGE_I_ALL)
[92372]323 ? Internal::tr(
324 " gueststats <vmname|uuid> [--interval <seconds>]\n"
325 " Obtains and prints internal guest statistics.\n"
326 " Sets the update interval if specified.\n"
327 "\n")
[36067]328 : ""
[32701]329 );
[1]330}
331
[94240]332
333/**
334 * Print a usage synopsis and the syntax error message.
335 * @returns RTEXITCODE_SYNTAX.
336 */
337static RTEXITCODE errorSyntaxInternal(USAGECATEGORY enmCommand, const char *pszFormat, ...)
338{
339 va_list args;
340 showLogo(g_pStdErr); // show logo even if suppressed
341
342 printUsageInternal(enmCommand, g_pStdErr);
343
344 va_start(args, pszFormat);
345 RTStrmPrintf(g_pStdErr, Internal::tr("\nSyntax error: %N\n"), pszFormat, &args);
346 va_end(args);
347 return RTEXITCODE_SYNTAX;
348}
349
350
351/**
352 * errorSyntaxInternal for RTGetOpt users.
353 *
354 * @returns RTEXITCODE_SYNTAX.
355 *
356 * @param enmCommand The command.
[98298]357 * @param vrc The RTGetOpt return code.
[94240]358 * @param pValueUnion The value union.
359 */
[98298]360static RTEXITCODE errorGetOptInternal(USAGECATEGORY enmCommand, int vrc, union RTGETOPTUNION const *pValueUnion)
[94240]361{
362 /*
363 * Check if it is an unhandled standard option.
364 */
[98298]365 if (vrc == 'V')
[94240]366 {
367 RTPrintf("%sr%d\n", VBOX_VERSION_STRING, RTBldCfgRevision());
368 return RTEXITCODE_SUCCESS;
369 }
370
[98298]371 if (vrc == 'h')
[94240]372 {
373 showLogo(g_pStdErr);
374 printUsageInternal(enmCommand, g_pStdOut);
375 return RTEXITCODE_SUCCESS;
376 }
377
378 /*
379 * General failure.
380 */
381 showLogo(g_pStdErr); // show logo even if suppressed
382
383 printUsageInternal(enmCommand, g_pStdErr);
384
[98298]385 if (vrc == VINF_GETOPT_NOT_OPTION)
[94240]386 return RTMsgErrorExit(RTEXITCODE_SYNTAX, Internal::tr("Invalid parameter '%s'"), pValueUnion->psz);
[98298]387 if (vrc > 0)
[94240]388 {
[98298]389 if (RT_C_IS_PRINT(vrc))
390 return RTMsgErrorExit(RTEXITCODE_SYNTAX, Internal::tr("Invalid option -%c"), vrc);
391 return RTMsgErrorExit(RTEXITCODE_SYNTAX, Internal::tr("Invalid option case %i"), vrc);
[94240]392 }
[98298]393 if (vrc == VERR_GETOPT_UNKNOWN_OPTION)
[94240]394 return RTMsgErrorExit(RTEXITCODE_SYNTAX, Internal::tr("Unknown option: %s"), pValueUnion->psz);
[98298]395 if (vrc == VERR_GETOPT_INVALID_ARGUMENT_FORMAT)
[94240]396 return RTMsgErrorExit(RTEXITCODE_SYNTAX, Internal::tr("Invalid argument format: %s"), pValueUnion->psz);
397 if (pValueUnion->pDef)
[98298]398 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "%s: %Rrs", pValueUnion->pDef->pszLong, vrc);
399 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "%Rrs", vrc);
[94240]400}
401
402
[94290]403/**
404 * Externally visible wrapper around printUsageInternal() to dump the
405 * complete usage text.
406 *
407 * @param pStrm The stream to dump the usage text to.
408 */
409DECLHIDDEN(void) printUsageInternalCmds(PRTSTREAM pStrm)
410{
411 printUsageInternal(USAGE_I_ALL, pStrm);
412}
413
414
[1]415/** @todo this is no longer necessary, we can enumerate extra data */
416/**
417 * Finds a new unique key name.
418 *
419 * I don't think this is 100% race condition proof, but we assumes
420 * the user is not trying to push this point.
421 *
422 * @returns Result from the insert.
423 * @param pMachine The Machine object.
424 * @param pszKeyBase The base key.
425 * @param rKey Reference to the string object in which we will return the key.
426 */
427static HRESULT NewUniqueKey(ComPtr<IMachine> pMachine, const char *pszKeyBase, Utf8Str &rKey)
428{
[32718]429 Bstr KeyBase(pszKeyBase);
[1]430 Bstr Keys;
[32718]431 HRESULT hrc = pMachine->GetExtraData(KeyBase.raw(), Keys.asOutParam());
[1]432 if (FAILED(hrc))
433 return hrc;
434
435 /* if there are no keys, it's simple. */
436 if (Keys.isEmpty())
437 {
438 rKey = "1";
[32718]439 return pMachine->SetExtraData(KeyBase.raw(), Bstr(rKey).raw());
[1]440 }
441
442 /* find a unique number - brute force rulez. */
443 Utf8Str KeysUtf8(Keys);
[31539]444 const char *pszKeys = RTStrStripL(KeysUtf8.c_str());
[1]445 for (unsigned i = 1; i < 1000000; i++)
446 {
447 char szKey[32];
448 size_t cchKey = RTStrPrintf(szKey, sizeof(szKey), "%#x", i);
449 const char *psz = strstr(pszKeys, szKey);
450 while (psz)
451 {
452 if ( ( psz == pszKeys
453 || psz[-1] == ' ')
454 && ( psz[cchKey] == ' '
455 || !psz[cchKey])
456 )
457 break;
458 psz = strstr(psz + cchKey, szKey);
459 }
460 if (!psz)
461 {
462 rKey = szKey;
463 Utf8StrFmt NewKeysUtf8("%s %s", pszKeys, szKey);
[32718]464 return pMachine->SetExtraData(KeyBase.raw(),
465 Bstr(NewKeysUtf8).raw());
[1]466 }
467 }
[92372]468 RTMsgError(Internal::tr("Cannot find unique key for '%s'!"), pszKeyBase);
[1]469 return E_FAIL;
470}
471
472
473#if 0
474/**
475 * Remove a key.
476 *
477 * I don't think this isn't 100% race condition proof, but we assumes
478 * the user is not trying to push this point.
479 *
480 * @returns Result from the insert.
481 * @param pMachine The machine object.
482 * @param pszKeyBase The base key.
483 * @param pszKey The key to remove.
484 */
485static HRESULT RemoveKey(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey)
486{
487 Bstr Keys;
488 HRESULT hrc = pMachine->GetExtraData(Bstr(pszKeyBase), Keys.asOutParam());
489 if (FAILED(hrc))
490 return hrc;
491
492 /* if there are no keys, it's simple. */
493 if (Keys.isEmpty())
494 return S_OK;
495
496 char *pszKeys;
[98298]497 int vrc = RTUtf16ToUtf8(Keys.raw(), &pszKeys);
498 if (RT_SUCCESS(vrc))
[1]499 {
500 /* locate it */
501 size_t cchKey = strlen(pszKey);
502 char *psz = strstr(pszKeys, pszKey);
503 while (psz)
504 {
505 if ( ( psz == pszKeys
506 || psz[-1] == ' ')
507 && ( psz[cchKey] == ' '
508 || !psz[cchKey])
509 )
510 break;
511 psz = strstr(psz + cchKey, pszKey);
512 }
513 if (psz)
514 {
515 /* remove it */
516 char *pszNext = RTStrStripL(psz + cchKey);
517 if (*pszNext)
518 memmove(psz, pszNext, strlen(pszNext) + 1);
519 else
520 *psz = '\0';
521 psz = RTStrStrip(pszKeys);
522
523 /* update */
524 hrc = pMachine->SetExtraData(Bstr(pszKeyBase), Bstr(psz));
525 }
526
527 RTStrFree(pszKeys);
528 return hrc;
529 }
530 else
[92372]531 RTMsgError(Internal::tr("Failed to delete key '%s' from '%s', string conversion error %Rrc!"),
[98298]532 pszKey, pszKeyBase, vrc);
[1]533
534 return E_FAIL;
535}
536#endif
537
538
539/**
540 * Sets a key value, does necessary error bitching.
541 *
542 * @returns COM status code.
543 * @param pMachine The Machine object.
544 * @param pszKeyBase The key base.
545 * @param pszKey The key.
546 * @param pszAttribute The attribute name.
547 * @param pszValue The string value.
548 */
549static HRESULT SetString(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey, const char *pszAttribute, const char *pszValue)
550{
[32718]551 HRESULT hrc = pMachine->SetExtraData(BstrFmt("%s/%s/%s", pszKeyBase,
552 pszKey, pszAttribute).raw(),
553 Bstr(pszValue).raw());
[1]554 if (FAILED(hrc))
[92372]555 RTMsgError(Internal::tr("Failed to set '%s/%s/%s' to '%s'! hrc=%#x"),
[32701]556 pszKeyBase, pszKey, pszAttribute, pszValue, hrc);
[1]557 return hrc;
558}
559
560
561/**
562 * Sets a key value, does necessary error bitching.
563 *
564 * @returns COM status code.
565 * @param pMachine The Machine object.
566 * @param pszKeyBase The key base.
567 * @param pszKey The key.
568 * @param pszAttribute The attribute name.
569 * @param u64Value The value.
570 */
571static HRESULT SetUInt64(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey, const char *pszAttribute, uint64_t u64Value)
572{
573 char szValue[64];
574 RTStrPrintf(szValue, sizeof(szValue), "%#RX64", u64Value);
575 return SetString(pMachine, pszKeyBase, pszKey, pszAttribute, szValue);
576}
577
578
579/**
580 * Sets a key value, does necessary error bitching.
581 *
582 * @returns COM status code.
583 * @param pMachine The Machine object.
584 * @param pszKeyBase The key base.
585 * @param pszKey The key.
586 * @param pszAttribute The attribute name.
587 * @param i64Value The value.
588 */
589static HRESULT SetInt64(ComPtr<IMachine> pMachine, const char *pszKeyBase, const char *pszKey, const char *pszAttribute, int64_t i64Value)
590{
591 char szValue[64];
592 RTStrPrintf(szValue, sizeof(szValue), "%RI64", i64Value);
593 return SetString(pMachine, pszKeyBase, pszKey, pszAttribute, szValue);
594}
595
596
597/**
598 * Identical to the 'loadsyms' command.
599 */
[56118]600static RTEXITCODE CmdLoadSyms(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[1]601{
[63384]602 RT_NOREF(aSession);
[95140]603 HRESULT hrc;
[1]604
605 /*
606 * Get the VM
607 */
608 ComPtr<IMachine> machine;
[33294]609 CHECK_ERROR_RET(aVirtualBox, FindMachine(Bstr(argv[0]).raw(),
[56118]610 machine.asOutParam()), RTEXITCODE_FAILURE);
[1]611
612 /*
613 * Parse the command.
614 */
615 const char *pszFilename;
616 int64_t offDelta = 0;
617 const char *pszModule = NULL;
[63300]618 uint64_t ModuleAddress = UINT64_MAX;
[1]619 uint64_t ModuleSize = 0;
620
621 /* filename */
622 if (argc < 2)
[92372]623 return errorArgument(Internal::tr("Missing the filename argument!\n"));
[1]624 pszFilename = argv[1];
625
626 /* offDelta */
627 if (argc >= 3)
628 {
[95140]629 int vrc = RTStrToInt64Ex(argv[2], NULL, 0, &offDelta);
630 if (RT_FAILURE(vrc))
[98298]631 return errorArgument(argv[0], Internal::tr("Failed to read delta '%s', vrc=%Rrc\n"), argv[2], vrc);
[1]632 }
633
634 /* pszModule */
635 if (argc >= 4)
636 pszModule = argv[3];
637
638 /* ModuleAddress */
639 if (argc >= 5)
640 {
[95140]641 int vrc = RTStrToUInt64Ex(argv[4], NULL, 0, &ModuleAddress);
642 if (RT_FAILURE(vrc))
[98298]643 return errorArgument(argv[0], Internal::tr("Failed to read module address '%s', vrc=%Rrc\n"), argv[4], vrc);
[1]644 }
645
646 /* ModuleSize */
647 if (argc >= 6)
648 {
[95140]649 int vrc = RTStrToUInt64Ex(argv[5], NULL, 0, &ModuleSize);
650 if (RT_FAILURE(vrc))
[98298]651 return errorArgument(argv[0], Internal::tr("Failed to read module size '%s', vrc=%Rrc\n"), argv[5], vrc);
[1]652 }
653
654 /*
655 * Add extra data.
656 */
657 Utf8Str KeyStr;
[95140]658 hrc = NewUniqueKey(machine, "VBoxInternal/DBGF/loadsyms", KeyStr);
[1]659 if (SUCCEEDED(hrc))
[22173]660 hrc = SetString(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "Filename", pszFilename);
[1]661 if (SUCCEEDED(hrc) && argc >= 3)
[22173]662 hrc = SetInt64(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "Delta", offDelta);
[1]663 if (SUCCEEDED(hrc) && argc >= 4)
[22173]664 hrc = SetString(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "Module", pszModule);
[1]665 if (SUCCEEDED(hrc) && argc >= 5)
[22173]666 hrc = SetUInt64(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "ModuleAddress", ModuleAddress);
[1]667 if (SUCCEEDED(hrc) && argc >= 6)
[22173]668 hrc = SetUInt64(machine, "VBoxInternal/DBGF/loadsyms", KeyStr.c_str(), "ModuleSize", ModuleSize);
[1]669
[56118]670 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[1]671}
672
[15366]673
[39477]674/**
675 * Identical to the 'loadmap' command.
676 */
[56118]677static RTEXITCODE CmdLoadMap(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[39477]678{
[63384]679 RT_NOREF(aSession);
[95140]680 HRESULT hrc;
[39477]681
682 /*
683 * Get the VM
684 */
685 ComPtr<IMachine> machine;
686 CHECK_ERROR_RET(aVirtualBox, FindMachine(Bstr(argv[0]).raw(),
[56118]687 machine.asOutParam()), RTEXITCODE_FAILURE);
[39477]688
689 /*
690 * Parse the command.
691 */
692 const char *pszFilename;
693 uint64_t ModuleAddress = UINT64_MAX;
694 const char *pszModule = NULL;
695 uint64_t offSubtrahend = 0;
696 uint32_t iSeg = UINT32_MAX;
697
698 /* filename */
699 if (argc < 2)
[92372]700 return errorArgument(Internal::tr("Missing the filename argument!\n"));
[39477]701 pszFilename = argv[1];
702
703 /* address */
704 if (argc < 3)
[92372]705 return errorArgument(Internal::tr("Missing the module address argument!\n"));
[95140]706 int vrc = RTStrToUInt64Ex(argv[2], NULL, 0, &ModuleAddress);
707 if (RT_FAILURE(vrc))
[98298]708 return errorArgument(argv[0], Internal::tr("Failed to read module address '%s', vrc=%Rrc\n"), argv[2], vrc);
[39477]709
710 /* name (optional) */
711 if (argc > 3)
712 pszModule = argv[3];
713
714 /* subtrahend (optional) */
715 if (argc > 4)
716 {
[95140]717 vrc = RTStrToUInt64Ex(argv[4], NULL, 0, &offSubtrahend);
718 if (RT_FAILURE(vrc))
[98298]719 return errorArgument(argv[0], Internal::tr("Failed to read subtrahend '%s', vrc=%Rrc\n"), argv[4], vrc);
[39477]720 }
721
722 /* segment (optional) */
723 if (argc > 5)
724 {
[95140]725 vrc = RTStrToUInt32Ex(argv[5], NULL, 0, &iSeg);
726 if (RT_FAILURE(vrc))
[98298]727 return errorArgument(argv[0], Internal::tr("Failed to read segment number '%s', vrc=%Rrc\n"), argv[5], vrc);
[39477]728 }
729
730 /*
731 * Add extra data.
732 */
733 Utf8Str KeyStr;
[95140]734 hrc = NewUniqueKey(machine, "VBoxInternal/DBGF/loadmap", KeyStr);
[39477]735 if (SUCCEEDED(hrc))
736 hrc = SetString(machine, "VBoxInternal/DBGF/loadmap", KeyStr.c_str(), "Filename", pszFilename);
737 if (SUCCEEDED(hrc))
738 hrc = SetUInt64(machine, "VBoxInternal/DBGF/loadmap", KeyStr.c_str(), "Address", ModuleAddress);
739 if (SUCCEEDED(hrc) && pszModule != NULL)
740 hrc = SetString(machine, "VBoxInternal/DBGF/loadmap", KeyStr.c_str(), "Name", pszModule);
741 if (SUCCEEDED(hrc) && offSubtrahend != 0)
742 hrc = SetUInt64(machine, "VBoxInternal/DBGF/loadmap", KeyStr.c_str(), "Subtrahend", offSubtrahend);
743 if (SUCCEEDED(hrc) && iSeg != UINT32_MAX)
744 hrc = SetUInt64(machine, "VBoxInternal/DBGF/loadmap", KeyStr.c_str(), "Segment", iSeg);
745
[56118]746 return SUCCEEDED(hrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[39477]747}
748
749
[98298]750static DECLCALLBACK(void) handleVDError(void *pvUser, int vrc, RT_SRC_POS_DECL, const char *pszFormat, va_list va)
[1]751{
[63300]752 RT_NOREF(pvUser);
[32701]753 RTMsgErrorV(pszFormat, va);
[98298]754 RTMsgError(Internal::tr("Error code %Rrc at %s(%u) in function %s"), vrc, RT_SRC_POS_ARGS);
[15366]755}
756
[57428]757static DECLCALLBACK(int) handleVDMessage(void *pvUser, const char *pszFormat, va_list va)
[29649]758{
759 NOREF(pvUser);
[40107]760 return RTPrintfV(pszFormat, va);
[29649]761}
762
[56118]763static RTEXITCODE CmdSetHDUUID(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[15366]764{
[63384]765 RT_NOREF(aVirtualBox, aSession);
[31461]766 Guid uuid;
767 RTUUID rtuuid;
768 enum eUuidType {
769 HDUUID,
770 HDPARENTUUID
771 } uuidType;
[31539]772
[31461]773 if (!strcmp(argv[0], "sethduuid"))
[1]774 {
[31461]775 uuidType = HDUUID;
776 if (argc != 3 && argc != 2)
[94240]777 return errorSyntaxInternal(USAGE_I_SETHDUUID, Internal::tr("Not enough parameters"));
[31461]778 /* if specified, take UUID, otherwise generate a new one */
779 if (argc == 3)
780 {
781 if (RT_FAILURE(RTUuidFromStr(&rtuuid, argv[2])))
[94240]782 return errorSyntaxInternal(USAGE_I_SETHDUUID, Internal::tr("Invalid UUID parameter"));
[31461]783 uuid = argv[2];
784 } else
785 uuid.create();
[1]786 }
[31461]787 else if (!strcmp(argv[0], "sethdparentuuid"))
788 {
789 uuidType = HDPARENTUUID;
790 if (argc != 3)
[94240]791 return errorSyntaxInternal(USAGE_I_SETHDPARENTUUID, Internal::tr("Not enough parameters"));
[31461]792 if (RT_FAILURE(RTUuidFromStr(&rtuuid, argv[2])))
[94240]793 return errorSyntaxInternal(USAGE_I_SETHDPARENTUUID, Internal::tr("Invalid UUID parameter"));
[31461]794 uuid = argv[2];
795 }
796 else
[94240]797 return errorSyntaxInternal(USAGE_I_SETHDUUID, Internal::tr("Invalid invocation"));
[1]798
799 /* just try it */
[15366]800 char *pszFormat = NULL;
[33524]801 VDTYPE enmType = VDTYPE_INVALID;
[98298]802 int vrc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */, argv[1], VDTYPE_INVALID, &pszFormat, &enmType);
803 if (RT_FAILURE(vrc))
804 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Format autodetect failed: %Rrc"), vrc);
[15366]805
[66250]806 PVDISK pDisk = NULL;
[15366]807
808 PVDINTERFACE pVDIfs = NULL;
[38469]809 VDINTERFACEERROR vdInterfaceError;
810 vdInterfaceError.pfnError = handleVDError;
811 vdInterfaceError.pfnMessage = handleVDMessage;
[15366]812
[98298]813 vrc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
814 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
815 AssertRC(vrc);
[15366]816
[98298]817 vrc = VDCreate(pVDIfs, enmType, &pDisk);
818 if (RT_FAILURE(vrc))
819 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot create the virtual disk container: %Rrc"), vrc);
[1]820
[15366]821 /* Open the image */
[98298]822 vrc = VDOpen(pDisk, pszFormat, argv[1], VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_INFO, NULL);
823 if (RT_FAILURE(vrc))
824 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot open the image: %Rrc"), vrc);
[1]825
[31461]826 if (uuidType == HDUUID)
[98298]827 vrc = VDSetUuid(pDisk, VD_LAST_IMAGE, uuid.raw());
[31461]828 else
[98298]829 vrc = VDSetParentUuid(pDisk, VD_LAST_IMAGE, uuid.raw());
830 if (RT_FAILURE(vrc))
831 RTMsgError(Internal::tr("Cannot set a new UUID: %Rrc"), vrc);
[15366]832 else
[92372]833 RTPrintf(Internal::tr("UUID changed to: %s\n"), uuid.toString().c_str());
[8230]834
[15366]835 VDCloseAll(pDisk);
836
[98298]837 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[8230]838}
839
[21806]840
[56118]841static RTEXITCODE CmdDumpHDInfo(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[21806]842{
[63384]843 RT_NOREF(aVirtualBox, aSession);
844
[21806]845 /* we need exactly one parameter: the image file */
846 if (argc != 1)
847 {
[94240]848 return errorSyntaxInternal(USAGE_I_DUMPHDINFO, Internal::tr("Not enough parameters"));
[21806]849 }
850
851 /* just try it */
852 char *pszFormat = NULL;
[33524]853 VDTYPE enmType = VDTYPE_INVALID;
[98298]854 int vrc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */, argv[0], VDTYPE_INVALID, &pszFormat, &enmType);
855 if (RT_FAILURE(vrc))
856 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Format autodetect failed: %Rrc"), vrc);
[21806]857
[66250]858 PVDISK pDisk = NULL;
[21806]859
860 PVDINTERFACE pVDIfs = NULL;
[38469]861 VDINTERFACEERROR vdInterfaceError;
862 vdInterfaceError.pfnError = handleVDError;
863 vdInterfaceError.pfnMessage = handleVDMessage;
[21806]864
[98298]865 vrc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
866 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
867 AssertRC(vrc);
[21806]868
[98298]869 vrc = VDCreate(pVDIfs, enmType, &pDisk);
870 if (RT_FAILURE(vrc))
871 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot create the virtual disk container: %Rrc"), vrc);
[21806]872
873 /* Open the image */
[98298]874 vrc = VDOpen(pDisk, pszFormat, argv[0], VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_INFO, NULL);
875 if (RT_FAILURE(vrc))
876 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot open the image: %Rrc"), vrc);
[21806]877
878 VDDumpImages(pDisk);
879
880 VDCloseAll(pDisk);
881
[98298]882 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[21806]883}
884
[8230]885static int partRead(RTFILE File, PHOSTPARTITIONS pPart)
886{
887 uint8_t aBuffer[512];
[42860]888 uint8_t partitionTableHeader[512];
889 uint32_t sector_size = 512;
[43207]890 uint64_t lastUsableLBA = 0;
[8230]891
[66250]892 VDISKPARTTYPE partitioningType;
[42860]893
[8230]894 pPart->cPartitions = 0;
895 memset(pPart->aPartitions, '\0', sizeof(pPart->aPartitions));
[42860]896
[98298]897 int vrc = RTFileReadAt(File, 0, &aBuffer, sizeof(aBuffer), NULL);
898 if (RT_FAILURE(vrc))
899 return vrc;
[8230]900
[42860]901 if (aBuffer[450] == 0xEE)/* check the sign of the GPT disk*/
[8230]902 {
[85221]903 partitioningType = VDISKPARTTYPE_GPT;
904 pPart->uPartitioningType = VDISKPARTTYPE_GPT;//partitioningType;
[8230]905
[42860]906 if (aBuffer[510] != 0x55 || aBuffer[511] != 0xaa)
907 return VERR_INVALID_PARAMETER;
908
[98298]909 vrc = RTFileReadAt(File, sector_size, &partitionTableHeader, sector_size, NULL);
910 if (RT_SUCCESS(vrc))
[8230]911 {
[56118]912 /** @todo r=bird: This is a 64-bit magic value, right... */
913 const char *l_ppth = (char *)partitionTableHeader;
[55906]914 if (strncmp(l_ppth, "EFI PART", 8))
[42860]915 return VERR_INVALID_PARAMETER;
916
917 /** @todo check GPT Version */
918
[56118]919 /** @todo r=bird: C have this handy concept called structures which
920 * greatly simplify data access... (Someone is really lazy here!) */
[63300]921#if 0 /* unused */
[56118]922 uint64_t firstUsableLBA = RT_MAKE_U64_FROM_U8(partitionTableHeader[40],
923 partitionTableHeader[41],
924 partitionTableHeader[42],
925 partitionTableHeader[43],
926 partitionTableHeader[44],
927 partitionTableHeader[45],
928 partitionTableHeader[46],
929 partitionTableHeader[47]
930 );
[63300]931#endif
[56118]932 lastUsableLBA = RT_MAKE_U64_FROM_U8(partitionTableHeader[48],
933 partitionTableHeader[49],
934 partitionTableHeader[50],
935 partitionTableHeader[51],
936 partitionTableHeader[52],
937 partitionTableHeader[53],
938 partitionTableHeader[54],
939 partitionTableHeader[55]
940 );
941 uint32_t partitionsNumber = RT_MAKE_U32_FROM_U8(partitionTableHeader[80],
942 partitionTableHeader[81],
943 partitionTableHeader[82],
944 partitionTableHeader[83]
945 );
946 uint32_t partitionEntrySize = RT_MAKE_U32_FROM_U8(partitionTableHeader[84],
947 partitionTableHeader[85],
948 partitionTableHeader[86],
949 partitionTableHeader[87]
950 );
[42860]951
952 uint32_t currentEntry = 0;
[55906]953
954 if (partitionEntrySize * partitionsNumber > 4 * _1M)
[8230]955 {
[92372]956 RTMsgError(Internal::tr("The GPT header seems corrupt because it contains too many entries"));
[55906]957 return VERR_INVALID_PARAMETER;
958 }
[42860]959
[55906]960 uint8_t *pbPartTable = (uint8_t *)RTMemAllocZ(RT_ALIGN_Z(partitionEntrySize * partitionsNumber, 512));
961 if (!pbPartTable)
962 {
[92372]963 RTMsgError(Internal::tr("Allocating memory for the GPT partitions entries failed"));
[55906]964 return VERR_NO_MEMORY;
965 }
[42860]966
[55906]967 /* partition entries begin from LBA2 */
968 /** @todo r=aeichner: Reading from LBA 2 is not always correct, the header will contain the starting LBA. */
[98298]969 vrc = RTFileReadAt(File, 1024, pbPartTable, RT_ALIGN_Z(partitionEntrySize * partitionsNumber, 512), NULL);
970 if (RT_FAILURE(vrc))
[55906]971 {
[92372]972 RTMsgError(Internal::tr("Reading the partition table failed"));
[55906]973 RTMemFree(pbPartTable);
[98298]974 return vrc;
[55906]975 }
[42860]976
[55906]977 while (currentEntry < partitionsNumber)
978 {
979 uint8_t *partitionEntry = pbPartTable + currentEntry * partitionEntrySize;
980
981 uint64_t start = RT_MAKE_U64_FROM_U8(partitionEntry[32], partitionEntry[33], partitionEntry[34], partitionEntry[35],
982 partitionEntry[36], partitionEntry[37], partitionEntry[38], partitionEntry[39]);
983 uint64_t end = RT_MAKE_U64_FROM_U8(partitionEntry[40], partitionEntry[41], partitionEntry[42], partitionEntry[43],
984 partitionEntry[44], partitionEntry[45], partitionEntry[46], partitionEntry[47]);
985
[42860]986 PHOSTPARTITION pCP = &pPart->aPartitions[pPart->cPartitions++];
987 pCP->uIndex = currentEntry + 1;
[56918]988 pCP->uIndexWin = currentEntry + 1;
[42860]989 pCP->uType = 0;
990 pCP->uStartCylinder = 0;
991 pCP->uStartHead = 0;
992 pCP->uStartSector = 0;
993 pCP->uEndCylinder = 0;
994 pCP->uEndHead = 0;
995 pCP->uEndSector = 0;
996 pCP->uPartDataStart = 0; /* will be filled out later properly. */
997 pCP->cPartDataSectors = 0;
[43207]998 if (start==0 || end==0)
[42860]999 {
1000 pCP->uIndex = 0;
[56918]1001 pCP->uIndexWin = 0;
[42860]1002 --pPart->cPartitions;
1003 break;
1004 }
[43207]1005 else
1006 {
[42860]1007 pCP->uStart = start;
1008 pCP->uSize = (end +1) - start;/*+1 LBA because the last address is included*/
[43207]1009 }
[42860]1010
1011 ++currentEntry;
[8230]1012 }
[55906]1013
1014 RTMemFree(pbPartTable);
[8230]1015 }
1016 }
[42860]1017 else
1018 {
[85221]1019 partitioningType = VDISKPARTTYPE_MBR;
1020 pPart->uPartitioningType = VDISKPARTTYPE_MBR;//partitioningType;
[8230]1021
[42860]1022 if (aBuffer[510] != 0x55 || aBuffer[511] != 0xaa)
[8230]1023 return VERR_INVALID_PARAMETER;
1024
[42860]1025 unsigned uExtended = (unsigned)-1;
[56918]1026 unsigned uIndexWin = 1;
[42860]1027
1028 for (unsigned i = 0; i < 4; i++)
[8230]1029 {
[42860]1030 uint8_t *p = &aBuffer[0x1be + i * 16];
[8230]1031 if (p[4] == 0)
[42860]1032 continue;
[8230]1033 PHOSTPARTITION pCP = &pPart->aPartitions[pPart->cPartitions++];
[42860]1034 pCP->uIndex = i + 1;
[8230]1035 pCP->uType = p[4];
1036 pCP->uStartCylinder = (uint32_t)p[3] + ((uint32_t)(p[2] & 0xc0) << 2);
1037 pCP->uStartHead = p[1];
1038 pCP->uStartSector = p[2] & 0x3f;
1039 pCP->uEndCylinder = (uint32_t)p[7] + ((uint32_t)(p[6] & 0xc0) << 2);
1040 pCP->uEndHead = p[5];
1041 pCP->uEndSector = p[6] & 0x3f;
[42860]1042 pCP->uStart = RT_MAKE_U32_FROM_U8(p[8], p[9], p[10], p[11]);
[8230]1043 pCP->uSize = RT_MAKE_U32_FROM_U8(p[12], p[13], p[14], p[15]);
[42860]1044 pCP->uPartDataStart = 0; /* will be filled out later properly. */
1045 pCP->cPartDataSectors = 0;
1046
1047 if (PARTTYPE_IS_EXTENDED(p[4]))
[8230]1048 {
[42860]1049 if (uExtended == (unsigned)-1)
[56918]1050 {
[42860]1051 uExtended = (unsigned)(pCP - pPart->aPartitions);
[56918]1052 pCP->uIndexWin = 0;
1053 }
[42860]1054 else
1055 {
[92372]1056 RTMsgError(Internal::tr("More than one extended partition"));
[42860]1057 return VERR_INVALID_PARAMETER;
1058 }
[8230]1059 }
[56918]1060 else
1061 {
1062 pCP->uIndexWin = uIndexWin;
1063 uIndexWin++;
1064 }
[42860]1065 }
1066
1067 if (uExtended != (unsigned)-1)
1068 {
1069 unsigned uIndex = 5;
1070 uint64_t uStart = pPart->aPartitions[uExtended].uStart;
1071 uint64_t uOffset = 0;
1072 if (!uStart)
[8230]1073 {
[92372]1074 RTMsgError(Internal::tr("Inconsistency for logical partition start"));
[8230]1075 return VERR_INVALID_PARAMETER;
1076 }
[42860]1077
1078 do
1079 {
[98298]1080 vrc = RTFileReadAt(File, (uStart + uOffset) * 512, &aBuffer, sizeof(aBuffer), NULL);
1081 if (RT_FAILURE(vrc))
1082 return vrc;
[42860]1083
1084 if (aBuffer[510] != 0x55 || aBuffer[511] != 0xaa)
1085 {
[92372]1086 RTMsgError(Internal::tr("Logical partition without magic"));
[42860]1087 return VERR_INVALID_PARAMETER;
1088 }
1089 uint8_t *p = &aBuffer[0x1be];
1090
1091 if (p[4] == 0)
1092 {
[92372]1093 RTMsgError(Internal::tr("Logical partition with type 0 encountered"));
[42860]1094 return VERR_INVALID_PARAMETER;
1095 }
1096
1097 PHOSTPARTITION pCP = &pPart->aPartitions[pPart->cPartitions++];
1098 pCP->uIndex = uIndex;
[56918]1099 pCP->uIndexWin = uIndexWin;
[42860]1100 pCP->uType = p[4];
1101 pCP->uStartCylinder = (uint32_t)p[3] + ((uint32_t)(p[2] & 0xc0) << 2);
1102 pCP->uStartHead = p[1];
1103 pCP->uStartSector = p[2] & 0x3f;
1104 pCP->uEndCylinder = (uint32_t)p[7] + ((uint32_t)(p[6] & 0xc0) << 2);
1105 pCP->uEndHead = p[5];
1106 pCP->uEndSector = p[6] & 0x3f;
1107 uint32_t uStartOffset = RT_MAKE_U32_FROM_U8(p[8], p[9], p[10], p[11]);
1108 if (!uStartOffset)
1109 {
[92372]1110 RTMsgError(Internal::tr("Invalid partition start offset"));
[42860]1111 return VERR_INVALID_PARAMETER;
1112 }
1113 pCP->uStart = uStart + uOffset + uStartOffset;
1114 pCP->uSize = RT_MAKE_U32_FROM_U8(p[12], p[13], p[14], p[15]);
1115 /* Fill out partitioning location info for EBR. */
1116 pCP->uPartDataStart = uStart + uOffset;
1117 pCP->cPartDataSectors = uStartOffset;
1118 p += 16;
1119 if (p[4] == 0)
1120 uExtended = (unsigned)-1;
1121 else if (PARTTYPE_IS_EXTENDED(p[4]))
1122 {
[56918]1123 uExtended = uIndex;
1124 uIndex++;
1125 uIndexWin++;
[42860]1126 uOffset = RT_MAKE_U32_FROM_U8(p[8], p[9], p[10], p[11]);
1127 }
1128 else
1129 {
[92372]1130 RTMsgError(Internal::tr("Logical partition chain broken"));
[42860]1131 return VERR_INVALID_PARAMETER;
1132 }
1133 } while (uExtended != (unsigned)-1);
1134 }
[8230]1135 }
1136
[42860]1137
[9975]1138 /* Sort partitions in ascending order of start sector, plus a trivial
1139 * bit of consistency checking. */
[8230]1140 for (unsigned i = 0; i < pPart->cPartitions-1; i++)
1141 {
1142 unsigned uMinIdx = i;
1143 uint64_t uMinVal = pPart->aPartitions[i].uStart;
1144 for (unsigned j = i + 1; j < pPart->cPartitions; j++)
1145 {
1146 if (pPart->aPartitions[j].uStart < uMinVal)
1147 {
1148 uMinIdx = j;
1149 uMinVal = pPart->aPartitions[j].uStart;
1150 }
1151 else if (pPart->aPartitions[j].uStart == uMinVal)
1152 {
[92372]1153 RTMsgError(Internal::tr("Two partitions start at the same place"));
[8230]1154 return VERR_INVALID_PARAMETER;
[18164]1155 }
1156 else if (pPart->aPartitions[j].uStart == 0)
[8230]1157 {
[92372]1158 RTMsgError(Internal::tr("Partition starts at sector 0"));
[8230]1159 return VERR_INVALID_PARAMETER;
1160 }
1161 }
1162 if (uMinIdx != i)
1163 {
1164 /* Swap entries at index i and uMinIdx. */
1165 memcpy(&pPart->aPartitions[pPart->cPartitions],
1166 &pPart->aPartitions[i], sizeof(HOSTPARTITION));
1167 memcpy(&pPart->aPartitions[i],
1168 &pPart->aPartitions[uMinIdx], sizeof(HOSTPARTITION));
1169 memcpy(&pPart->aPartitions[uMinIdx],
1170 &pPart->aPartitions[pPart->cPartitions], sizeof(HOSTPARTITION));
1171 }
[9975]1172 }
1173
[42860]1174 /* Fill out partitioning location info for MBR or GPT. */
[29649]1175 pPart->aPartitions[0].uPartDataStart = 0;
1176 pPart->aPartitions[0].cPartDataSectors = pPart->aPartitions[0].uStart;
1177
[42860]1178 /* Fill out partitioning location info for backup GPT. */
[85221]1179 if (partitioningType == VDISKPARTTYPE_GPT)
[9975]1180 {
[42860]1181 pPart->aPartitions[pPart->cPartitions-1].uPartDataStart = lastUsableLBA+1;
1182 pPart->aPartitions[pPart->cPartitions-1].cPartDataSectors = 33;
1183
1184 /* Now do a some partition table consistency checking, to reject the most
1185 * obvious garbage which can lead to trouble later. */
1186 uint64_t uPrevEnd = 0;
1187 for (unsigned i = 0; i < pPart->cPartitions; i++)
[8230]1188 {
[42860]1189 if (pPart->aPartitions[i].cPartDataSectors)
1190 uPrevEnd = pPart->aPartitions[i].uPartDataStart + pPart->aPartitions[i].cPartDataSectors;
1191 if (pPart->aPartitions[i].uStart < uPrevEnd &&
1192 pPart->cPartitions-1 != i)
1193 {
[92372]1194 RTMsgError(Internal::tr("Overlapping GPT partitions"));
[42860]1195 return VERR_INVALID_PARAMETER;
1196 }
[8230]1197 }
1198 }
[42860]1199 else
1200 {
1201 /* Now do a some partition table consistency checking, to reject the most
1202 * obvious garbage which can lead to trouble later. */
1203 uint64_t uPrevEnd = 0;
1204 for (unsigned i = 0; i < pPart->cPartitions; i++)
1205 {
1206 if (pPart->aPartitions[i].cPartDataSectors)
1207 uPrevEnd = pPart->aPartitions[i].uPartDataStart + pPart->aPartitions[i].cPartDataSectors;
1208 if (pPart->aPartitions[i].uStart < uPrevEnd)
1209 {
[92372]1210 RTMsgError(Internal::tr("Overlapping MBR partitions"));
[42860]1211 return VERR_INVALID_PARAMETER;
1212 }
1213 if (!PARTTYPE_IS_EXTENDED(pPart->aPartitions[i].uType))
1214 uPrevEnd = pPart->aPartitions[i].uStart + pPart->aPartitions[i].uSize;
1215 }
1216 }
[8230]1217
1218 return VINF_SUCCESS;
1219}
1220
[56118]1221static RTEXITCODE CmdListPartitions(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[8230]1222{
[63384]1223 RT_NOREF(aVirtualBox, aSession);
[8230]1224 Utf8Str rawdisk;
1225
1226 /* let's have a closer look at the arguments */
1227 for (int i = 0; i < argc; i++)
1228 {
1229 if (strcmp(argv[i], "-rawdisk") == 0)
1230 {
1231 if (argc <= i + 1)
1232 {
[92372]1233 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
[8230]1234 }
1235 i++;
1236 rawdisk = argv[i];
1237 }
1238 else
1239 {
[94240]1240 return errorSyntaxInternal(USAGE_I_LISTPARTITIONS, Internal::tr("Invalid parameter '%s'"), argv[i]);
[8230]1241 }
1242 }
1243
[21394]1244 if (rawdisk.isEmpty())
[94240]1245 return errorSyntaxInternal(USAGE_I_LISTPARTITIONS, Internal::tr("Mandatory parameter -rawdisk missing"));
[8230]1246
[37596]1247 RTFILE hRawFile;
1248 int vrc = RTFileOpen(&hRawFile, rawdisk.c_str(), RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
[13835]1249 if (RT_FAILURE(vrc))
[92372]1250 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot open the raw disk: %Rrc"), vrc);
[8230]1251
1252 HOSTPARTITIONS partitions;
[37596]1253 vrc = partRead(hRawFile, &partitions);
[29649]1254 /* Don't bail out on errors, print the table and return the result code. */
[8230]1255
[92372]1256 RTPrintf(Internal::tr("Number Type StartCHS EndCHS Size (MiB) Start (Sect)\n"));
[8230]1257 for (unsigned i = 0; i < partitions.cPartitions; i++)
1258 {
[29649]1259 /* Don't show the extended partition, otherwise users might think they
1260 * can add it to the list of partitions for raw partition access. */
[8230]1261 if (PARTTYPE_IS_EXTENDED(partitions.aPartitions[i].uType))
1262 continue;
1263
1264 RTPrintf("%-7u %#04x %-4u/%-3u/%-2u %-4u/%-3u/%-2u %10llu %10llu\n",
1265 partitions.aPartitions[i].uIndex,
1266 partitions.aPartitions[i].uType,
1267 partitions.aPartitions[i].uStartCylinder,
1268 partitions.aPartitions[i].uStartHead,
1269 partitions.aPartitions[i].uStartSector,
1270 partitions.aPartitions[i].uEndCylinder,
1271 partitions.aPartitions[i].uEndHead,
1272 partitions.aPartitions[i].uEndSector,
1273 partitions.aPartitions[i].uSize / 2048,
1274 partitions.aPartitions[i].uStart);
1275 }
1276
[56118]1277 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[8230]1278}
1279
[97313]1280static const RTGETOPTDEF g_aCreateRawVMDKOptions[] =
[8230]1281{
[97313]1282 { "--filename", 'f', RTGETOPT_REQ_STRING },
1283 { "-filename", 'f', RTGETOPT_REQ_STRING },
1284 { "--rawdisk", 'd', RTGETOPT_REQ_STRING },
1285 { "-rawdisk", 'd', RTGETOPT_REQ_STRING },
1286 { "--partitions", 'p', RTGETOPT_REQ_STRING },
1287 { "-partitions", 'p', RTGETOPT_REQ_STRING },
1288 { "--mbr", 'm', RTGETOPT_REQ_STRING },
1289 { "-mbr", 'm', RTGETOPT_REQ_STRING },
1290#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_WINDOWS)
1291 { "--relative", 'r', RTGETOPT_REQ_NOTHING },
1292 { "-relative", 'r', RTGETOPT_REQ_NOTHING },
1293#endif /* RT_OS_LINUX || RT_OS_FREEBSD || RT_OS_WINDOWS */
1294};
1295
1296static RTEXITCODE CmdCreateRawVMDK(int argc, char **argv, HandlerArg *a)
1297{
1298 const char *pszFilename = NULL;
1299 const char *pszRawdisk = NULL;
[8230]1300 const char *pszPartitions = NULL;
[97313]1301 const char *pszMbr = NULL;
[8230]1302 bool fRelative = false;
[97313]1303 int c;
1304 RTGETOPTUNION ValueUnion;
1305 RTGETOPTSTATE GetState;
1306 RTGetOptInit(&GetState, argc, argv, g_aCreateRawVMDKOptions, RT_ELEMENTS(g_aCreateRawVMDKOptions), 0, 0);
1307 while ((c = RTGetOpt(&GetState, &ValueUnion)))
[8230]1308 {
[97313]1309 switch (c)
[8230]1310 {
[97313]1311 case 'f': // --filename
1312 pszFilename = ValueUnion.psz;
1313 break;
[8230]1314
[97313]1315 case 'd': // --rawdisk
1316 pszRawdisk = ValueUnion.psz;
1317 break;
[8230]1318
[97313]1319 case 'p': // --partitions
1320 pszPartitions = ValueUnion.psz;
1321 break;
[8230]1322
[97313]1323 case 'm': // --mbr
1324 pszMbr = ValueUnion.psz;
1325 break;
1326#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) || defined(RT_OS_WINDOWS)
1327 case 'r': // --relative
1328 fRelative = true;
1329 break;
1330#endif /* RT_OS_LINUX || RT_OS_FREEBSD || RT_OS_WINDOWS */
[8969]1331
[97313]1332 default:
1333 return errorGetOptInternal(USAGE_I_CREATERAWVMDK, c, &ValueUnion);
[8969]1334 }
[8230]1335 }
1336
[97313]1337 if (!pszFilename || !*pszFilename)
1338 return errorSyntaxInternal(USAGE_I_CREATERAWVMDK, Internal::tr("Mandatory parameter --filename missing"));
1339 if (!pszRawdisk || !*pszRawdisk)
1340 return errorSyntaxInternal(USAGE_I_CREATERAWVMDK, Internal::tr("Mandatory parameter --rawdisk missing"));
1341 if (!pszPartitions && pszMbr)
1342 return errorSyntaxInternal(USAGE_I_CREATERAWVMDK,
1343 Internal::tr("The parameter --mbr is only valid when the parameter -partitions is also present"));
[9891]1344
[97313]1345 /* Construct the equivalent 'VBoxManage createmedium disk --variant RawDisk ...' command line. */
1346 size_t cMaxArgs = 9; /* all possible 'createmedium' args based on the 'createrawvmdk' options + 1 for NULL */
1347 char **papszNewArgv = (char **)RTMemAllocZ(sizeof(papszNewArgv[0]) * cMaxArgs);
1348 if (!papszNewArgv)
1349 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Failed to allocate memory for argument array"));
[97314]1350 int cArgs = 0;
[8230]1351
[97313]1352 papszNewArgv[cArgs++] = RTStrDup("disk");
1353 papszNewArgv[cArgs++] = RTStrDup("--variant=RawDisk");
1354 papszNewArgv[cArgs++] = RTStrDup("--format=VMDK");
[29649]1355
[97314]1356 for (int i = 0; i < cArgs; i++)
[97313]1357 if (!papszNewArgv[i])
1358 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Failed to allocate memory for argument array"));
[8230]1359
[97313]1360 if ( RTStrAPrintf(&papszNewArgv[cArgs++], "--filename=%s", pszFilename) == -1
1361 || RTStrAPrintf(&papszNewArgv[cArgs++], "--property=RawDrive=%s", pszRawdisk) == -1
1362 || (pszPartitions && (RTStrAPrintf(&papszNewArgv[cArgs++], "--property=Partitions=%s", pszPartitions) == -1))
1363 || (pszMbr && (RTStrAPrintf(&papszNewArgv[cArgs++], "--property-filename=%s", pszMbr) == -1))
1364 || (fRelative && (RTStrAPrintf(&papszNewArgv[cArgs++], "--property=Relative=%d", fRelative) == -1)))
1365 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Failed to allocate memory for argument array"));
[8230]1366
[97313]1367 papszNewArgv[cArgs] = NULL;
[42860]1368
[97313]1369 RTStrmPrintf(g_pStdErr,
1370 Internal::tr("\nThe 'createrawvdk' subcommand is deprecated. The equivalent functionality is\n"
1371 "available using the 'VBoxManage createmedium' command and should be used\n"
1372 "instead. See 'VBoxManage help createmedium' for details.\n\n"));
[8230]1373
[97313]1374 a->argc = cArgs;
1375 a->argv = papszNewArgv;
1376 RTEXITCODE rcExit = handleCreateMedium(a);
[29649]1377
[97314]1378 for (int i = 0; i < cArgs; i++)
[97313]1379 RTStrFree(papszNewArgv[i]);
1380 RTMemFree(papszNewArgv);
[29649]1381
[97313]1382 return rcExit;
[8230]1383}
1384
[56118]1385static RTEXITCODE CmdRenameVMDK(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[9047]1386{
[63384]1387 RT_NOREF(aVirtualBox, aSession);
[32531]1388 Utf8Str src;
1389 Utf8Str dst;
[9047]1390 /* Parse the arguments. */
1391 for (int i = 0; i < argc; i++)
1392 {
1393 if (strcmp(argv[i], "-from") == 0)
1394 {
1395 if (argc <= i + 1)
1396 {
[92372]1397 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
[9047]1398 }
1399 i++;
1400 src = argv[i];
1401 }
1402 else if (strcmp(argv[i], "-to") == 0)
1403 {
1404 if (argc <= i + 1)
1405 {
[92372]1406 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
[9047]1407 }
1408 i++;
1409 dst = argv[i];
1410 }
1411 else
1412 {
[94240]1413 return errorSyntaxInternal(USAGE_I_RENAMEVMDK, Internal::tr("Invalid parameter '%s'"), argv[i]);
[9047]1414 }
1415 }
1416
1417 if (src.isEmpty())
[94240]1418 return errorSyntaxInternal(USAGE_I_RENAMEVMDK, Internal::tr("Mandatory parameter -from missing"));
[9047]1419 if (dst.isEmpty())
[94240]1420 return errorSyntaxInternal(USAGE_I_RENAMEVMDK, Internal::tr("Mandatory parameter -to missing"));
[9047]1421
[66250]1422 PVDISK pDisk = NULL;
[9047]1423
[11435]1424 PVDINTERFACE pVDIfs = NULL;
[38469]1425 VDINTERFACEERROR vdInterfaceError;
1426 vdInterfaceError.pfnError = handleVDError;
1427 vdInterfaceError.pfnMessage = handleVDMessage;
[10715]1428
[38469]1429 int vrc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1430 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
[10715]1431 AssertRC(vrc);
1432
[33524]1433 vrc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
[13835]1434 if (RT_FAILURE(vrc))
[92372]1435 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot create the virtual disk container: %Rrc"), vrc);
[56118]1436
1437 vrc = VDOpen(pDisk, "VMDK", src.c_str(), VD_OPEN_FLAGS_NORMAL, NULL);
1438 if (RT_SUCCESS(vrc))
[9047]1439 {
[56118]1440 vrc = VDCopy(pDisk, 0, pDisk, "VMDK", dst.c_str(), true, 0,
1441 VD_IMAGE_FLAGS_NONE, NULL, VD_OPEN_FLAGS_NORMAL,
1442 NULL, NULL, NULL);
1443 if (RT_FAILURE(vrc))
[92372]1444 RTMsgError(Internal::tr("Cannot rename the image: %Rrc"), vrc);
[9047]1445 }
1446 else
[92372]1447 RTMsgError(Internal::tr("Cannot create the source image: %Rrc"), vrc);
[9047]1448 VDCloseAll(pDisk);
[56118]1449 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[9047]1450}
1451
[56118]1452static RTEXITCODE CmdConvertToRaw(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[11066]1453{
[63384]1454 RT_NOREF(aVirtualBox, aSession);
[32531]1455 Utf8Str srcformat;
1456 Utf8Str src;
1457 Utf8Str dst;
[11066]1458 bool fWriteToStdOut = false;
1459
1460 /* Parse the arguments. */
1461 for (int i = 0; i < argc; i++)
1462 {
1463 if (strcmp(argv[i], "-format") == 0)
1464 {
1465 if (argc <= i + 1)
1466 {
[92372]1467 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
[11066]1468 }
1469 i++;
1470 srcformat = argv[i];
1471 }
1472 else if (src.isEmpty())
1473 {
1474 src = argv[i];
1475 }
1476 else if (dst.isEmpty())
1477 {
1478 dst = argv[i];
1479#ifdef ENABLE_CONVERT_RAW_TO_STDOUT
1480 if (!strcmp(argv[i], "stdout"))
1481 fWriteToStdOut = true;
1482#endif /* ENABLE_CONVERT_RAW_TO_STDOUT */
1483 }
1484 else
1485 {
[94240]1486 return errorSyntaxInternal(USAGE_I_CONVERTTORAW, Internal::tr("Invalid parameter '%s'"), argv[i]);
[11066]1487 }
1488 }
1489
1490 if (src.isEmpty())
[94240]1491 return errorSyntaxInternal(USAGE_I_CONVERTTORAW, Internal::tr("Mandatory filename parameter missing"));
[11066]1492 if (dst.isEmpty())
[94240]1493 return errorSyntaxInternal(USAGE_I_CONVERTTORAW, Internal::tr("Mandatory outputfile parameter missing"));
[11066]1494
[66250]1495 PVDISK pDisk = NULL;
[11066]1496
[11435]1497 PVDINTERFACE pVDIfs = NULL;
[38469]1498 VDINTERFACEERROR vdInterfaceError;
1499 vdInterfaceError.pfnError = handleVDError;
1500 vdInterfaceError.pfnMessage = handleVDMessage;
[11066]1501
[38469]1502 int vrc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1503 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
[11066]1504 AssertRC(vrc);
1505
[63567]1506 /** @todo Support convert to raw for floppy and DVD images too. */
[33524]1507 vrc = VDCreate(pVDIfs, VDTYPE_HDD, &pDisk);
[13835]1508 if (RT_FAILURE(vrc))
[92372]1509 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot create the virtual disk container: %Rrc"), vrc);
[11066]1510
1511 /* Open raw output file. */
1512 RTFILE outFile;
1513 vrc = VINF_SUCCESS;
1514 if (fWriteToStdOut)
[37596]1515 vrc = RTFileFromNative(&outFile, 1);
[11066]1516 else
[32531]1517 vrc = RTFileOpen(&outFile, dst.c_str(), RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_ALL);
[13835]1518 if (RT_FAILURE(vrc))
[11066]1519 {
1520 VDCloseAll(pDisk);
[92372]1521 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot create destination file \"%s\": %Rrc"),
1522 dst.c_str(), vrc);
[11066]1523 }
1524
1525 if (srcformat.isEmpty())
1526 {
1527 char *pszFormat = NULL;
[33524]1528 VDTYPE enmType = VDTYPE_INVALID;
[32536]1529 vrc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
[79965]1530 src.c_str(), VDTYPE_INVALID, &pszFormat, &enmType);
[33524]1531 if (RT_FAILURE(vrc) || enmType != VDTYPE_HDD)
[11066]1532 {
1533 VDCloseAll(pDisk);
1534 if (!fWriteToStdOut)
1535 {
1536 RTFileClose(outFile);
[32531]1537 RTFileDelete(dst.c_str());
[11066]1538 }
[33524]1539 if (RT_FAILURE(vrc))
[92372]1540 RTMsgError(Internal::tr("No file format specified and autodetect failed - please specify format: %Rrc"),
1541 vrc);
[33524]1542 else
[92372]1543 RTMsgError(Internal::tr("Only converting harddisk images is supported"));
[56118]1544 return RTEXITCODE_FAILURE;
[11066]1545 }
1546 srcformat = pszFormat;
1547 RTStrFree(pszFormat);
1548 }
[32531]1549 vrc = VDOpen(pDisk, srcformat.c_str(), src.c_str(), VD_OPEN_FLAGS_READONLY, NULL);
[13835]1550 if (RT_FAILURE(vrc))
[11066]1551 {
1552 VDCloseAll(pDisk);
1553 if (!fWriteToStdOut)
1554 {
1555 RTFileClose(outFile);
[32531]1556 RTFileDelete(dst.c_str());
[11066]1557 }
[92372]1558 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot open the source image: %Rrc"), vrc);
[11066]1559 }
1560
1561 uint64_t cbSize = VDGetSize(pDisk, VD_LAST_IMAGE);
1562 uint64_t offFile = 0;
1563#define RAW_BUFFER_SIZE _128K
[27797]1564 size_t cbBuf = RAW_BUFFER_SIZE;
[11066]1565 void *pvBuf = RTMemAlloc(cbBuf);
1566 if (pvBuf)
1567 {
[92594]1568 RTStrmPrintf(g_pStdErr, Internal::tr("Converting image \"%s\" with size %RU64 bytes (%RU64MB) to raw...\n", "", cbSize),
[92372]1569 src.c_str(), cbSize, (cbSize + _1M - 1) / _1M);
[11066]1570 while (offFile < cbSize)
1571 {
[27797]1572 size_t cb = (size_t)RT_MIN(cbSize - offFile, cbBuf);
[11066]1573 vrc = VDRead(pDisk, offFile, pvBuf, cb);
[13835]1574 if (RT_FAILURE(vrc))
[11066]1575 break;
1576 vrc = RTFileWrite(outFile, pvBuf, cb, NULL);
[13835]1577 if (RT_FAILURE(vrc))
[11066]1578 break;
1579 offFile += cb;
1580 }
[55020]1581 RTMemFree(pvBuf);
[13835]1582 if (RT_FAILURE(vrc))
[11066]1583 {
1584 VDCloseAll(pDisk);
1585 if (!fWriteToStdOut)
1586 {
1587 RTFileClose(outFile);
[32531]1588 RTFileDelete(dst.c_str());
[11066]1589 }
[92372]1590 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Cannot copy image data: %Rrc"), vrc);
[11066]1591 }
1592 }
1593 else
1594 {
1595 vrc = VERR_NO_MEMORY;
1596 VDCloseAll(pDisk);
1597 if (!fWriteToStdOut)
1598 {
1599 RTFileClose(outFile);
[32531]1600 RTFileDelete(dst.c_str());
[11066]1601 }
[92372]1602 return RTMsgErrorExit(RTEXITCODE_FAILURE, Internal::tr("Out of memory allocating read buffer"));
[11066]1603 }
1604
1605 if (!fWriteToStdOut)
1606 RTFileClose(outFile);
1607 VDCloseAll(pDisk);
[56118]1608 return RTEXITCODE_SUCCESS;
[11066]1609}
1610
[56118]1611static RTEXITCODE CmdConvertHardDisk(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[15602]1612{
[63384]1613 RT_NOREF(aVirtualBox, aSession);
[32531]1614 Utf8Str srcformat;
1615 Utf8Str dstformat;
1616 Utf8Str src;
1617 Utf8Str dst;
[15602]1618 int vrc;
[66250]1619 PVDISK pSrcDisk = NULL;
1620 PVDISK pDstDisk = NULL;
[33524]1621 VDTYPE enmSrcType = VDTYPE_INVALID;
[15602]1622
1623 /* Parse the arguments. */
1624 for (int i = 0; i < argc; i++)
1625 {
1626 if (strcmp(argv[i], "-srcformat") == 0)
1627 {
1628 if (argc <= i + 1)
1629 {
[92372]1630 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
[15602]1631 }
1632 i++;
1633 srcformat = argv[i];
1634 }
1635 else if (strcmp(argv[i], "-dstformat") == 0)
1636 {
1637 if (argc <= i + 1)
1638 {
[92372]1639 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
[15602]1640 }
1641 i++;
1642 dstformat = argv[i];
1643 }
1644 else if (src.isEmpty())
1645 {
1646 src = argv[i];
1647 }
1648 else if (dst.isEmpty())
1649 {
1650 dst = argv[i];
1651 }
1652 else
1653 {
[94240]1654 return errorSyntaxInternal(USAGE_I_CONVERTHD, Internal::tr("Invalid parameter '%s'"), argv[i]);
[15602]1655 }
1656 }
1657
1658 if (src.isEmpty())
[94240]1659 return errorSyntaxInternal(USAGE_I_CONVERTHD, Internal::tr("Mandatory input image parameter missing"));
[15602]1660 if (dst.isEmpty())
[94240]1661 return errorSyntaxInternal(USAGE_I_CONVERTHD, Internal::tr("Mandatory output image parameter missing"));
[15602]1662
1663
1664 PVDINTERFACE pVDIfs = NULL;
[38469]1665 VDINTERFACEERROR vdInterfaceError;
1666 vdInterfaceError.pfnError = handleVDError;
1667 vdInterfaceError.pfnMessage = handleVDMessage;
[15602]1668
[38469]1669 vrc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1670 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
[15602]1671 AssertRC(vrc);
1672
1673 do
1674 {
1675 /* Try to determine input image format */
1676 if (srcformat.isEmpty())
1677 {
1678 char *pszFormat = NULL;
[32536]1679 vrc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
[79965]1680 src.c_str(), VDTYPE_HDD, &pszFormat, &enmSrcType);
[15602]1681 if (RT_FAILURE(vrc))
1682 {
[92372]1683 RTMsgError(Internal::tr("No file format specified and autodetect failed - please specify format: %Rrc"),
1684 vrc);
[15602]1685 break;
1686 }
1687 srcformat = pszFormat;
1688 RTStrFree(pszFormat);
1689 }
1690
[33524]1691 vrc = VDCreate(pVDIfs, enmSrcType, &pSrcDisk);
[15602]1692 if (RT_FAILURE(vrc))
1693 {
[92372]1694 RTMsgError(Internal::tr("Cannot create the source virtual disk container: %Rrc"), vrc);
[15602]1695 break;
1696 }
1697
1698 /* Open the input image */
[32531]1699 vrc = VDOpen(pSrcDisk, srcformat.c_str(), src.c_str(), VD_OPEN_FLAGS_READONLY, NULL);
[15602]1700 if (RT_FAILURE(vrc))
1701 {
[92372]1702 RTMsgError(Internal::tr("Cannot open the source image: %Rrc"), vrc);
[15602]1703 break;
1704 }
1705
1706 /* Output format defaults to VDI */
1707 if (dstformat.isEmpty())
1708 dstformat = "VDI";
1709
[33524]1710 vrc = VDCreate(pVDIfs, enmSrcType, &pDstDisk);
[15602]1711 if (RT_FAILURE(vrc))
1712 {
[92372]1713 RTMsgError(Internal::tr("Cannot create the destination virtual disk container: %Rrc"), vrc);
[15602]1714 break;
1715 }
1716
1717 uint64_t cbSize = VDGetSize(pSrcDisk, VD_LAST_IMAGE);
[92594]1718 RTStrmPrintf(g_pStdErr, Internal::tr("Converting image \"%s\" with size %RU64 bytes (%RU64MB)...\n", "", cbSize),
[92372]1719 src.c_str(), cbSize, (cbSize + _1M - 1) / _1M);
[15602]1720
1721 /* Create the output image */
[32531]1722 vrc = VDCopy(pSrcDisk, VD_LAST_IMAGE, pDstDisk, dstformat.c_str(),
1723 dst.c_str(), false, 0, VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED,
[33082]1724 NULL, VD_OPEN_FLAGS_NORMAL, NULL, NULL, NULL);
[15602]1725 if (RT_FAILURE(vrc))
1726 {
[92372]1727 RTMsgError(Internal::tr("Cannot copy the image: %Rrc"), vrc);
[15602]1728 break;
1729 }
1730 }
1731 while (0);
1732 if (pDstDisk)
1733 VDCloseAll(pDstDisk);
1734 if (pSrcDisk)
1735 VDCloseAll(pSrcDisk);
1736
[56118]1737 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[15602]1738}
1739
[1]1740/**
[39576]1741 * Tries to repair a corrupted hard disk image.
1742 *
1743 * @returns VBox status code
1744 */
[56118]1745static RTEXITCODE CmdRepairHardDisk(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[39576]1746{
[63384]1747 RT_NOREF(aVirtualBox, aSession);
[39576]1748 Utf8Str image;
1749 Utf8Str format;
1750 int vrc;
1751 bool fDryRun = false;
1752
1753 /* Parse the arguments. */
1754 for (int i = 0; i < argc; i++)
1755 {
1756 if (strcmp(argv[i], "-dry-run") == 0)
1757 {
1758 fDryRun = true;
1759 }
1760 else if (strcmp(argv[i], "-format") == 0)
1761 {
1762 if (argc <= i + 1)
1763 {
[92372]1764 return errorArgument(Internal::tr("Missing argument to '%s'"), argv[i]);
[39576]1765 }
1766 i++;
1767 format = argv[i];
1768 }
1769 else if (image.isEmpty())
1770 {
1771 image = argv[i];
1772 }
1773 else
1774 {
[94240]1775 return errorSyntaxInternal(USAGE_I_REPAIRHD, Internal::tr("Invalid parameter '%s'"), argv[i]);
[39576]1776 }
1777 }
1778
1779 if (image.isEmpty())
[94240]1780 return errorSyntaxInternal(USAGE_I_REPAIRHD, Internal::tr("Mandatory input image parameter missing"));
[39576]1781
1782 PVDINTERFACE pVDIfs = NULL;
1783 VDINTERFACEERROR vdInterfaceError;
1784 vdInterfaceError.pfnError = handleVDError;
1785 vdInterfaceError.pfnMessage = handleVDMessage;
1786
1787 vrc = VDInterfaceAdd(&vdInterfaceError.Core, "VBoxManage_IError", VDINTERFACETYPE_ERROR,
1788 NULL, sizeof(VDINTERFACEERROR), &pVDIfs);
1789 AssertRC(vrc);
1790
1791 do
1792 {
1793 /* Try to determine input image format */
1794 if (format.isEmpty())
1795 {
1796 char *pszFormat = NULL;
1797 VDTYPE enmSrcType = VDTYPE_INVALID;
1798
1799 vrc = VDGetFormat(NULL /* pVDIfsDisk */, NULL /* pVDIfsImage */,
[79965]1800 image.c_str(), VDTYPE_HDD, &pszFormat, &enmSrcType);
[39576]1801 if (RT_FAILURE(vrc) && (vrc != VERR_VD_IMAGE_CORRUPTED))
1802 {
[92372]1803 RTMsgError(Internal::tr("No file format specified and autodetect failed - please specify format: %Rrc"),
1804 vrc);
[39576]1805 break;
1806 }
1807 format = pszFormat;
1808 RTStrFree(pszFormat);
1809 }
1810
1811 uint32_t fFlags = 0;
1812 if (fDryRun)
1813 fFlags |= VD_REPAIR_DRY_RUN;
1814
1815 vrc = VDRepair(pVDIfs, NULL, image.c_str(), format.c_str(), fFlags);
1816 }
1817 while (0);
1818
[56118]1819 return RT_SUCCESS(vrc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
[39576]1820}
1821
1822/**
[33540]1823 * Unloads the necessary driver.
[5895]1824 *
1825 * @returns VBox status code
1826 */
[56118]1827static RTEXITCODE CmdModUninstall(void)
[5895]1828{
[98298]1829 int vrc = SUPR3Uninstall();
1830 if (RT_SUCCESS(vrc) || vrc == VERR_NOT_IMPLEMENTED)
[56118]1831 return RTEXITCODE_SUCCESS;
1832 return RTEXITCODE_FAILURE;
[5895]1833}
1834
1835/**
[33540]1836 * Loads the necessary driver.
[5895]1837 *
1838 * @returns VBox status code
1839 */
[56118]1840static RTEXITCODE CmdModInstall(void)
[5895]1841{
[98298]1842 int vrc = SUPR3Install();
1843 if (RT_SUCCESS(vrc) || vrc == VERR_NOT_IMPLEMENTED)
[56118]1844 return RTEXITCODE_SUCCESS;
1845 return RTEXITCODE_FAILURE;
[5895]1846}
1847
[56118]1848static RTEXITCODE CmdDebugLog(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[30319]1849{
1850 /*
1851 * The first parameter is the name or UUID of a VM with a direct session
1852 * that we wish to open.
1853 */
1854 if (argc < 1)
[94240]1855 return errorSyntaxInternal(USAGE_I_DEBUGLOG, Internal::tr("Missing VM name/UUID"));
[30319]1856
1857 ComPtr<IMachine> ptrMachine;
[95140]1858 HRESULT hrc;
[33294]1859 CHECK_ERROR_RET(aVirtualBox, FindMachine(Bstr(argv[0]).raw(),
[56118]1860 ptrMachine.asOutParam()), RTEXITCODE_FAILURE);
[30319]1861
[56118]1862 CHECK_ERROR_RET(ptrMachine, LockMachine(aSession, LockType_Shared), RTEXITCODE_FAILURE);
[30319]1863
1864 /*
1865 * Get the debugger interface.
1866 */
1867 ComPtr<IConsole> ptrConsole;
[56118]1868 CHECK_ERROR_RET(aSession, COMGETTER(Console)(ptrConsole.asOutParam()), RTEXITCODE_FAILURE);
[30319]1869
1870 ComPtr<IMachineDebugger> ptrDebugger;
[56118]1871 CHECK_ERROR_RET(ptrConsole, COMGETTER(Debugger)(ptrDebugger.asOutParam()), RTEXITCODE_FAILURE);
[30319]1872
1873 /*
1874 * Parse the command.
1875 */
1876 bool fEnablePresent = false;
1877 bool fEnable = false;
1878 bool fFlagsPresent = false;
[36527]1879 RTCString strFlags;
[30319]1880 bool fGroupsPresent = false;
[36527]1881 RTCString strGroups;
[30319]1882 bool fDestsPresent = false;
[36527]1883 RTCString strDests;
[30319]1884
1885 static const RTGETOPTDEF s_aOptions[] =
1886 {
1887 { "--disable", 'E', RTGETOPT_REQ_NOTHING },
1888 { "--enable", 'e', RTGETOPT_REQ_NOTHING },
1889 { "--flags", 'f', RTGETOPT_REQ_STRING },
1890 { "--groups", 'g', RTGETOPT_REQ_STRING },
1891 { "--destinations", 'd', RTGETOPT_REQ_STRING }
1892 };
1893
1894 int ch;
1895 RTGETOPTUNION ValueUnion;
1896 RTGETOPTSTATE GetState;
1897 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
1898 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
1899 {
1900 switch (ch)
1901 {
1902 case 'e':
1903 fEnablePresent = true;
1904 fEnable = true;
1905 break;
1906
1907 case 'E':
1908 fEnablePresent = true;
1909 fEnable = false;
1910 break;
1911
1912 case 'f':
1913 fFlagsPresent = true;
1914 if (*ValueUnion.psz)
1915 {
1916 if (strFlags.isNotEmpty())
1917 strFlags.append(' ');
1918 strFlags.append(ValueUnion.psz);
1919 }
1920 break;
1921
1922 case 'g':
1923 fGroupsPresent = true;
1924 if (*ValueUnion.psz)
1925 {
1926 if (strGroups.isNotEmpty())
1927 strGroups.append(' ');
1928 strGroups.append(ValueUnion.psz);
1929 }
1930 break;
1931
1932 case 'd':
1933 fDestsPresent = true;
1934 if (*ValueUnion.psz)
1935 {
1936 if (strDests.isNotEmpty())
1937 strDests.append(' ');
1938 strDests.append(ValueUnion.psz);
1939 }
1940 break;
1941
1942 default:
[94240]1943 return errorGetOptInternal(USAGE_I_DEBUGLOG, ch, &ValueUnion);
[30319]1944 }
1945 }
1946
1947 /*
1948 * Do the job.
1949 */
1950 if (fEnablePresent && !fEnable)
[56118]1951 CHECK_ERROR_RET(ptrDebugger, COMSETTER(LogEnabled)(FALSE), RTEXITCODE_FAILURE);
[30319]1952
1953 /** @todo flags, groups destination. */
1954 if (fFlagsPresent || fGroupsPresent || fDestsPresent)
[92372]1955 RTMsgWarning(Internal::tr("One or more of the requested features are not implemented! Feel free to do this."));
[30319]1956
1957 if (fEnablePresent && fEnable)
[56118]1958 CHECK_ERROR_RET(ptrDebugger, COMSETTER(LogEnabled)(TRUE), RTEXITCODE_FAILURE);
1959 return RTEXITCODE_SUCCESS;
[30319]1960}
1961
[5895]1962/**
[33228]1963 * Generate a SHA-256 password hash
1964 */
[56118]1965static RTEXITCODE CmdGeneratePasswordHash(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[33228]1966{
[63384]1967 RT_NOREF(aVirtualBox, aSession);
1968
[33228]1969 /* one parameter, the password to hash */
1970 if (argc != 1)
[94240]1971 return errorSyntaxInternal(USAGE_I_PASSWORDHASH, Internal::tr("password to hash required"));
[33228]1972
1973 uint8_t abDigest[RTSHA256_HASH_SIZE];
1974 RTSha256(argv[0], strlen(argv[0]), abDigest);
[33229]1975 char pszDigest[RTSHA256_DIGEST_LEN + 1];
[33228]1976 RTSha256ToString(abDigest, pszDigest, sizeof(pszDigest));
[92372]1977 RTPrintf(Internal::tr("Password hash: %s\n"), pszDigest);
[33294]1978
[56118]1979 return RTEXITCODE_SUCCESS;
[33228]1980}
1981
1982/**
[36067]1983 * Print internal guest statistics or
1984 * set internal guest statistics update interval if specified
1985 */
[56118]1986static RTEXITCODE CmdGuestStats(int argc, char **argv, ComPtr<IVirtualBox> aVirtualBox, ComPtr<ISession> aSession)
[36067]1987{
1988 /* one parameter, guest name */
1989 if (argc < 1)
[94240]1990 return errorSyntaxInternal(USAGE_I_GUESTSTATS, Internal::tr("Missing VM name/UUID"));
[36067]1991
1992 /*
1993 * Parse the command.
1994 */
1995 ULONG aUpdateInterval = 0;
1996
1997 static const RTGETOPTDEF s_aOptions[] =
1998 {
1999 { "--interval", 'i', RTGETOPT_REQ_UINT32 }
2000 };
2001
2002 int ch;
2003 RTGETOPTUNION ValueUnion;
2004 RTGETOPTSTATE GetState;
2005 RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 1, 0);
2006 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
2007 {
2008 switch (ch)
2009 {
2010 case 'i':
2011 aUpdateInterval = ValueUnion.u32;
2012 break;
2013
2014 default:
[94240]2015 return errorGetOptInternal(USAGE_I_GUESTSTATS, ch, &ValueUnion);
[36067]2016 }
2017 }
2018
2019 if (argc > 1 && aUpdateInterval == 0)
[94240]2020 return errorSyntaxInternal(USAGE_I_GUESTSTATS, Internal::tr("Invalid update interval specified"));
[36067]2021
[92372]2022 RTPrintf(Internal::tr("argc=%d interval=%u\n"), argc, aUpdateInterval);
[36067]2023
2024 ComPtr<IMachine> ptrMachine;
[95140]2025 HRESULT hrc;
[36067]2026 CHECK_ERROR_RET(aVirtualBox, FindMachine(Bstr(argv[0]).raw(),
[56118]2027 ptrMachine.asOutParam()), RTEXITCODE_FAILURE);
[36067]2028
[56118]2029 CHECK_ERROR_RET(ptrMachine, LockMachine(aSession, LockType_Shared), RTEXITCODE_FAILURE);
[36067]2030
2031 /*
2032 * Get the guest interface.
2033 */
2034 ComPtr<IConsole> ptrConsole;
[56118]2035 CHECK_ERROR_RET(aSession, COMGETTER(Console)(ptrConsole.asOutParam()), RTEXITCODE_FAILURE);
[36067]2036
2037 ComPtr<IGuest> ptrGuest;
[56118]2038 CHECK_ERROR_RET(ptrConsole, COMGETTER(Guest)(ptrGuest.asOutParam()), RTEXITCODE_FAILURE);
[36067]2039
2040 if (aUpdateInterval)
[56118]2041 CHECK_ERROR_RET(ptrGuest, COMSETTER(StatisticsUpdateInterval)(aUpdateInterval), RTEXITCODE_FAILURE);
[36067]2042 else
2043 {
2044 ULONG mCpuUser, mCpuKernel, mCpuIdle;
2045 ULONG mMemTotal, mMemFree, mMemBalloon, mMemShared, mMemCache, mPageTotal;
2046 ULONG ulMemAllocTotal, ulMemFreeTotal, ulMemBalloonTotal, ulMemSharedTotal;
2047
[36069]2048 CHECK_ERROR_RET(ptrGuest, InternalGetStatistics(&mCpuUser, &mCpuKernel, &mCpuIdle,
[56118]2049 &mMemTotal, &mMemFree, &mMemBalloon, &mMemShared, &mMemCache,
2050 &mPageTotal, &ulMemAllocTotal, &ulMemFreeTotal,
2051 &ulMemBalloonTotal, &ulMemSharedTotal),
2052 RTEXITCODE_FAILURE);
[36067]2053 RTPrintf("mCpuUser=%u mCpuKernel=%u mCpuIdle=%u\n"
2054 "mMemTotal=%u mMemFree=%u mMemBalloon=%u mMemShared=%u mMemCache=%u\n"
2055 "mPageTotal=%u ulMemAllocTotal=%u ulMemFreeTotal=%u ulMemBalloonTotal=%u ulMemSharedTotal=%u\n",
2056 mCpuUser, mCpuKernel, mCpuIdle,
2057 mMemTotal, mMemFree, mMemBalloon, mMemShared, mMemCache,
2058 mPageTotal, ulMemAllocTotal, ulMemFreeTotal, ulMemBalloonTotal, ulMemSharedTotal);
2059
2060 }
2061
[56118]2062 return RTEXITCODE_SUCCESS;
[36067]2063}
2064
2065
2066/**
[1]2067 * Wrapper for handling internal commands
2068 */
[56118]2069RTEXITCODE handleInternalCommands(HandlerArg *a)
[1]2070{
2071 /* at least a command is required */
[16052]2072 if (a->argc < 1)
[94290]2073 return errorSyntaxInternal(USAGE_I_ALL, Internal::tr("Command missing"));
[1]2074
2075 /*
2076 * The 'string switch' on command name.
2077 */
[16052]2078 const char *pszCmd = a->argv[0];
[39477]2079 if (!strcmp(pszCmd, "loadmap"))
2080 return CmdLoadMap(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[1]2081 if (!strcmp(pszCmd, "loadsyms"))
[16052]2082 return CmdLoadSyms(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[1]2083 //if (!strcmp(pszCmd, "unloadsyms"))
[49621]2084 // return CmdUnloadSyms(argc - 1, &a->argv[1]);
[31461]2085 if (!strcmp(pszCmd, "sethduuid") || !strcmp(pszCmd, "sethdparentuuid"))
2086 return CmdSetHDUUID(a->argc, &a->argv[0], a->virtualBox, a->session);
[21806]2087 if (!strcmp(pszCmd, "dumphdinfo"))
2088 return CmdDumpHDInfo(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[2675]2089 if (!strcmp(pszCmd, "listpartitions"))
[16052]2090 return CmdListPartitions(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[2675]2091 if (!strcmp(pszCmd, "createrawvmdk"))
[97313]2092 return CmdCreateRawVMDK(a->argc - 1, &a->argv[1], a);
[9047]2093 if (!strcmp(pszCmd, "renamevmdk"))
[16052]2094 return CmdRenameVMDK(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[11066]2095 if (!strcmp(pszCmd, "converttoraw"))
[16052]2096 return CmdConvertToRaw(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[15602]2097 if (!strcmp(pszCmd, "converthd"))
[16052]2098 return CmdConvertHardDisk(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[5895]2099 if (!strcmp(pszCmd, "modinstall"))
2100 return CmdModInstall();
2101 if (!strcmp(pszCmd, "moduninstall"))
2102 return CmdModUninstall();
[30319]2103 if (!strcmp(pszCmd, "debuglog"))
2104 return CmdDebugLog(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[33228]2105 if (!strcmp(pszCmd, "passwordhash"))
2106 return CmdGeneratePasswordHash(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[36067]2107 if (!strcmp(pszCmd, "gueststats"))
2108 return CmdGuestStats(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[39576]2109 if (!strcmp(pszCmd, "repairhd"))
2110 return CmdRepairHardDisk(a->argc - 1, &a->argv[1], a->virtualBox, a->session);
[5895]2111
[1]2112 /* default: */
[94290]2113 return errorSyntaxInternal(USAGE_I_ALL, Internal::tr("Invalid command '%s'"), a->argv[0]);
[1]2114}
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use