VirtualBox

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

Last change on this file since 98298 was 98298, checked in by vboxsync, 16 months ago

VBoxManage: rc -> vrc/hrc. Make scm check. bugref:10223

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

© 2023 Oracle
ContactPrivacy policyTerms of Use