VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxManage/VBoxManageInfo.cpp@ 35761

Last change on this file since 35761 was 35761, checked in by vboxsync, 14 years ago

Main, frontends: proper description for maximal number of NICs per VM

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 88.8 KB
Line 
1/* $Id: VBoxManageInfo.cpp 35761 2011-01-28 13:19:26Z vboxsync $ */
2/** @file
3 * VBoxManage - The 'showvminfo' command and helper routines.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18#ifndef VBOX_ONLY_DOCS
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#include <VBox/com/com.h>
24#include <VBox/com/string.h>
25#include <VBox/com/Guid.h>
26#include <VBox/com/array.h>
27#include <VBox/com/ErrorInfo.h>
28#include <VBox/com/errorprint.h>
29
30#include <VBox/com/VirtualBox.h>
31
32#include <VBox/log.h>
33#include <iprt/stream.h>
34#include <iprt/time.h>
35#include <iprt/string.h>
36#include <iprt/getopt.h>
37#include <iprt/ctype.h>
38
39#include "VBoxManage.h"
40using namespace com;
41
42
43// funcs
44///////////////////////////////////////////////////////////////////////////////
45
46void showSnapshots(ComPtr<ISnapshot> &rootSnapshot,
47 ComPtr<ISnapshot> &currentSnapshot,
48 VMINFO_DETAILS details,
49 const Bstr &prefix /* = ""*/,
50 int level /*= 0*/)
51{
52 /* start with the root */
53 Bstr name;
54 Bstr uuid;
55 rootSnapshot->COMGETTER(Name)(name.asOutParam());
56 rootSnapshot->COMGETTER(Id)(uuid.asOutParam());
57 if (details == VMINFO_MACHINEREADABLE)
58 {
59 /* print with hierarchical numbering */
60 RTPrintf("SnapshotName%lS=\"%lS\"\n", prefix.raw(), name.raw());
61 RTPrintf("SnapshotUUID%lS=\"%s\"\n", prefix.raw(), Utf8Str(uuid).c_str());
62 }
63 else
64 {
65 /* print with indentation */
66 bool fCurrent = (rootSnapshot == currentSnapshot);
67 RTPrintf(" %lSName: %lS (UUID: %s)%s\n",
68 prefix.raw(),
69 name.raw(),
70 Utf8Str(uuid).c_str(),
71 (fCurrent) ? " *" : "");
72 }
73
74 /* get the children */
75 SafeIfaceArray <ISnapshot> coll;
76 rootSnapshot->COMGETTER(Children)(ComSafeArrayAsOutParam(coll));
77 if (!coll.isNull())
78 {
79 for (size_t index = 0; index < coll.size(); ++index)
80 {
81 ComPtr<ISnapshot> snapshot = coll[index];
82 if (snapshot)
83 {
84 Bstr newPrefix;
85 if (details == VMINFO_MACHINEREADABLE)
86 newPrefix = Utf8StrFmt("%lS-%d", prefix.raw(), index + 1);
87 else
88 {
89 newPrefix = Utf8StrFmt("%lS ", prefix.raw());
90 }
91
92 /* recursive call */
93 showSnapshots(snapshot, currentSnapshot, details, newPrefix, level + 1);
94 }
95 }
96 }
97}
98
99static void makeTimeStr(char *s, int cb, int64_t millies)
100{
101 RTTIME t;
102 RTTIMESPEC ts;
103
104 RTTimeSpecSetMilli(&ts, millies);
105
106 RTTimeExplode(&t, &ts);
107
108 RTStrPrintf(s, cb, "%04d/%02d/%02d %02d:%02d:%02d UTC",
109 t.i32Year, t.u8Month, t.u8MonthDay,
110 t.u8Hour, t.u8Minute, t.u8Second);
111}
112
113
114const char *stateToName(MachineState_T machineState, bool fShort)
115{
116 switch (machineState)
117 {
118 case MachineState_PoweredOff:
119 return fShort ? "poweroff" : "powered off";
120 case MachineState_Saved:
121 return "saved";
122 case MachineState_Aborted:
123 return "aborted";
124 case MachineState_Teleported:
125 return "teleported";
126 case MachineState_Running:
127 return "running";
128 case MachineState_Paused:
129 return "paused";
130 case MachineState_Stuck:
131 return fShort ? "gurumeditation" : "guru meditation";
132 case MachineState_LiveSnapshotting:
133 return fShort ? "livesnapshotting" : "live snapshotting";
134 case MachineState_Teleporting:
135 return "teleporting";
136 case MachineState_Starting:
137 return "starting";
138 case MachineState_Stopping:
139 return "stopping";
140 case MachineState_Saving:
141 return "saving";
142 case MachineState_Restoring:
143 return "restoring";
144 case MachineState_TeleportingPausedVM:
145 return fShort ? "teleportingpausedvm" : "teleporting paused vm";
146 case MachineState_TeleportingIn:
147 return fShort ? "teleportingin" : "teleporting (incoming)";
148 case MachineState_RestoringSnapshot:
149 return fShort ? "restoringsnapshot" : "restoring snapshot";
150 case MachineState_DeletingSnapshot:
151 return fShort ? "deletingsnapshot" : "deleting snapshot";
152 case MachineState_DeletingSnapshotOnline:
153 return fShort ? "deletingsnapshotlive" : "deleting snapshot live";
154 case MachineState_DeletingSnapshotPaused:
155 return fShort ? "deletingsnapshotlivepaused" : "deleting snapshot live paused";
156 case MachineState_SettingUp:
157 return fShort ? "settingup" : "setting up";
158 default:
159 return "unknown";
160 }
161}
162
163/* Disable global optimizations for MSC 8.0/64 to make it compile in reasonable
164 time. MSC 7.1/32 doesn't have quite as much trouble with it, but still
165 sufficient to qualify for this hack as well since this code isn't performance
166 critical and probably won't gain much from the extra optimizing in real life. */
167#if defined(_MSC_VER)
168# pragma optimize("g", off)
169#endif
170
171HRESULT showVMInfo(ComPtr<IVirtualBox> virtualBox,
172 ComPtr<IMachine> machine,
173 VMINFO_DETAILS details /*= VMINFO_NONE*/,
174 ComPtr<IConsole> console /*= ComPtr <IConsole> ()*/)
175{
176 HRESULT rc;
177
178 /*
179 * The rules for output in -argdump format:
180 * 1) the key part (the [0-9a-zA-Z_]+ string before the '=' delimiter)
181 * is all lowercase for "VBoxManage modifyvm" parameters. Any
182 * other values printed are in CamelCase.
183 * 2) strings (anything non-decimal) are printed surrounded by
184 * double quotes '"'. If the strings themselves contain double
185 * quotes, these characters are escaped by '\'. Any '\' character
186 * in the original string is also escaped by '\'.
187 * 3) numbers (containing just [0-9\-]) are written out unchanged.
188 */
189
190 /** @todo the quoting is not yet implemented! */
191 /** @todo error checking! */
192
193 BOOL accessible = FALSE;
194 CHECK_ERROR(machine, COMGETTER(Accessible)(&accessible));
195 if (FAILED(rc)) return rc;
196
197 Bstr uuid;
198 rc = machine->COMGETTER(Id)(uuid.asOutParam());
199
200 if (!accessible)
201 {
202 if (details == VMINFO_COMPACT)
203 RTPrintf("\"<inaccessible>\" {%s}\n", Utf8Str(uuid).c_str());
204 else
205 {
206 if (details == VMINFO_MACHINEREADABLE)
207 RTPrintf("name=\"<inaccessible>\"\n");
208 else
209 RTPrintf("Name: <inaccessible!>\n");
210 if (details == VMINFO_MACHINEREADABLE)
211 RTPrintf("UUID=\"%s\"\n", Utf8Str(uuid).c_str());
212 else
213 RTPrintf("UUID: %s\n", Utf8Str(uuid).c_str());
214 if (details != VMINFO_MACHINEREADABLE)
215 {
216 Bstr settingsFilePath;
217 rc = machine->COMGETTER(SettingsFilePath)(settingsFilePath.asOutParam());
218 RTPrintf("Config file: %lS\n", settingsFilePath.raw());
219 ComPtr<IVirtualBoxErrorInfo> accessError;
220 rc = machine->COMGETTER(AccessError)(accessError.asOutParam());
221 RTPrintf("Access error details:\n");
222 ErrorInfo ei(accessError);
223 GluePrintErrorInfo(ei);
224 RTPrintf("\n");
225 }
226 }
227 return S_OK;
228 }
229
230 Bstr machineName;
231 rc = machine->COMGETTER(Name)(machineName.asOutParam());
232
233 if (details == VMINFO_COMPACT)
234 {
235 RTPrintf("\"%lS\" {%s}\n", machineName.raw(), Utf8Str(uuid).c_str());
236 return S_OK;
237 }
238
239 if (details == VMINFO_MACHINEREADABLE)
240 RTPrintf("name=\"%lS\"\n", machineName.raw());
241 else
242 RTPrintf("Name: %lS\n", machineName.raw());
243
244 Bstr osTypeId;
245 rc = machine->COMGETTER(OSTypeId)(osTypeId.asOutParam());
246 ComPtr<IGuestOSType> osType;
247 rc = virtualBox->GetGuestOSType(osTypeId.raw(), osType.asOutParam());
248 Bstr osName;
249 rc = osType->COMGETTER(Description)(osName.asOutParam());
250 if (details == VMINFO_MACHINEREADABLE)
251 RTPrintf("ostype=\"%lS\"\n", osTypeId.raw());
252 else
253 RTPrintf("Guest OS: %lS\n", osName.raw());
254
255 if (details == VMINFO_MACHINEREADABLE)
256 RTPrintf("UUID=\"%s\"\n", Utf8Str(uuid).c_str());
257 else
258 RTPrintf("UUID: %s\n", Utf8Str(uuid).c_str());
259
260 Bstr settingsFilePath;
261 rc = machine->COMGETTER(SettingsFilePath)(settingsFilePath.asOutParam());
262 if (details == VMINFO_MACHINEREADABLE)
263 RTPrintf("CfgFile=\"%lS\"\n", settingsFilePath.raw());
264 else
265 RTPrintf("Config file: %lS\n", settingsFilePath.raw());
266
267 Bstr snapshotFolder;
268 rc = machine->COMGETTER(SnapshotFolder)(snapshotFolder.asOutParam());
269 if (details == VMINFO_MACHINEREADABLE)
270 RTPrintf("SnapFldr=\"%lS\"\n", snapshotFolder.raw());
271 else
272 RTPrintf("Snapshot folder: %lS\n", snapshotFolder.raw());
273
274 Bstr logFolder;
275 rc = machine->COMGETTER(LogFolder)(logFolder.asOutParam());
276 if (details == VMINFO_MACHINEREADABLE)
277 RTPrintf("LogFldr=\"%lS\"\n", logFolder.raw());
278 else
279 RTPrintf("Log folder: %lS\n", logFolder.raw());
280
281 Bstr strHardwareUuid;
282 rc = machine->COMGETTER(HardwareUUID)(strHardwareUuid.asOutParam());
283 if (details == VMINFO_MACHINEREADABLE)
284 RTPrintf("hardwareuuid=\"%lS\"\n", strHardwareUuid.raw());
285 else
286 RTPrintf("Hardware UUID: %lS\n", strHardwareUuid.raw());
287
288 ULONG memorySize;
289 rc = machine->COMGETTER(MemorySize)(&memorySize);
290 if (details == VMINFO_MACHINEREADABLE)
291 RTPrintf("memory=%u\n", memorySize);
292 else
293 RTPrintf("Memory size: %uMB\n", memorySize);
294
295 BOOL fPageFusionEnabled;
296 rc = machine->COMGETTER(PageFusionEnabled)(&fPageFusionEnabled);
297 if (details == VMINFO_MACHINEREADABLE)
298 RTPrintf("pagefusion=\"%s\"\n", fPageFusionEnabled ? "on" : "off");
299 else
300 RTPrintf("Page Fusion: %s\n", fPageFusionEnabled ? "on" : "off");
301
302 ULONG vramSize;
303 rc = machine->COMGETTER(VRAMSize)(&vramSize);
304 if (details == VMINFO_MACHINEREADABLE)
305 RTPrintf("vram=%u\n", vramSize);
306 else
307 RTPrintf("VRAM size: %uMB\n", vramSize);
308
309 BOOL fHpetEnabled;
310 machine->COMGETTER(HpetEnabled)(&fHpetEnabled);
311 if (details == VMINFO_MACHINEREADABLE)
312 RTPrintf("hpet=\"%s\"\n", fHpetEnabled ? "on" : "off");
313 else
314 RTPrintf("HPET: %s\n", fHpetEnabled ? "on" : "off");
315
316 ChipsetType_T chipsetType = ChipsetType_Null;
317 const char *pszChipsetType = NULL;
318 machine->COMGETTER(ChipsetType)(&chipsetType);
319 switch (chipsetType)
320 {
321 case ChipsetType_Null:
322 pszChipsetType = "invalid";
323 break;
324 case ChipsetType_PIIX3:
325 pszChipsetType = "piix3";
326 break;
327 case ChipsetType_ICH9:
328 pszChipsetType = "ich9";
329 break;
330 default:
331 Assert(false);
332 pszChipsetType = "unknown";
333 }
334 if (details == VMINFO_MACHINEREADABLE)
335 RTPrintf("chipset=\"%s\"\n", pszChipsetType);
336 else
337 RTPrintf("Chipset: %s\n", pszChipsetType);
338
339 FirmwareType_T firmwareType = FirmwareType_BIOS;
340 const char *pszFirmwareType = NULL;
341 machine->COMGETTER(FirmwareType)(&firmwareType);
342 switch (firmwareType)
343 {
344 case FirmwareType_BIOS:
345 pszFirmwareType = "BIOS";
346 break;
347 case FirmwareType_EFI:
348 pszFirmwareType = "EFI";
349 break;
350 case FirmwareType_EFI32:
351 pszFirmwareType = "EFI32";
352 break;
353 case FirmwareType_EFI64:
354 pszFirmwareType = "EFI64";
355 break;
356 case FirmwareType_EFIDUAL:
357 pszFirmwareType = "EFIDUAL";
358 break;
359 default:
360 Assert(false);
361 pszFirmwareType = "unknown";
362 }
363 if (details == VMINFO_MACHINEREADABLE)
364 RTPrintf("firmware=\"%s\"\n", pszFirmwareType);
365 else
366 RTPrintf("Firmware: %s\n", pszFirmwareType);
367
368
369 ULONG numCpus;
370 rc = machine->COMGETTER(CPUCount)(&numCpus);
371 if (details == VMINFO_MACHINEREADABLE)
372 RTPrintf("cpus=%u\n", numCpus);
373 else
374 RTPrintf("Number of CPUs: %u\n", numCpus);
375
376 BOOL fSyntheticCpu;
377 machine->GetCPUProperty(CPUPropertyType_Synthetic, &fSyntheticCpu);
378 if (details == VMINFO_MACHINEREADABLE)
379 RTPrintf("synthcpu=\"%s\"\n", fSyntheticCpu ? "on" : "off");
380 else
381 RTPrintf("Synthetic Cpu: %s\n", fSyntheticCpu ? "on" : "off");
382
383 if (details != VMINFO_MACHINEREADABLE)
384 RTPrintf("CPUID overrides: ");
385 ULONG cFound = 0;
386 static uint32_t const s_auCpuIdRanges[] =
387 {
388 UINT32_C(0x00000000), UINT32_C(0x0000000a),
389 UINT32_C(0x80000000), UINT32_C(0x8000000a)
390 };
391 for (unsigned i = 0; i < RT_ELEMENTS(s_auCpuIdRanges); i += 2)
392 for (uint32_t uLeaf = s_auCpuIdRanges[i]; uLeaf < s_auCpuIdRanges[i + 1]; uLeaf++)
393 {
394 ULONG uEAX, uEBX, uECX, uEDX;
395 rc = machine->GetCPUIDLeaf(uLeaf, &uEAX, &uEBX, &uECX, &uEDX);
396 if (SUCCEEDED(rc))
397 {
398 if (details == VMINFO_MACHINEREADABLE)
399 RTPrintf("cpuid=%08x,%08x,%08x,%08x,%08x", uLeaf, uEAX, uEBX, uECX, uEDX);
400 else
401 {
402 if (!cFound)
403 RTPrintf("Leaf no. EAX EBX ECX EDX\n");
404 RTPrintf(" %08x %08x %08x %08x %08x\n", uLeaf, uEAX, uEBX, uECX, uEDX);
405 }
406 cFound++;
407 }
408 }
409 if (!cFound && details != VMINFO_MACHINEREADABLE)
410 RTPrintf("None\n");
411
412 ComPtr <IBIOSSettings> biosSettings;
413 machine->COMGETTER(BIOSSettings)(biosSettings.asOutParam());
414
415 BIOSBootMenuMode_T bootMenuMode;
416 biosSettings->COMGETTER(BootMenuMode)(&bootMenuMode);
417 const char *pszBootMenu = NULL;
418 switch (bootMenuMode)
419 {
420 case BIOSBootMenuMode_Disabled:
421 pszBootMenu = "disabled";
422 break;
423 case BIOSBootMenuMode_MenuOnly:
424 if (details == VMINFO_MACHINEREADABLE)
425 pszBootMenu = "menuonly";
426 else
427 pszBootMenu = "menu only";
428 break;
429 default:
430 if (details == VMINFO_MACHINEREADABLE)
431 pszBootMenu = "messageandmenu";
432 else
433 pszBootMenu = "message and menu";
434 }
435 if (details == VMINFO_MACHINEREADABLE)
436 RTPrintf("bootmenu=\"%s\"\n", pszBootMenu);
437 else
438 RTPrintf("Boot menu mode: %s\n", pszBootMenu);
439
440 ULONG maxBootPosition = 0;
441 ComPtr<ISystemProperties> systemProperties;
442 virtualBox->COMGETTER(SystemProperties)(systemProperties.asOutParam());
443 systemProperties->COMGETTER(MaxBootPosition)(&maxBootPosition);
444 for (ULONG i = 1; i <= maxBootPosition; i++)
445 {
446 DeviceType_T bootOrder;
447 machine->GetBootOrder(i, &bootOrder);
448 if (bootOrder == DeviceType_Floppy)
449 {
450 if (details == VMINFO_MACHINEREADABLE)
451 RTPrintf("boot%d=\"floppy\"\n", i);
452 else
453 RTPrintf("Boot Device (%d): Floppy\n", i);
454 }
455 else if (bootOrder == DeviceType_DVD)
456 {
457 if (details == VMINFO_MACHINEREADABLE)
458 RTPrintf("boot%d=\"dvd\"\n", i);
459 else
460 RTPrintf("Boot Device (%d): DVD\n", i);
461 }
462 else if (bootOrder == DeviceType_HardDisk)
463 {
464 if (details == VMINFO_MACHINEREADABLE)
465 RTPrintf("boot%d=\"disk\"\n", i);
466 else
467 RTPrintf("Boot Device (%d): HardDisk\n", i);
468 }
469 else if (bootOrder == DeviceType_Network)
470 {
471 if (details == VMINFO_MACHINEREADABLE)
472 RTPrintf("boot%d=\"net\"\n", i);
473 else
474 RTPrintf("Boot Device (%d): Network\n", i);
475 }
476 else if (bootOrder == DeviceType_USB)
477 {
478 if (details == VMINFO_MACHINEREADABLE)
479 RTPrintf("boot%d=\"usb\"\n", i);
480 else
481 RTPrintf("Boot Device (%d): USB\n", i);
482 }
483 else if (bootOrder == DeviceType_SharedFolder)
484 {
485 if (details == VMINFO_MACHINEREADABLE)
486 RTPrintf("boot%d=\"sharedfolder\"\n", i);
487 else
488 RTPrintf("Boot Device (%d): Shared Folder\n", i);
489 }
490 else
491 {
492 if (details == VMINFO_MACHINEREADABLE)
493 RTPrintf("boot%d=\"none\"\n", i);
494 else
495 RTPrintf("Boot Device (%d): Not Assigned\n", i);
496 }
497 }
498
499 BOOL acpiEnabled;
500 biosSettings->COMGETTER(ACPIEnabled)(&acpiEnabled);
501 if (details == VMINFO_MACHINEREADABLE)
502 RTPrintf("acpi=\"%s\"\n", acpiEnabled ? "on" : "off");
503 else
504 RTPrintf("ACPI: %s\n", acpiEnabled ? "on" : "off");
505
506 BOOL ioapicEnabled;
507 biosSettings->COMGETTER(IOAPICEnabled)(&ioapicEnabled);
508 if (details == VMINFO_MACHINEREADABLE)
509 RTPrintf("ioapic=\"%s\"\n", ioapicEnabled ? "on" : "off");
510 else
511 RTPrintf("IOAPIC: %s\n", ioapicEnabled ? "on" : "off");
512
513 BOOL PAEEnabled;
514 machine->GetCPUProperty(CPUPropertyType_PAE, &PAEEnabled);
515 if (details == VMINFO_MACHINEREADABLE)
516 RTPrintf("pae=\"%s\"\n", PAEEnabled ? "on" : "off");
517 else
518 RTPrintf("PAE: %s\n", PAEEnabled ? "on" : "off");
519
520 LONG64 timeOffset;
521 biosSettings->COMGETTER(TimeOffset)(&timeOffset);
522 if (details == VMINFO_MACHINEREADABLE)
523 RTPrintf("biossystemtimeoffset=%lld\n", timeOffset);
524 else
525 RTPrintf("Time offset: %lld ms\n", timeOffset);
526
527 BOOL RTCUseUTC;
528 machine->COMGETTER(RTCUseUTC)(&RTCUseUTC);
529 if (details == VMINFO_MACHINEREADABLE)
530 RTPrintf("rtcuseutc=\"%s\"\n", RTCUseUTC ? "on" : "off");
531 else
532 RTPrintf("RTC: %s\n", RTCUseUTC ? "UTC" : "local time");
533
534 BOOL hwVirtExEnabled;
535 machine->GetHWVirtExProperty(HWVirtExPropertyType_Enabled, &hwVirtExEnabled);
536 if (details == VMINFO_MACHINEREADABLE)
537 RTPrintf("hwvirtex=\"%s\"\n", hwVirtExEnabled ? "on" : "off");
538 else
539 RTPrintf("Hardw. virt.ext: %s\n", hwVirtExEnabled ? "on" : "off");
540
541 BOOL hwVirtExExclusive;
542 machine->GetHWVirtExProperty(HWVirtExPropertyType_Exclusive, &hwVirtExExclusive);
543 if (details == VMINFO_MACHINEREADABLE)
544 RTPrintf("hwvirtexexcl=\"%s\"\n", hwVirtExExclusive ? "on" : "off");
545 else
546 RTPrintf("Hardw. virt.ext exclusive: %s\n", hwVirtExExclusive ? "on" : "off");
547
548 BOOL HWVirtExNestedPagingEnabled;
549 machine->GetHWVirtExProperty(HWVirtExPropertyType_NestedPaging, &HWVirtExNestedPagingEnabled);
550 if (details == VMINFO_MACHINEREADABLE)
551 RTPrintf("nestedpaging=\"%s\"\n", HWVirtExNestedPagingEnabled ? "on" : "off");
552 else
553 RTPrintf("Nested Paging: %s\n", HWVirtExNestedPagingEnabled ? "on" : "off");
554
555 BOOL HWVirtExLargePagesEnabled;
556 machine->GetHWVirtExProperty(HWVirtExPropertyType_LargePages, &HWVirtExLargePagesEnabled);
557 if (details == VMINFO_MACHINEREADABLE)
558 RTPrintf("largepages=\"%s\"\n", HWVirtExLargePagesEnabled ? "on" : "off");
559 else
560 RTPrintf("Large Pages: %s\n", HWVirtExLargePagesEnabled ? "on" : "off");
561
562 BOOL HWVirtExVPIDEnabled;
563 machine->GetHWVirtExProperty(HWVirtExPropertyType_VPID, &HWVirtExVPIDEnabled);
564 if (details == VMINFO_MACHINEREADABLE)
565 RTPrintf("vtxvpid=\"%s\"\n", HWVirtExVPIDEnabled ? "on" : "off");
566 else
567 RTPrintf("VT-x VPID: %s\n", HWVirtExVPIDEnabled ? "on" : "off");
568
569 MachineState_T machineState;
570 rc = machine->COMGETTER(State)(&machineState);
571 const char *pszState = stateToName(machineState, details == VMINFO_MACHINEREADABLE /*=fShort*/);
572
573 LONG64 stateSince;
574 machine->COMGETTER(LastStateChange)(&stateSince);
575 RTTIMESPEC timeSpec;
576 RTTimeSpecSetMilli(&timeSpec, stateSince);
577 char pszTime[30] = {0};
578 RTTimeSpecToString(&timeSpec, pszTime, sizeof(pszTime));
579 Bstr stateFile;
580 machine->COMGETTER(StateFilePath)(stateFile.asOutParam());
581 if (details == VMINFO_MACHINEREADABLE)
582 {
583 RTPrintf("VMState=\"%s\"\n", pszState);
584 RTPrintf("VMStateChangeTime=\"%s\"\n", pszTime);
585 if (!stateFile.isEmpty())
586 RTPrintf("VMStateFile=\"%lS\"\n", stateFile.raw());
587 }
588 else
589 RTPrintf("State: %s (since %s)\n", pszState, pszTime);
590
591 ULONG numMonitors;
592 machine->COMGETTER(MonitorCount)(&numMonitors);
593 if (details == VMINFO_MACHINEREADABLE)
594 RTPrintf("monitorcount=%d\n", numMonitors);
595 else
596 RTPrintf("Monitor count: %d\n", numMonitors);
597
598 BOOL accelerate3d;
599 machine->COMGETTER(Accelerate3DEnabled)(&accelerate3d);
600 if (details == VMINFO_MACHINEREADABLE)
601 RTPrintf("accelerate3d=\"%s\"\n", accelerate3d ? "on" : "off");
602 else
603 RTPrintf("3D Acceleration: %s\n", accelerate3d ? "on" : "off");
604
605#ifdef VBOX_WITH_VIDEOHWACCEL
606 BOOL accelerate2dVideo;
607 machine->COMGETTER(Accelerate2DVideoEnabled)(&accelerate2dVideo);
608 if (details == VMINFO_MACHINEREADABLE)
609 RTPrintf("accelerate2dvideo=\"%s\"\n", accelerate2dVideo ? "on" : "off");
610 else
611 RTPrintf("2D Video Acceleration: %s\n", accelerate2dVideo ? "on" : "off");
612#endif
613
614 BOOL teleporterEnabled;
615 machine->COMGETTER(TeleporterEnabled)(&teleporterEnabled);
616 if (details == VMINFO_MACHINEREADABLE)
617 RTPrintf("teleporterenabled=\"%s\"\n", teleporterEnabled ? "on" : "off");
618 else
619 RTPrintf("Teleporter Enabled: %s\n", teleporterEnabled ? "on" : "off");
620
621 ULONG teleporterPort;
622 machine->COMGETTER(TeleporterPort)(&teleporterPort);
623 if (details == VMINFO_MACHINEREADABLE)
624 RTPrintf("teleporterport=%u\n", teleporterPort);
625 else
626 RTPrintf("Teleporter Port: %u\n", teleporterPort);
627
628 Bstr teleporterAddress;
629 machine->COMGETTER(TeleporterAddress)(teleporterAddress.asOutParam());
630 if (details == VMINFO_MACHINEREADABLE)
631 RTPrintf("teleporteraddress=\"%lS\"\n", teleporterAddress.raw());
632 else
633 RTPrintf("Teleporter Address: %lS\n", teleporterAddress.raw());
634
635 Bstr teleporterPassword;
636 machine->COMGETTER(TeleporterPassword)(teleporterPassword.asOutParam());
637 if (details == VMINFO_MACHINEREADABLE)
638 RTPrintf("teleporterpassword=\"%lS\"\n", teleporterPassword.raw());
639 else
640 RTPrintf("Teleporter Password: %lS\n", teleporterPassword.raw());
641
642 /*
643 * Storage Controllers and their attached Mediums.
644 */
645 com::SafeIfaceArray<IStorageController> storageCtls;
646 CHECK_ERROR(machine, COMGETTER(StorageControllers)(ComSafeArrayAsOutParam(storageCtls)));
647 for (size_t i = 0; i < storageCtls.size(); ++ i)
648 {
649 ComPtr<IStorageController> storageCtl = storageCtls[i];
650 StorageControllerType_T enmCtlType = StorageControllerType_Null;
651 const char *pszCtl = NULL;
652 ULONG ulValue = 0;
653 BOOL fBootable = FALSE;
654 Bstr storageCtlName;
655
656 storageCtl->COMGETTER(Name)(storageCtlName.asOutParam());
657 if (details == VMINFO_MACHINEREADABLE)
658 RTPrintf("storagecontrollername%u=\"%lS\"\n", i, storageCtlName.raw());
659 else
660 RTPrintf("Storage Controller Name (%u): %lS\n", i, storageCtlName.raw());
661
662 storageCtl->COMGETTER(ControllerType)(&enmCtlType);
663 switch (enmCtlType)
664 {
665 case StorageControllerType_LsiLogic:
666 pszCtl = "LsiLogic";
667 break;
668 case StorageControllerType_BusLogic:
669 pszCtl = "BusLogic";
670 break;
671 case StorageControllerType_IntelAhci:
672 pszCtl = "IntelAhci";
673 break;
674 case StorageControllerType_PIIX3:
675 pszCtl = "PIIX3";
676 break;
677 case StorageControllerType_PIIX4:
678 pszCtl = "PIIX4";
679 break;
680 case StorageControllerType_ICH6:
681 pszCtl = "ICH6";
682 break;
683 case StorageControllerType_I82078:
684 pszCtl = "I82078";
685 break;
686
687 default:
688 pszCtl = "unknown";
689 }
690 if (details == VMINFO_MACHINEREADABLE)
691 RTPrintf("storagecontrollertype%u=\"%s\"\n", i, pszCtl);
692 else
693 RTPrintf("Storage Controller Type (%u): %s\n", i, pszCtl);
694
695 storageCtl->COMGETTER(Instance)(&ulValue);
696 if (details == VMINFO_MACHINEREADABLE)
697 RTPrintf("storagecontrollerinstance%u=\"%lu\"\n", i, ulValue);
698 else
699 RTPrintf("Storage Controller Instance Number (%u): %lu\n", i, ulValue);
700
701 storageCtl->COMGETTER(MaxPortCount)(&ulValue);
702 if (details == VMINFO_MACHINEREADABLE)
703 RTPrintf("storagecontrollermaxportcount%u=\"%lu\"\n", i, ulValue);
704 else
705 RTPrintf("Storage Controller Max Port Count (%u): %lu\n", i, ulValue);
706
707 storageCtl->COMGETTER(PortCount)(&ulValue);
708 if (details == VMINFO_MACHINEREADABLE)
709 RTPrintf("storagecontrollerportcount%u=\"%lu\"\n", i, ulValue);
710 else
711 RTPrintf("Storage Controller Port Count (%u): %lu\n", i, ulValue);
712
713 storageCtl->COMGETTER(Bootable)(&fBootable);
714 if (details == VMINFO_MACHINEREADABLE)
715 RTPrintf("storagecontrollerbootable%u=\"%s\"\n", i, fBootable ? "on" : "off");
716 else
717 RTPrintf("Storage Controller Bootable (%u): %s\n", i, fBootable ? "on" : "off");
718 }
719
720 for (size_t j = 0; j < storageCtls.size(); ++ j)
721 {
722 ComPtr<IStorageController> storageCtl = storageCtls[j];
723 ComPtr<IMedium> medium;
724 Bstr storageCtlName;
725 Bstr filePath;
726 ULONG cDevices;
727 ULONG cPorts;
728
729 storageCtl->COMGETTER(Name)(storageCtlName.asOutParam());
730 storageCtl->COMGETTER(MaxDevicesPerPortCount)(&cDevices);
731 storageCtl->COMGETTER(PortCount)(&cPorts);
732
733 for (ULONG i = 0; i < cPorts; ++ i)
734 {
735 for (ULONG k = 0; k < cDevices; ++ k)
736 {
737 rc = machine->GetMedium(storageCtlName.raw(), i, k,
738 medium.asOutParam());
739 if (SUCCEEDED(rc) && medium)
740 {
741 BOOL fPassthrough;
742 ComPtr<IMediumAttachment> mediumAttach;
743
744 rc = machine->GetMediumAttachment(storageCtlName.raw(),
745 i, k,
746 mediumAttach.asOutParam());
747 if (SUCCEEDED(rc) && mediumAttach)
748 mediumAttach->COMGETTER(Passthrough)(&fPassthrough);
749
750 medium->COMGETTER(Location)(filePath.asOutParam());
751 medium->COMGETTER(Id)(uuid.asOutParam());
752
753 if (details == VMINFO_MACHINEREADABLE)
754 {
755 RTPrintf("\"%lS-%d-%d\"=\"%lS\"\n", storageCtlName.raw(),
756 i, k, filePath.raw());
757 RTPrintf("\"%lS-ImageUUID-%d-%d\"=\"%s\"\n",
758 storageCtlName.raw(), i, k, Utf8Str(uuid).c_str());
759 if (fPassthrough)
760 RTPrintf("\"%lS-dvdpassthrough\"=\"%s\"\n", storageCtlName.raw(),
761 fPassthrough ? "on" : "off");
762 }
763 else
764 {
765 RTPrintf("%lS (%d, %d): %lS (UUID: %s)",
766 storageCtlName.raw(), i, k, filePath.raw(),
767 Utf8Str(uuid).c_str());
768 if (fPassthrough)
769 RTPrintf(" (passthrough enabled)");
770 RTPrintf("\n");
771 }
772 }
773 else if (SUCCEEDED(rc))
774 {
775 if (details == VMINFO_MACHINEREADABLE)
776 RTPrintf("\"%lS-%d-%d\"=\"emptydrive\"\n", storageCtlName.raw(), i, k);
777 else
778 RTPrintf("%lS (%d, %d): Empty\n", storageCtlName.raw(), i, k);
779 }
780 else
781 {
782 if (details == VMINFO_MACHINEREADABLE)
783 RTPrintf("\"%lS-%d-%d\"=\"none\"\n", storageCtlName.raw(), i, k);
784 }
785 }
786 }
787 }
788
789 /* get the maximum amount of NICS */
790 ULONG maxNICs = getMaxNics(virtualBox, machine);
791
792 for (ULONG currentNIC = 0; currentNIC < maxNICs; currentNIC++)
793 {
794 ComPtr<INetworkAdapter> nic;
795 rc = machine->GetNetworkAdapter(currentNIC, nic.asOutParam());
796 if (SUCCEEDED(rc) && nic)
797 {
798 BOOL fEnabled;
799 nic->COMGETTER(Enabled)(&fEnabled);
800 if (!fEnabled)
801 {
802 if (details == VMINFO_MACHINEREADABLE)
803 RTPrintf("nic%d=\"none\"\n", currentNIC + 1);
804 else
805 RTPrintf("NIC %d: disabled\n", currentNIC + 1);
806 }
807 else
808 {
809 Bstr strMACAddress;
810 nic->COMGETTER(MACAddress)(strMACAddress.asOutParam());
811 Utf8Str strAttachment;
812 Utf8Str strNatSettings = "";
813 Utf8Str strNatForwardings = "";
814 NetworkAttachmentType_T attachment;
815 nic->COMGETTER(AttachmentType)(&attachment);
816 switch (attachment)
817 {
818 case NetworkAttachmentType_Null:
819 if (details == VMINFO_MACHINEREADABLE)
820 strAttachment = "null";
821 else
822 strAttachment = "none";
823 break;
824 case NetworkAttachmentType_NAT:
825 {
826 Bstr strNetwork;
827 ComPtr<INATEngine> driver;
828 nic->COMGETTER(NatDriver)(driver.asOutParam());
829 driver->COMGETTER(Network)(strNetwork.asOutParam());
830 com::SafeArray<BSTR> forwardings;
831 driver->COMGETTER(Redirects)(ComSafeArrayAsOutParam(forwardings));
832 strNatForwardings = "";
833 for (size_t i = 0; i < forwardings.size(); ++i)
834 {
835 bool fSkip = false;
836 uint16_t port = 0;
837 BSTR r = forwardings[i];
838 Utf8Str utf = Utf8Str(r);
839 Utf8Str strName;
840 Utf8Str strProto;
841 Utf8Str strHostPort;
842 Utf8Str strHostIP;
843 Utf8Str strGuestPort;
844 Utf8Str strGuestIP;
845 size_t pos, ppos;
846 pos = ppos = 0;
847 #define ITERATE_TO_NEXT_TERM(res, str, pos, ppos) \
848 do { \
849 pos = str.find(",", ppos); \
850 if (pos == Utf8Str::npos) \
851 { \
852 Log(( #res " extracting from %s is failed\n", str.c_str())); \
853 fSkip = true; \
854 } \
855 res = str.substr(ppos, pos - ppos); \
856 Log2((#res " %s pos:%d, ppos:%d\n", res.c_str(), pos, ppos)); \
857 ppos = pos + 1; \
858 } while (0)
859 ITERATE_TO_NEXT_TERM(strName, utf, pos, ppos);
860 if (fSkip) continue;
861 ITERATE_TO_NEXT_TERM(strProto, utf, pos, ppos);
862 if (fSkip) continue;
863 ITERATE_TO_NEXT_TERM(strHostIP, utf, pos, ppos);
864 if (fSkip) continue;
865 ITERATE_TO_NEXT_TERM(strHostPort, utf, pos, ppos);
866 if (fSkip) continue;
867 ITERATE_TO_NEXT_TERM(strGuestIP, utf, pos, ppos);
868 if (fSkip) continue;
869 strGuestPort = utf.substr(ppos, utf.length() - ppos);
870 #undef ITERATE_TO_NEXT_TERM
871 switch (strProto.toUInt32())
872 {
873 case NATProtocol_TCP:
874 strProto = "tcp";
875 break;
876 case NATProtocol_UDP:
877 strProto = "udp";
878 break;
879 default:
880 strProto = "unk";
881 break;
882 }
883 if (details == VMINFO_MACHINEREADABLE)
884 {
885 strNatForwardings = Utf8StrFmt("%sForwarding(%d)=\"%s,%s,%s,%s,%s,%s\"\n",
886 strNatForwardings.c_str(), i, strName.c_str(), strProto.c_str(),
887 strHostIP.c_str(), strHostPort.c_str(),
888 strGuestIP.c_str(), strGuestPort.c_str());
889 }
890 else
891 {
892 strNatForwardings = Utf8StrFmt("%sNIC %d Rule(%d): name = %s, protocol = %s,"
893 " host ip = %s, host port = %s, guest ip = %s, guest port = %s\n",
894 strNatForwardings.c_str(), currentNIC + 1, i, strName.c_str(), strProto.c_str(),
895 strHostIP.c_str(), strHostPort.c_str(),
896 strGuestIP.c_str(), strGuestPort.c_str());
897 }
898 }
899 ULONG mtu = 0;
900 ULONG sockSnd = 0;
901 ULONG sockRcv = 0;
902 ULONG tcpSnd = 0;
903 ULONG tcpRcv = 0;
904 driver->GetNetworkSettings(&mtu, &sockSnd, &sockRcv, &tcpSnd, &tcpRcv);
905
906 if (details == VMINFO_MACHINEREADABLE)
907 {
908 RTPrintf("natnet%d=\"%lS\"\n", currentNIC + 1, strNetwork.length() ? strNetwork.raw(): Bstr("nat").raw());
909 strAttachment = "nat";
910 strNatSettings = Utf8StrFmt("mtu=\"%d\"\nsockSnd=\"%d\"\nsockRcv=\"%d\"\ntcpWndSnd=\"%d\"\ntcpWndRcv=\"%d\"\n",
911 mtu, sockSnd ? sockSnd : 64, sockRcv ? sockRcv : 64 , tcpSnd ? tcpSnd : 64, tcpRcv ? tcpRcv : 64);
912 }
913 else
914 {
915 strAttachment = "NAT";
916 strNatSettings = Utf8StrFmt("NIC %d Settings: MTU: %d, Socket( send: %d, receive: %d), TCP Window( send:%d, receive: %d)\n",
917 currentNIC + 1, mtu, sockSnd ? sockSnd : 64, sockRcv ? sockRcv : 64 , tcpSnd ? tcpSnd : 64, tcpRcv ? tcpRcv : 64);
918 }
919 break;
920 }
921 case NetworkAttachmentType_Bridged:
922 {
923 Bstr strBridgeAdp;
924 nic->COMGETTER(HostInterface)(strBridgeAdp.asOutParam());
925 if (details == VMINFO_MACHINEREADABLE)
926 {
927 RTPrintf("bridgeadapter%d=\"%lS\"\n", currentNIC + 1, strBridgeAdp.raw());
928 strAttachment = "bridged";
929 }
930 else
931 strAttachment = Utf8StrFmt("Bridged Interface '%lS'", strBridgeAdp.raw());
932 break;
933 }
934 case NetworkAttachmentType_Internal:
935 {
936 Bstr strNetwork;
937 nic->COMGETTER(InternalNetwork)(strNetwork.asOutParam());
938 if (details == VMINFO_MACHINEREADABLE)
939 {
940 RTPrintf("intnet%d=\"%lS\"\n", currentNIC + 1, strNetwork.raw());
941 strAttachment = "intnet";
942 }
943 else
944 strAttachment = Utf8StrFmt("Internal Network '%s'", Utf8Str(strNetwork).c_str());
945 break;
946 }
947#if defined(VBOX_WITH_NETFLT)
948 case NetworkAttachmentType_HostOnly:
949 {
950 Bstr strHostonlyAdp;
951 nic->COMGETTER(HostInterface)(strHostonlyAdp.asOutParam());
952 if (details == VMINFO_MACHINEREADABLE)
953 {
954 RTPrintf("hostonlyadapter%d=\"%lS\"\n", currentNIC + 1, strHostonlyAdp.raw());
955 strAttachment = "hostonly";
956 }
957 else
958 strAttachment = Utf8StrFmt("Host-only Interface '%lS'", strHostonlyAdp.raw());
959 break;
960 }
961#endif
962#ifdef VBOX_WITH_VDE
963 case NetworkAttachmentType_VDE:
964 {
965 Bstr strVDEAdp;
966 nic->COMGETTER(VDENetwork)(strVDEAdp.asOutParam());
967 if (details == VMINFO_MACHINEREADABLE)
968 {
969 RTPrintf("vdenet%d=\"%lS\"\n", currentNIC + 1, strVDEAdp.raw());
970 strAttachment = "VDE";
971 }
972 else
973 strAttachment = Utf8StrFmt("VDE Network '%lS'", strVDEAdp.raw());
974 break;
975 }
976#endif
977 default:
978 strAttachment = "unknown";
979 break;
980 }
981
982 /* cable connected */
983 BOOL fConnected;
984 nic->COMGETTER(CableConnected)(&fConnected);
985
986 /* trace stuff */
987 BOOL fTraceEnabled;
988 nic->COMGETTER(TraceEnabled)(&fTraceEnabled);
989 Bstr traceFile;
990 nic->COMGETTER(TraceFile)(traceFile.asOutParam());
991
992 /* NIC type */
993 Utf8Str strNICType;
994 NetworkAdapterType_T NICType;
995 nic->COMGETTER(AdapterType)(&NICType);
996 switch (NICType) {
997 case NetworkAdapterType_Am79C970A:
998 strNICType = "Am79C970A";
999 break;
1000 case NetworkAdapterType_Am79C973:
1001 strNICType = "Am79C973";
1002 break;
1003#ifdef VBOX_WITH_E1000
1004 case NetworkAdapterType_I82540EM:
1005 strNICType = "82540EM";
1006 break;
1007 case NetworkAdapterType_I82543GC:
1008 strNICType = "82543GC";
1009 break;
1010 case NetworkAdapterType_I82545EM:
1011 strNICType = "82545EM";
1012 break;
1013#endif
1014#ifdef VBOX_WITH_VIRTIO
1015 case NetworkAdapterType_Virtio:
1016 strNICType = "virtio";
1017 break;
1018#endif /* VBOX_WITH_VIRTIO */
1019 default:
1020 strNICType = "unknown";
1021 break;
1022 }
1023
1024 /* reported line speed */
1025 ULONG ulLineSpeed;
1026 nic->COMGETTER(LineSpeed)(&ulLineSpeed);
1027
1028 /* boot priority of the adapter */
1029 ULONG ulBootPriority;
1030 nic->COMGETTER(BootPriority)(&ulBootPriority);
1031
1032 if (details == VMINFO_MACHINEREADABLE)
1033 {
1034 RTPrintf("macaddress%d=\"%lS\"\n", currentNIC + 1, strMACAddress.raw());
1035 RTPrintf("cableconnected%d=\"%s\"\n", currentNIC + 1, fConnected ? "on" : "off");
1036 RTPrintf("nic%d=\"%s\"\n", currentNIC + 1, strAttachment.c_str());
1037 }
1038 else
1039 RTPrintf("NIC %d: MAC: %lS, Attachment: %s, Cable connected: %s, Trace: %s (file: %lS), Type: %s, Reported speed: %d Mbps, Boot priority: %d\n",
1040 currentNIC + 1, strMACAddress.raw(), strAttachment.c_str(),
1041 fConnected ? "on" : "off",
1042 fTraceEnabled ? "on" : "off",
1043 traceFile.isEmpty() ? Bstr("none").raw() : traceFile.raw(),
1044 strNICType.c_str(),
1045 ulLineSpeed / 1000,
1046 (int)ulBootPriority);
1047 if (strNatSettings.length())
1048 RTPrintf(strNatSettings.c_str());
1049 if (strNatForwardings.length())
1050 RTPrintf(strNatForwardings.c_str());
1051 }
1052 }
1053 }
1054
1055 /* Pointing device information */
1056 PointingHidType_T aPointingHid;
1057 const char *pszHid = "Unknown";
1058 const char *pszMrHid = "unknown";
1059 machine->COMGETTER(PointingHidType)(&aPointingHid);
1060 switch (aPointingHid)
1061 {
1062 case PointingHidType_None:
1063 pszHid = "None";
1064 pszMrHid = "none";
1065 break;
1066 case PointingHidType_PS2Mouse:
1067 pszHid = "PS/2 Mouse";
1068 pszMrHid = "ps2mouse";
1069 break;
1070 case PointingHidType_USBMouse:
1071 pszHid = "USB Mouse";
1072 pszMrHid = "usbmouse";
1073 break;
1074 case PointingHidType_USBTablet:
1075 pszHid = "USB Tablet";
1076 pszMrHid = "usbtablet";
1077 break;
1078 case PointingHidType_ComboMouse:
1079 pszHid = "USB Tablet and PS/2 Mouse";
1080 pszMrHid = "combomouse";
1081 break;
1082 default:
1083 break;
1084 }
1085 if (details == VMINFO_MACHINEREADABLE)
1086 RTPrintf("hidpointing=\"%s\"\n", pszMrHid);
1087 else
1088 RTPrintf("Pointing Device: %s\n", pszHid);
1089
1090 /* Keyboard device information */
1091 KeyboardHidType_T aKeyboardHid;
1092 machine->COMGETTER(KeyboardHidType)(&aKeyboardHid);
1093 pszHid = "Unknown";
1094 pszMrHid = "unknown";
1095 switch (aKeyboardHid)
1096 {
1097 case KeyboardHidType_None:
1098 pszHid = "None";
1099 pszMrHid = "none";
1100 break;
1101 case KeyboardHidType_PS2Keyboard:
1102 pszHid = "PS/2 Keyboard";
1103 pszMrHid = "ps2kbd";
1104 break;
1105 case KeyboardHidType_USBKeyboard:
1106 pszHid = "USB Keyboard";
1107 pszMrHid = "usbkbd";
1108 break;
1109 case KeyboardHidType_ComboKeyboard:
1110 pszHid = "USB and PS/2 Keyboard";
1111 pszMrHid = "combokbd";
1112 break;
1113 default:
1114 break;
1115 }
1116 if (details == VMINFO_MACHINEREADABLE)
1117 RTPrintf("hidkeyboard=\"%s\"\n", pszMrHid);
1118 else
1119 RTPrintf("Keyboard Device: %s\n", pszHid);
1120
1121 /* get the maximum amount of UARTs */
1122 ComPtr<ISystemProperties> sysProps;
1123 virtualBox->COMGETTER(SystemProperties)(sysProps.asOutParam());
1124
1125 ULONG maxUARTs = 0;
1126 sysProps->COMGETTER(SerialPortCount)(&maxUARTs);
1127 for (ULONG currentUART = 0; currentUART < maxUARTs; currentUART++)
1128 {
1129 ComPtr<ISerialPort> uart;
1130 rc = machine->GetSerialPort(currentUART, uart.asOutParam());
1131 if (SUCCEEDED(rc) && uart)
1132 {
1133 BOOL fEnabled;
1134 uart->COMGETTER(Enabled)(&fEnabled);
1135 if (!fEnabled)
1136 {
1137 if (details == VMINFO_MACHINEREADABLE)
1138 RTPrintf("uart%d=\"off\"\n", currentUART + 1);
1139 else
1140 RTPrintf("UART %d: disabled\n", currentUART + 1);
1141 }
1142 else
1143 {
1144 ULONG ulIRQ, ulIOBase;
1145 PortMode_T HostMode;
1146 Bstr path;
1147 BOOL fServer;
1148 uart->COMGETTER(IRQ)(&ulIRQ);
1149 uart->COMGETTER(IOBase)(&ulIOBase);
1150 uart->COMGETTER(Path)(path.asOutParam());
1151 uart->COMGETTER(Server)(&fServer);
1152 uart->COMGETTER(HostMode)(&HostMode);
1153
1154 if (details == VMINFO_MACHINEREADABLE)
1155 RTPrintf("uart%d=\"%#06x,%d\"\n", currentUART + 1,
1156 ulIOBase, ulIRQ);
1157 else
1158 RTPrintf("UART %d: I/O base: %#06x, IRQ: %d",
1159 currentUART + 1, ulIOBase, ulIRQ);
1160 switch (HostMode)
1161 {
1162 default:
1163 case PortMode_Disconnected:
1164 if (details == VMINFO_MACHINEREADABLE)
1165 RTPrintf("uartmode%d=\"disconnected\"\n", currentUART + 1);
1166 else
1167 RTPrintf(", disconnected\n");
1168 break;
1169 case PortMode_RawFile:
1170 if (details == VMINFO_MACHINEREADABLE)
1171 RTPrintf("uartmode%d=\"%lS\"\n", currentUART + 1,
1172 path.raw());
1173 else
1174 RTPrintf(", attached to raw file '%lS'\n",
1175 path.raw());
1176 break;
1177 case PortMode_HostPipe:
1178 if (details == VMINFO_MACHINEREADABLE)
1179 RTPrintf("uartmode%d=\"%s,%lS\"\n", currentUART + 1,
1180 fServer ? "server" : "client", path.raw());
1181 else
1182 RTPrintf(", attached to pipe (%s) '%lS'\n",
1183 fServer ? "server" : "client", path.raw());
1184 break;
1185 case PortMode_HostDevice:
1186 if (details == VMINFO_MACHINEREADABLE)
1187 RTPrintf("uartmode%d=\"%lS\"\n", currentUART + 1,
1188 path.raw());
1189 else
1190 RTPrintf(", attached to device '%lS'\n", path.raw());
1191 break;
1192 }
1193 }
1194 }
1195 }
1196
1197 ComPtr<IAudioAdapter> AudioAdapter;
1198 rc = machine->COMGETTER(AudioAdapter)(AudioAdapter.asOutParam());
1199 if (SUCCEEDED(rc))
1200 {
1201 const char *pszDrv = "Unknown";
1202 const char *pszCtrl = "Unknown";
1203 BOOL fEnabled;
1204 rc = AudioAdapter->COMGETTER(Enabled)(&fEnabled);
1205 if (SUCCEEDED(rc) && fEnabled)
1206 {
1207 AudioDriverType_T enmDrvType;
1208 rc = AudioAdapter->COMGETTER(AudioDriver)(&enmDrvType);
1209 switch (enmDrvType)
1210 {
1211 case AudioDriverType_Null:
1212 if (details == VMINFO_MACHINEREADABLE)
1213 pszDrv = "null";
1214 else
1215 pszDrv = "Null";
1216 break;
1217 case AudioDriverType_WinMM:
1218 if (details == VMINFO_MACHINEREADABLE)
1219 pszDrv = "winmm";
1220 else
1221 pszDrv = "WINMM";
1222 break;
1223 case AudioDriverType_DirectSound:
1224 if (details == VMINFO_MACHINEREADABLE)
1225 pszDrv = "dsound";
1226 else
1227 pszDrv = "DSOUND";
1228 break;
1229 case AudioDriverType_OSS:
1230 if (details == VMINFO_MACHINEREADABLE)
1231 pszDrv = "oss";
1232 else
1233 pszDrv = "OSS";
1234 break;
1235 case AudioDriverType_ALSA:
1236 if (details == VMINFO_MACHINEREADABLE)
1237 pszDrv = "alsa";
1238 else
1239 pszDrv = "ALSA";
1240 break;
1241 case AudioDriverType_Pulse:
1242 if (details == VMINFO_MACHINEREADABLE)
1243 pszDrv = "pulse";
1244 else
1245 pszDrv = "PulseAudio";
1246 break;
1247 case AudioDriverType_CoreAudio:
1248 if (details == VMINFO_MACHINEREADABLE)
1249 pszDrv = "coreaudio";
1250 else
1251 pszDrv = "CoreAudio";
1252 break;
1253 case AudioDriverType_SolAudio:
1254 if (details == VMINFO_MACHINEREADABLE)
1255 pszDrv = "solaudio";
1256 else
1257 pszDrv = "SolAudio";
1258 break;
1259 default:
1260 if (details == VMINFO_MACHINEREADABLE)
1261 pszDrv = "unknown";
1262 break;
1263 }
1264 AudioControllerType_T enmCtrlType;
1265 rc = AudioAdapter->COMGETTER(AudioController)(&enmCtrlType);
1266 switch (enmCtrlType)
1267 {
1268 case AudioControllerType_AC97:
1269 if (details == VMINFO_MACHINEREADABLE)
1270 pszCtrl = "ac97";
1271 else
1272 pszCtrl = "AC97";
1273 break;
1274 case AudioControllerType_SB16:
1275 if (details == VMINFO_MACHINEREADABLE)
1276 pszCtrl = "sb16";
1277 else
1278 pszCtrl = "SB16";
1279 break;
1280 case AudioControllerType_HDA:
1281 if (details == VMINFO_MACHINEREADABLE)
1282 pszCtrl = "hda";
1283 else
1284 pszCtrl = "HDA";
1285 break;
1286 }
1287 }
1288 else
1289 fEnabled = FALSE;
1290 if (details == VMINFO_MACHINEREADABLE)
1291 {
1292 if (fEnabled)
1293 RTPrintf("audio=\"%s\"\n", pszDrv);
1294 else
1295 RTPrintf("audio=\"none\"\n");
1296 }
1297 else
1298 {
1299 RTPrintf("Audio: %s",
1300 fEnabled ? "enabled" : "disabled");
1301 if (fEnabled)
1302 RTPrintf(" (Driver: %s, Controller: %s)",
1303 pszDrv, pszCtrl);
1304 RTPrintf("\n");
1305 }
1306 }
1307
1308 /* Shared clipboard */
1309 {
1310 const char *psz = "Unknown";
1311 ClipboardMode_T enmMode;
1312 rc = machine->COMGETTER(ClipboardMode)(&enmMode);
1313 switch (enmMode)
1314 {
1315 case ClipboardMode_Disabled:
1316 if (details == VMINFO_MACHINEREADABLE)
1317 psz = "disabled";
1318 else
1319 psz = "disabled";
1320 break;
1321 case ClipboardMode_HostToGuest:
1322 if (details == VMINFO_MACHINEREADABLE)
1323 psz = "hosttoguest";
1324 else
1325 psz = "HostToGuest";
1326 break;
1327 case ClipboardMode_GuestToHost:
1328 if (details == VMINFO_MACHINEREADABLE)
1329 psz = "guesttohost";
1330 else
1331 psz = "GuestToHost";
1332 break;
1333 case ClipboardMode_Bidirectional:
1334 if (details == VMINFO_MACHINEREADABLE)
1335 psz = "bidirectional";
1336 else
1337 psz = "Bidirectional";
1338 break;
1339 default:
1340 if (details == VMINFO_MACHINEREADABLE)
1341 psz = "unknown";
1342 break;
1343 }
1344 if (details == VMINFO_MACHINEREADABLE)
1345 RTPrintf("clipboard=\"%s\"\n", psz);
1346 else
1347 RTPrintf("Clipboard Mode: %s\n", psz);
1348 }
1349
1350 if (console)
1351 {
1352 ComPtr<IDisplay> display;
1353 CHECK_ERROR_RET(console, COMGETTER(Display)(display.asOutParam()), rc);
1354 do
1355 {
1356 ULONG xRes, yRes, bpp;
1357 rc = display->GetScreenResolution(0, &xRes, &yRes, &bpp);
1358 if (rc == E_ACCESSDENIED)
1359 break; /* VM not powered up */
1360 if (FAILED(rc))
1361 {
1362 com::ErrorInfo info(display, COM_IIDOF(IDisplay));
1363 GluePrintErrorInfo(info);
1364 return rc;
1365 }
1366 if (details == VMINFO_MACHINEREADABLE)
1367 RTPrintf("VideoMode=\"%d,%d,%d\"\n", xRes, yRes, bpp);
1368 else
1369 RTPrintf("Video mode: %dx%dx%d\n", xRes, yRes, bpp);
1370 }
1371 while (0);
1372 }
1373
1374 /*
1375 * Remote Desktop
1376 */
1377 ComPtr<IVRDEServer> vrdeServer;
1378 rc = machine->COMGETTER(VRDEServer)(vrdeServer.asOutParam());
1379 if (SUCCEEDED(rc) && vrdeServer)
1380 {
1381 BOOL fEnabled = false;
1382 vrdeServer->COMGETTER(Enabled)(&fEnabled);
1383 if (fEnabled)
1384 {
1385 LONG currentPort = -1;
1386 Bstr ports;
1387 vrdeServer->GetVRDEProperty(Bstr("TCP/Ports").raw(), ports.asOutParam());
1388 Bstr address;
1389 vrdeServer->GetVRDEProperty(Bstr("TCP/Address").raw(), address.asOutParam());
1390 BOOL fMultiCon;
1391 vrdeServer->COMGETTER(AllowMultiConnection)(&fMultiCon);
1392 BOOL fReuseCon;
1393 vrdeServer->COMGETTER(ReuseSingleConnection)(&fReuseCon);
1394 Bstr videoChannel;
1395 vrdeServer->GetVRDEProperty(Bstr("VideoChannel/Enabled").raw(), videoChannel.asOutParam());
1396 BOOL fVideoChannel = (videoChannel.compare(Bstr("true"), Bstr::CaseInsensitive)== 0)
1397 || (videoChannel == "1");
1398 Bstr videoChannelQuality;
1399 vrdeServer->GetVRDEProperty(Bstr("VideoChannel/Quality").raw(), videoChannelQuality.asOutParam());
1400 AuthType_T authType;
1401 const char *strAuthType;
1402 vrdeServer->COMGETTER(AuthType)(&authType);
1403 switch (authType)
1404 {
1405 case AuthType_Null:
1406 strAuthType = "null";
1407 break;
1408 case AuthType_External:
1409 strAuthType = "external";
1410 break;
1411 case AuthType_Guest:
1412 strAuthType = "guest";
1413 break;
1414 default:
1415 strAuthType = "unknown";
1416 break;
1417 }
1418 if (console)
1419 {
1420 ComPtr<IVRDEServerInfo> vrdeServerInfo;
1421 CHECK_ERROR_RET(console, COMGETTER(VRDEServerInfo)(vrdeServerInfo.asOutParam()), rc);
1422 rc = vrdeServerInfo->COMGETTER(Port)(&currentPort);
1423 if (rc == E_ACCESSDENIED)
1424 {
1425 currentPort = -1; /* VM not powered up */
1426 }
1427 if (FAILED(rc))
1428 {
1429 com::ErrorInfo info(vrdeServerInfo, COM_IIDOF(IVRDEServerInfo));
1430 GluePrintErrorInfo(info);
1431 return rc;
1432 }
1433 }
1434 if (details == VMINFO_MACHINEREADABLE)
1435 {
1436 RTPrintf("vrde=\"on\"\n");
1437 RTPrintf("vrdeport=%d\n", currentPort);
1438 RTPrintf("vrdeports=\"%lS\"\n", ports.raw());
1439 RTPrintf("vrdeaddress=\"%lS\"\n", address.raw());
1440 RTPrintf("vrdeauthtype=\"%s\"\n", strAuthType);
1441 RTPrintf("vrdemulticon=\"%s\"\n", fMultiCon ? "on" : "off");
1442 RTPrintf("vrdereusecon=\"%s\"\n", fReuseCon ? "on" : "off");
1443 RTPrintf("vrdevideochannel=\"%s\"\n", fVideoChannel ? "on" : "off");
1444 if (fVideoChannel)
1445 RTPrintf("vrdevideochannelquality=\"%lS\"\n", videoChannelQuality.raw());
1446 }
1447 else
1448 {
1449 if (address.isEmpty())
1450 address = "0.0.0.0";
1451 RTPrintf("VRDE: enabled (Address %lS, Ports %lS, MultiConn: %s, ReuseSingleConn: %s, Authentication type: %s)\n", address.raw(), ports.raw(), fMultiCon ? "on" : "off", fReuseCon ? "on" : "off", strAuthType);
1452 if (console && currentPort != -1 && currentPort != 0)
1453 RTPrintf("VRDE port: %d\n", currentPort);
1454 if (fVideoChannel)
1455 RTPrintf("Video redirection: enabled (Quality %lS)\n", videoChannelQuality.raw());
1456 else
1457 RTPrintf("Video redirection: disabled\n");
1458 }
1459 com::SafeArray<BSTR> aProperties;
1460 if (SUCCEEDED(vrdeServer->COMGETTER(VRDEProperties)(ComSafeArrayAsOutParam(aProperties))))
1461 {
1462 unsigned i;
1463 for (i = 0; i < aProperties.size(); ++i)
1464 {
1465 Bstr value;
1466 vrdeServer->GetVRDEProperty(aProperties[i], value.asOutParam());
1467 if (details == VMINFO_MACHINEREADABLE)
1468 {
1469 if (value.isEmpty())
1470 RTPrintf("vrdeproperty[%lS]=<not set>\n", aProperties[i]);
1471 else
1472 RTPrintf("vrdeproperty[%lS]=\"%lS\"\n", aProperties[i], value.raw());
1473 }
1474 else
1475 {
1476 if (value.isEmpty())
1477 RTPrintf("VRDE property: %-10lS = <not set>\n", aProperties[i]);
1478 else
1479 RTPrintf("VRDE property: %-10lS = \"%lS\"\n", aProperties[i], value.raw());
1480 }
1481 }
1482 }
1483 }
1484 else
1485 {
1486 if (details == VMINFO_MACHINEREADABLE)
1487 RTPrintf("vrde=\"off\"\n");
1488 else
1489 RTPrintf("VRDE: disabled\n");
1490 }
1491 }
1492
1493 /*
1494 * USB.
1495 */
1496 ComPtr<IUSBController> USBCtl;
1497 rc = machine->COMGETTER(USBController)(USBCtl.asOutParam());
1498 if (SUCCEEDED(rc))
1499 {
1500 BOOL fEnabled;
1501 rc = USBCtl->COMGETTER(Enabled)(&fEnabled);
1502 if (FAILED(rc))
1503 fEnabled = false;
1504 if (details == VMINFO_MACHINEREADABLE)
1505 RTPrintf("usb=\"%s\"\n", fEnabled ? "on" : "off");
1506 else
1507 RTPrintf("USB: %s\n", fEnabled ? "enabled" : "disabled");
1508
1509 SafeIfaceArray <IUSBDeviceFilter> Coll;
1510 rc = USBCtl->COMGETTER(DeviceFilters)(ComSafeArrayAsOutParam(Coll));
1511 if (SUCCEEDED(rc))
1512 {
1513 if (details != VMINFO_MACHINEREADABLE)
1514 RTPrintf("\nUSB Device Filters:\n\n");
1515
1516 if (Coll.size() == 0)
1517 {
1518 if (details != VMINFO_MACHINEREADABLE)
1519 RTPrintf("<none>\n\n");
1520 }
1521 else
1522 {
1523 for (size_t index = 0; index < Coll.size(); ++index)
1524 {
1525 ComPtr<IUSBDeviceFilter> DevPtr = Coll[index];
1526
1527 /* Query info. */
1528
1529 if (details != VMINFO_MACHINEREADABLE)
1530 RTPrintf("Index: %zu\n", index);
1531
1532 BOOL bActive = FALSE;
1533 CHECK_ERROR_RET(DevPtr, COMGETTER(Active)(&bActive), rc);
1534 if (details == VMINFO_MACHINEREADABLE)
1535 RTPrintf("USBFilterActive%zu=\"%s\"\n", index + 1, bActive ? "on" : "off");
1536 else
1537 RTPrintf("Active: %s\n", bActive ? "yes" : "no");
1538
1539 Bstr bstr;
1540 CHECK_ERROR_RET(DevPtr, COMGETTER(Name)(bstr.asOutParam()), rc);
1541 if (details == VMINFO_MACHINEREADABLE)
1542 RTPrintf("USBFilterName%zu=\"%lS\"\n", index + 1, bstr.raw());
1543 else
1544 RTPrintf("Name: %lS\n", bstr.raw());
1545 CHECK_ERROR_RET(DevPtr, COMGETTER(VendorId)(bstr.asOutParam()), rc);
1546 if (details == VMINFO_MACHINEREADABLE)
1547 RTPrintf("USBFilterVendorId%zu=\"%lS\"\n", index + 1, bstr.raw());
1548 else
1549 RTPrintf("VendorId: %lS\n", bstr.raw());
1550 CHECK_ERROR_RET(DevPtr, COMGETTER(ProductId)(bstr.asOutParam()), rc);
1551 if (details == VMINFO_MACHINEREADABLE)
1552 RTPrintf("USBFilterProductId%zu=\"%lS\"\n", index + 1, bstr.raw());
1553 else
1554 RTPrintf("ProductId: %lS\n", bstr.raw());
1555 CHECK_ERROR_RET(DevPtr, COMGETTER(Revision)(bstr.asOutParam()), rc);
1556 if (details == VMINFO_MACHINEREADABLE)
1557 RTPrintf("USBFilterRevision%zu=\"%lS\"\n", index + 1, bstr.raw());
1558 else
1559 RTPrintf("Revision: %lS\n", bstr.raw());
1560 CHECK_ERROR_RET(DevPtr, COMGETTER(Manufacturer)(bstr.asOutParam()), rc);
1561 if (details == VMINFO_MACHINEREADABLE)
1562 RTPrintf("USBFilterManufacturer%zu=\"%lS\"\n", index + 1, bstr.raw());
1563 else
1564 RTPrintf("Manufacturer: %lS\n", bstr.raw());
1565 CHECK_ERROR_RET(DevPtr, COMGETTER(Product)(bstr.asOutParam()), rc);
1566 if (details == VMINFO_MACHINEREADABLE)
1567 RTPrintf("USBFilterProduct%zu=\"%lS\"\n", index + 1, bstr.raw());
1568 else
1569 RTPrintf("Product: %lS\n", bstr.raw());
1570 CHECK_ERROR_RET(DevPtr, COMGETTER(Remote)(bstr.asOutParam()), rc);
1571 if (details == VMINFO_MACHINEREADABLE)
1572 RTPrintf("USBFilterRemote%zu=\"%lS\"\n", index + 1, bstr.raw());
1573 else
1574 RTPrintf("Remote: %lS\n", bstr.raw());
1575 CHECK_ERROR_RET(DevPtr, COMGETTER(SerialNumber)(bstr.asOutParam()), rc);
1576 if (details == VMINFO_MACHINEREADABLE)
1577 RTPrintf("USBFilterSerialNumber%zu=\"%lS\"\n", index + 1, bstr.raw());
1578 else
1579 RTPrintf("Serial Number: %lS\n", bstr.raw());
1580 if (details != VMINFO_MACHINEREADABLE)
1581 {
1582 ULONG fMaskedIfs;
1583 CHECK_ERROR_RET(DevPtr, COMGETTER(MaskedInterfaces)(&fMaskedIfs), rc);
1584 if (fMaskedIfs)
1585 RTPrintf("Masked Interfaces: %#010x\n", fMaskedIfs);
1586 RTPrintf("\n");
1587 }
1588 }
1589 }
1590 }
1591
1592 if (console)
1593 {
1594 /* scope */
1595 {
1596 if (details != VMINFO_MACHINEREADABLE)
1597 RTPrintf("Available remote USB devices:\n\n");
1598
1599 SafeIfaceArray <IHostUSBDevice> coll;
1600 CHECK_ERROR_RET(console, COMGETTER(RemoteUSBDevices)(ComSafeArrayAsOutParam(coll)), rc);
1601
1602 if (coll.size() == 0)
1603 {
1604 if (details != VMINFO_MACHINEREADABLE)
1605 RTPrintf("<none>\n\n");
1606 }
1607 else
1608 {
1609 for (size_t index = 0; index < coll.size(); ++index)
1610 {
1611 ComPtr <IHostUSBDevice> dev = coll[index];
1612
1613 /* Query info. */
1614 Bstr id;
1615 CHECK_ERROR_RET(dev, COMGETTER(Id)(id.asOutParam()), rc);
1616 USHORT usVendorId;
1617 CHECK_ERROR_RET(dev, COMGETTER(VendorId)(&usVendorId), rc);
1618 USHORT usProductId;
1619 CHECK_ERROR_RET(dev, COMGETTER(ProductId)(&usProductId), rc);
1620 USHORT bcdRevision;
1621 CHECK_ERROR_RET(dev, COMGETTER(Revision)(&bcdRevision), rc);
1622
1623 if (details == VMINFO_MACHINEREADABLE)
1624 RTPrintf("USBRemoteUUID%zu=\"%S\"\n"
1625 "USBRemoteVendorId%zu=\"%#06x\"\n"
1626 "USBRemoteProductId%zu=\"%#06x\"\n"
1627 "USBRemoteRevision%zu=\"%#04x%02x\"\n",
1628 index + 1, Utf8Str(id).c_str(),
1629 index + 1, usVendorId,
1630 index + 1, usProductId,
1631 index + 1, bcdRevision >> 8, bcdRevision & 0xff);
1632 else
1633 RTPrintf("UUID: %S\n"
1634 "VendorId: %#06x (%04X)\n"
1635 "ProductId: %#06x (%04X)\n"
1636 "Revision: %u.%u (%02u%02u)\n",
1637 Utf8Str(id).c_str(),
1638 usVendorId, usVendorId, usProductId, usProductId,
1639 bcdRevision >> 8, bcdRevision & 0xff,
1640 bcdRevision >> 8, bcdRevision & 0xff);
1641
1642 /* optional stuff. */
1643 Bstr bstr;
1644 CHECK_ERROR_RET(dev, COMGETTER(Manufacturer)(bstr.asOutParam()), rc);
1645 if (!bstr.isEmpty())
1646 {
1647 if (details == VMINFO_MACHINEREADABLE)
1648 RTPrintf("USBRemoteManufacturer%zu=\"%lS\"\n", index + 1, bstr.raw());
1649 else
1650 RTPrintf("Manufacturer: %lS\n", bstr.raw());
1651 }
1652 CHECK_ERROR_RET(dev, COMGETTER(Product)(bstr.asOutParam()), rc);
1653 if (!bstr.isEmpty())
1654 {
1655 if (details == VMINFO_MACHINEREADABLE)
1656 RTPrintf("USBRemoteProduct%zu=\"%lS\"\n", index + 1, bstr.raw());
1657 else
1658 RTPrintf("Product: %lS\n", bstr.raw());
1659 }
1660 CHECK_ERROR_RET(dev, COMGETTER(SerialNumber)(bstr.asOutParam()), rc);
1661 if (!bstr.isEmpty())
1662 {
1663 if (details == VMINFO_MACHINEREADABLE)
1664 RTPrintf("USBRemoteSerialNumber%zu=\"%lS\"\n", index + 1, bstr.raw());
1665 else
1666 RTPrintf("SerialNumber: %lS\n", bstr.raw());
1667 }
1668 CHECK_ERROR_RET(dev, COMGETTER(Address)(bstr.asOutParam()), rc);
1669 if (!bstr.isEmpty())
1670 {
1671 if (details == VMINFO_MACHINEREADABLE)
1672 RTPrintf("USBRemoteAddress%zu=\"%lS\"\n", index + 1, bstr.raw());
1673 else
1674 RTPrintf("Address: %lS\n", bstr.raw());
1675 }
1676
1677 if (details != VMINFO_MACHINEREADABLE)
1678 RTPrintf("\n");
1679 }
1680 }
1681 }
1682
1683 /* scope */
1684 {
1685 if (details != VMINFO_MACHINEREADABLE)
1686 RTPrintf("Currently Attached USB Devices:\n\n");
1687
1688 SafeIfaceArray <IUSBDevice> coll;
1689 CHECK_ERROR_RET(console, COMGETTER(USBDevices)(ComSafeArrayAsOutParam(coll)), rc);
1690
1691 if (coll.size() == 0)
1692 {
1693 if (details != VMINFO_MACHINEREADABLE)
1694 RTPrintf("<none>\n\n");
1695 }
1696 else
1697 {
1698 for (size_t index = 0; index < coll.size(); ++index)
1699 {
1700 ComPtr <IUSBDevice> dev = coll[index];
1701
1702 /* Query info. */
1703 Bstr id;
1704 CHECK_ERROR_RET(dev, COMGETTER(Id)(id.asOutParam()), rc);
1705 USHORT usVendorId;
1706 CHECK_ERROR_RET(dev, COMGETTER(VendorId)(&usVendorId), rc);
1707 USHORT usProductId;
1708 CHECK_ERROR_RET(dev, COMGETTER(ProductId)(&usProductId), rc);
1709 USHORT bcdRevision;
1710 CHECK_ERROR_RET(dev, COMGETTER(Revision)(&bcdRevision), rc);
1711
1712 if (details == VMINFO_MACHINEREADABLE)
1713 RTPrintf("USBAttachedUUID%zu=\"%S\"\n"
1714 "USBAttachedVendorId%zu=\"%#06x\"\n"
1715 "USBAttachedProductId%zu=\"%#06x\"\n"
1716 "USBAttachedRevision%zu=\"%#04x%02x\"\n",
1717 index + 1, Utf8Str(id).c_str(),
1718 index + 1, usVendorId,
1719 index + 1, usProductId,
1720 index + 1, bcdRevision >> 8, bcdRevision & 0xff);
1721 else
1722 RTPrintf("UUID: %S\n"
1723 "VendorId: %#06x (%04X)\n"
1724 "ProductId: %#06x (%04X)\n"
1725 "Revision: %u.%u (%02u%02u)\n",
1726 Utf8Str(id).c_str(),
1727 usVendorId, usVendorId, usProductId, usProductId,
1728 bcdRevision >> 8, bcdRevision & 0xff,
1729 bcdRevision >> 8, bcdRevision & 0xff);
1730
1731 /* optional stuff. */
1732 Bstr bstr;
1733 CHECK_ERROR_RET(dev, COMGETTER(Manufacturer)(bstr.asOutParam()), rc);
1734 if (!bstr.isEmpty())
1735 {
1736 if (details == VMINFO_MACHINEREADABLE)
1737 RTPrintf("USBAttachedManufacturer%zu=\"%lS\"\n", index + 1, bstr.raw());
1738 else
1739 RTPrintf("Manufacturer: %lS\n", bstr.raw());
1740 }
1741 CHECK_ERROR_RET(dev, COMGETTER(Product)(bstr.asOutParam()), rc);
1742 if (!bstr.isEmpty())
1743 {
1744 if (details == VMINFO_MACHINEREADABLE)
1745 RTPrintf("USBAttachedProduct%zu=\"%lS\"\n", index + 1, bstr.raw());
1746 else
1747 RTPrintf("Product: %lS\n", bstr.raw());
1748 }
1749 CHECK_ERROR_RET(dev, COMGETTER(SerialNumber)(bstr.asOutParam()), rc);
1750 if (!bstr.isEmpty())
1751 {
1752 if (details == VMINFO_MACHINEREADABLE)
1753 RTPrintf("USBAttachedSerialNumber%zu=\"%lS\"\n", index + 1, bstr.raw());
1754 else
1755 RTPrintf("SerialNumber: %lS\n", bstr.raw());
1756 }
1757 CHECK_ERROR_RET(dev, COMGETTER(Address)(bstr.asOutParam()), rc);
1758 if (!bstr.isEmpty())
1759 {
1760 if (details == VMINFO_MACHINEREADABLE)
1761 RTPrintf("USBAttachedAddress%zu=\"%lS\"\n", index + 1, bstr.raw());
1762 else
1763 RTPrintf("Address: %lS\n", bstr.raw());
1764 }
1765
1766 if (details != VMINFO_MACHINEREADABLE)
1767 RTPrintf("\n");
1768 }
1769 }
1770 }
1771 }
1772 } /* USB */
1773
1774 /*
1775 * Shared folders
1776 */
1777 if (details != VMINFO_MACHINEREADABLE)
1778 RTPrintf("Shared folders: ");
1779 uint32_t numSharedFolders = 0;
1780#if 0 // not yet implemented
1781 /* globally shared folders first */
1782 {
1783 SafeIfaceArray <ISharedFolder> sfColl;
1784 CHECK_ERROR_RET(virtualBox, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(sfColl)), rc);
1785 for (size_t i = 0; i < sfColl.size(); ++i)
1786 {
1787 ComPtr<ISharedFolder> sf = sfColl[i];
1788 Bstr name, hostPath;
1789 sf->COMGETTER(Name)(name.asOutParam());
1790 sf->COMGETTER(HostPath)(hostPath.asOutParam());
1791 RTPrintf("Name: '%lS', Host path: '%lS' (global mapping)\n", name.raw(), hostPath.raw());
1792 ++numSharedFolders;
1793 }
1794 }
1795#endif
1796 /* now VM mappings */
1797 {
1798 com::SafeIfaceArray <ISharedFolder> folders;
1799
1800 CHECK_ERROR_RET(machine, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(folders)), rc);
1801
1802 for (size_t i = 0; i < folders.size(); ++i)
1803 {
1804 ComPtr <ISharedFolder> sf = folders[i];
1805
1806 Bstr name, hostPath;
1807 BOOL writable;
1808 sf->COMGETTER(Name)(name.asOutParam());
1809 sf->COMGETTER(HostPath)(hostPath.asOutParam());
1810 sf->COMGETTER(Writable)(&writable);
1811 if (!numSharedFolders && details != VMINFO_MACHINEREADABLE)
1812 RTPrintf("\n\n");
1813 if (details == VMINFO_MACHINEREADABLE)
1814 {
1815 RTPrintf("SharedFolderNameMachineMapping%zu=\"%lS\"\n", i + 1,
1816 name.raw());
1817 RTPrintf("SharedFolderPathMachineMapping%zu=\"%lS\"\n", i + 1,
1818 hostPath.raw());
1819 }
1820 else
1821 RTPrintf("Name: '%lS', Host path: '%lS' (machine mapping), %s\n",
1822 name.raw(), hostPath.raw(), writable ? "writable" : "readonly");
1823 ++numSharedFolders;
1824 }
1825 }
1826 /* transient mappings */
1827 if (console)
1828 {
1829 com::SafeIfaceArray <ISharedFolder> folders;
1830
1831 CHECK_ERROR_RET(console, COMGETTER(SharedFolders)(ComSafeArrayAsOutParam(folders)), rc);
1832
1833 for (size_t i = 0; i < folders.size(); ++i)
1834 {
1835 ComPtr <ISharedFolder> sf = folders[i];
1836
1837 Bstr name, hostPath;
1838 sf->COMGETTER(Name)(name.asOutParam());
1839 sf->COMGETTER(HostPath)(hostPath.asOutParam());
1840 if (!numSharedFolders && details != VMINFO_MACHINEREADABLE)
1841 RTPrintf("\n\n");
1842 if (details == VMINFO_MACHINEREADABLE)
1843 {
1844 RTPrintf("SharedFolderNameTransientMapping%zu=\"%lS\"\n", i + 1,
1845 name.raw());
1846 RTPrintf("SharedFolderPathTransientMapping%zu=\"%lS\"\n", i + 1,
1847 hostPath.raw());
1848 }
1849 else
1850 RTPrintf("Name: '%lS', Host path: '%lS' (transient mapping)\n", name.raw(), hostPath.raw());
1851 ++numSharedFolders;
1852 }
1853 }
1854 if (!numSharedFolders && details != VMINFO_MACHINEREADABLE)
1855 RTPrintf("<none>\n");
1856 if (details != VMINFO_MACHINEREADABLE)
1857 RTPrintf("\n");
1858
1859 if (console)
1860 {
1861 /*
1862 * Live VRDE info.
1863 */
1864 ComPtr<IVRDEServerInfo> vrdeServerInfo;
1865 CHECK_ERROR_RET(console, COMGETTER(VRDEServerInfo)(vrdeServerInfo.asOutParam()), rc);
1866 BOOL Active;
1867 ULONG NumberOfClients;
1868 LONG64 BeginTime;
1869 LONG64 EndTime;
1870 LONG64 BytesSent;
1871 LONG64 BytesSentTotal;
1872 LONG64 BytesReceived;
1873 LONG64 BytesReceivedTotal;
1874 Bstr User;
1875 Bstr Domain;
1876 Bstr ClientName;
1877 Bstr ClientIP;
1878 ULONG ClientVersion;
1879 ULONG EncryptionStyle;
1880
1881 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(Active)(&Active), rc);
1882 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(NumberOfClients)(&NumberOfClients), rc);
1883 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BeginTime)(&BeginTime), rc);
1884 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(EndTime)(&EndTime), rc);
1885 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesSent)(&BytesSent), rc);
1886 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesSentTotal)(&BytesSentTotal), rc);
1887 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesReceived)(&BytesReceived), rc);
1888 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(BytesReceivedTotal)(&BytesReceivedTotal), rc);
1889 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(User)(User.asOutParam()), rc);
1890 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(Domain)(Domain.asOutParam()), rc);
1891 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(ClientName)(ClientName.asOutParam()), rc);
1892 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(ClientIP)(ClientIP.asOutParam()), rc);
1893 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(ClientVersion)(&ClientVersion), rc);
1894 CHECK_ERROR_RET(vrdeServerInfo, COMGETTER(EncryptionStyle)(&EncryptionStyle), rc);
1895
1896 if (details == VMINFO_MACHINEREADABLE)
1897 RTPrintf("VRDEActiveConnection=\"%s\"\n", Active ? "on": "off");
1898 else
1899 RTPrintf("VRDE Connection: %s\n", Active? "active": "not active");
1900
1901 if (details == VMINFO_MACHINEREADABLE)
1902 RTPrintf("VRDEClients=%d\n", NumberOfClients);
1903 else
1904 RTPrintf("Clients so far: %d\n", NumberOfClients);
1905
1906 if (NumberOfClients > 0)
1907 {
1908 char timestr[128];
1909
1910 if (Active)
1911 {
1912 makeTimeStr(timestr, sizeof(timestr), BeginTime);
1913 if (details == VMINFO_MACHINEREADABLE)
1914 RTPrintf("VRDEStartTime=\"%s\"\n", timestr);
1915 else
1916 RTPrintf("Start time: %s\n", timestr);
1917 }
1918 else
1919 {
1920 makeTimeStr(timestr, sizeof(timestr), BeginTime);
1921 if (details == VMINFO_MACHINEREADABLE)
1922 RTPrintf("VRDELastStartTime=\"%s\"\n", timestr);
1923 else
1924 RTPrintf("Last started: %s\n", timestr);
1925 makeTimeStr(timestr, sizeof(timestr), EndTime);
1926 if (details == VMINFO_MACHINEREADABLE)
1927 RTPrintf("VRDELastEndTime=\"%s\"\n", timestr);
1928 else
1929 RTPrintf("Last ended: %s\n", timestr);
1930 }
1931
1932 int64_t ThroughputSend = 0;
1933 int64_t ThroughputReceive = 0;
1934 if (EndTime != BeginTime)
1935 {
1936 ThroughputSend = (BytesSent * 1000) / (EndTime - BeginTime);
1937 ThroughputReceive = (BytesReceived * 1000) / (EndTime - BeginTime);
1938 }
1939
1940 if (details == VMINFO_MACHINEREADABLE)
1941 {
1942 RTPrintf("VRDEBytesSent=%lld\n", BytesSent);
1943 RTPrintf("VRDEThroughputSend=%lld\n", ThroughputSend);
1944 RTPrintf("VRDEBytesSentTotal=%lld\n", BytesSentTotal);
1945
1946 RTPrintf("VRDEBytesReceived=%lld\n", BytesReceived);
1947 RTPrintf("VRDEThroughputReceive=%lld\n", ThroughputReceive);
1948 RTPrintf("VRDEBytesReceivedTotal=%lld\n", BytesReceivedTotal);
1949 }
1950 else
1951 {
1952 RTPrintf("Sent: %lld Bytes\n", BytesSent);
1953 RTPrintf("Average speed: %lld B/s\n", ThroughputSend);
1954 RTPrintf("Sent total: %lld Bytes\n", BytesSentTotal);
1955
1956 RTPrintf("Received: %lld Bytes\n", BytesReceived);
1957 RTPrintf("Speed: %lld B/s\n", ThroughputReceive);
1958 RTPrintf("Received total: %lld Bytes\n", BytesReceivedTotal);
1959 }
1960
1961 if (Active)
1962 {
1963 if (details == VMINFO_MACHINEREADABLE)
1964 {
1965 RTPrintf("VRDEUserName=\"%lS\"\n", User.raw());
1966 RTPrintf("VRDEDomain=\"%lS\"\n", Domain.raw());
1967 RTPrintf("VRDEClientName=\"%lS\"\n", ClientName.raw());
1968 RTPrintf("VRDEClientIP=\"%lS\"\n", ClientIP.raw());
1969 RTPrintf("VRDEClientVersion=%d\n", ClientVersion);
1970 RTPrintf("VRDEEncryption=\"%s\"\n", EncryptionStyle == 0? "RDP4": "RDP5 (X.509)");
1971 }
1972 else
1973 {
1974 RTPrintf("User name: %lS\n", User.raw());
1975 RTPrintf("Domain: %lS\n", Domain.raw());
1976 RTPrintf("Client name: %lS\n", ClientName.raw());
1977 RTPrintf("Client IP: %lS\n", ClientIP.raw());
1978 RTPrintf("Client version: %d\n", ClientVersion);
1979 RTPrintf("Encryption: %s\n", EncryptionStyle == 0? "RDP4": "RDP5 (X.509)");
1980 }
1981 }
1982 }
1983
1984 if (details != VMINFO_MACHINEREADABLE)
1985 RTPrintf("\n");
1986 }
1987
1988 if ( details == VMINFO_STANDARD
1989 || details == VMINFO_FULL
1990 || details == VMINFO_MACHINEREADABLE)
1991 {
1992 Bstr description;
1993 machine->COMGETTER(Description)(description.asOutParam());
1994 if (!description.isEmpty())
1995 {
1996 if (details == VMINFO_MACHINEREADABLE)
1997 RTPrintf("description=\"%lS\"\n", description.raw());
1998 else
1999 RTPrintf("Description:\n%lS\n", description.raw());
2000 }
2001 }
2002
2003
2004 if (details != VMINFO_MACHINEREADABLE)
2005 RTPrintf("Guest:\n\n");
2006
2007 if (console)
2008 {
2009 ComPtr<IGuest> guest;
2010 rc = console->COMGETTER(Guest)(guest.asOutParam());
2011 if (SUCCEEDED(rc))
2012 {
2013 Bstr guestString;
2014 rc = guest->COMGETTER(OSTypeId)(guestString.asOutParam());
2015 if ( SUCCEEDED(rc)
2016 && !guestString.isEmpty())
2017 {
2018 if (details == VMINFO_MACHINEREADABLE)
2019 RTPrintf("GuestOSType=\"%lS\"\n", guestString.raw());
2020 else
2021 RTPrintf("OS type: %lS\n", guestString.raw());
2022 }
2023
2024 AdditionsRunLevelType_T guestRunLevel; /** @todo Add a runlevel-to-string (e.g. 0 = "None") method? */
2025 rc = guest->COMGETTER(AdditionsRunLevel)(&guestRunLevel);
2026 if (SUCCEEDED(rc))
2027 {
2028 if (details == VMINFO_MACHINEREADABLE)
2029 RTPrintf("GuestAdditionsRunLevel=%u\n", guestRunLevel);
2030 else
2031 RTPrintf("Additions run level: %u\n", guestRunLevel);
2032 }
2033
2034 if (details == VMINFO_FULL)
2035 {
2036 rc = guest->COMGETTER(AdditionsVersion)(guestString.asOutParam());
2037 if ( SUCCEEDED(rc)
2038 && !guestString.isEmpty())
2039 {
2040 if (details == VMINFO_MACHINEREADABLE)
2041 RTPrintf("GuestAdditionsVersion=\"%lS\"\n", guestString.raw());
2042 else
2043 RTPrintf("Additions version: %lS\n\n", guestString.raw());
2044 }
2045 }
2046 }
2047 }
2048
2049 ULONG guestVal;
2050 rc = machine->COMGETTER(MemoryBalloonSize)(&guestVal);
2051 if (SUCCEEDED(rc))
2052 {
2053 if (details == VMINFO_MACHINEREADABLE)
2054 RTPrintf("GuestMemoryBalloon=%d\n", guestVal);
2055 else
2056 RTPrintf("Configured memory balloon size: %d MB\n", guestVal);
2057 }
2058 if (details != VMINFO_MACHINEREADABLE)
2059 RTPrintf("\n");
2060
2061 /*
2062 * snapshots
2063 */
2064 ComPtr<ISnapshot> snapshot;
2065 rc = machine->FindSnapshot(Bstr().raw(), snapshot.asOutParam());
2066 if (SUCCEEDED(rc) && snapshot)
2067 {
2068 ComPtr<ISnapshot> currentSnapshot;
2069 rc = machine->COMGETTER(CurrentSnapshot)(currentSnapshot.asOutParam());
2070 if (SUCCEEDED(rc))
2071 {
2072 if (details != VMINFO_MACHINEREADABLE)
2073 RTPrintf("Snapshots:\n\n");
2074 showSnapshots(snapshot, currentSnapshot, details);
2075 }
2076 }
2077
2078 if (details != VMINFO_MACHINEREADABLE)
2079 RTPrintf("\n");
2080 return S_OK;
2081}
2082
2083#if defined(_MSC_VER)
2084# pragma optimize("", on)
2085#endif
2086
2087static const RTGETOPTDEF g_aShowVMInfoOptions[] =
2088{
2089 { "--details", 'D', RTGETOPT_REQ_NOTHING },
2090 { "-details", 'D', RTGETOPT_REQ_NOTHING }, // deprecated
2091 { "--machinereadable", 'M', RTGETOPT_REQ_NOTHING },
2092 { "-machinereadable", 'M', RTGETOPT_REQ_NOTHING }, // deprecated
2093 { "--log", 'l', RTGETOPT_REQ_UINT32 },
2094};
2095
2096int handleShowVMInfo(HandlerArg *a)
2097{
2098 HRESULT rc;
2099 const char *VMNameOrUuid = NULL;
2100 bool fLog = false;
2101 uint32_t uLogIdx = 0;
2102 bool fDetails = false;
2103 bool fMachinereadable = false;
2104
2105 int c;
2106 RTGETOPTUNION ValueUnion;
2107 RTGETOPTSTATE GetState;
2108 // start at 0 because main() has hacked both the argc and argv given to us
2109 RTGetOptInit(&GetState, a->argc, a->argv, g_aShowVMInfoOptions, RT_ELEMENTS(g_aShowVMInfoOptions),
2110 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
2111 while ((c = RTGetOpt(&GetState, &ValueUnion)))
2112 {
2113 switch (c)
2114 {
2115 case 'D': // --details
2116 fDetails = true;
2117 break;
2118
2119 case 'M': // --machinereadable
2120 fMachinereadable = true;
2121 break;
2122
2123 case 'l': // --log
2124 fLog = true;
2125 uLogIdx = ValueUnion.u32;
2126 break;
2127
2128 case VINF_GETOPT_NOT_OPTION:
2129 if (!VMNameOrUuid)
2130 VMNameOrUuid = ValueUnion.psz;
2131 else
2132 return errorSyntax(USAGE_SHOWVMINFO, "Invalid parameter '%s'", ValueUnion.psz);
2133 break;
2134
2135 default:
2136 if (c > 0)
2137 {
2138 if (RT_C_IS_PRINT(c))
2139 return errorSyntax(USAGE_SHOWVMINFO, "Invalid option -%c", c);
2140 else
2141 return errorSyntax(USAGE_SHOWVMINFO, "Invalid option case %i", c);
2142 }
2143 else if (c == VERR_GETOPT_UNKNOWN_OPTION)
2144 return errorSyntax(USAGE_SHOWVMINFO, "unknown option: %s\n", ValueUnion.psz);
2145 else if (ValueUnion.pDef)
2146 return errorSyntax(USAGE_SHOWVMINFO, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
2147 else
2148 return errorSyntax(USAGE_SHOWVMINFO, "error: %Rrs", c);
2149 }
2150 }
2151
2152 /* check for required options */
2153 if (!VMNameOrUuid)
2154 return errorSyntax(USAGE_SHOWVMINFO, "VM name or UUID required");
2155
2156 /* try to find the given machine */
2157 ComPtr <IMachine> machine;
2158 CHECK_ERROR(a->virtualBox, FindMachine(Bstr(VMNameOrUuid).raw(),
2159 machine.asOutParam()));
2160 if (FAILED(rc))
2161 return 1;
2162
2163 /* Printing the log is exclusive. */
2164 if (fLog && (fMachinereadable || fDetails))
2165 return errorSyntax(USAGE_SHOWVMINFO, "Option --log is exclusive");
2166
2167 if (fLog)
2168 {
2169 ULONG64 uOffset = 0;
2170 SafeArray<BYTE> aLogData;
2171 ULONG cbLogData;
2172 while (true)
2173 {
2174 /* Reset the array */
2175 aLogData.setNull();
2176 /* Fetch a chunk of the log file */
2177 CHECK_ERROR_BREAK(machine, ReadLog(uLogIdx, uOffset, _1M,
2178 ComSafeArrayAsOutParam(aLogData)));
2179 cbLogData = aLogData.size();
2180 if (cbLogData == 0)
2181 break;
2182 /* aLogData has a platform dependent line ending, standardize on
2183 * Unix style, as RTStrmWrite does the LF -> CR/LF replacement on
2184 * Windows. Otherwise we end up with CR/CR/LF on Windows. */
2185 ULONG cbLogDataPrint = cbLogData;
2186 for (BYTE *s = aLogData.raw(), *d = s;
2187 s - aLogData.raw() < (ssize_t)cbLogData;
2188 s++, d++)
2189 {
2190 if (*s == '\r')
2191 {
2192 /* skip over CR, adjust destination */
2193 d--;
2194 cbLogDataPrint--;
2195 }
2196 else if (s != d)
2197 *d = *s;
2198 }
2199 RTStrmWrite(g_pStdOut, aLogData.raw(), cbLogDataPrint);
2200 uOffset += cbLogData;
2201 }
2202 }
2203 else
2204 {
2205 /* 2nd option can be -details or -argdump */
2206 VMINFO_DETAILS details = VMINFO_NONE;
2207 if (fMachinereadable)
2208 details = VMINFO_MACHINEREADABLE;
2209 else if (fDetails)
2210 details = VMINFO_FULL;
2211 else
2212 details = VMINFO_STANDARD;
2213
2214 ComPtr<IConsole> console;
2215
2216 /* open an existing session for the VM */
2217 rc = machine->LockMachine(a->session, LockType_Shared);
2218 if (SUCCEEDED(rc))
2219 /* get the session machine */
2220 rc = a->session->COMGETTER(Machine)(machine.asOutParam());
2221 if (SUCCEEDED(rc))
2222 /* get the session console */
2223 rc = a->session->COMGETTER(Console)(console.asOutParam());
2224
2225 rc = showVMInfo(a->virtualBox, machine, details, console);
2226
2227 if (console)
2228 a->session->UnlockMachine();
2229 }
2230
2231 return SUCCEEDED(rc) ? 0 : 1;
2232}
2233
2234#endif /* !VBOX_ONLY_DOCS */
2235/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

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