VirtualBox

source: vbox/trunk/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp@ 65456

最後變更 在這個檔案從65456是 65456,由 vboxsync 提交於 8 年 前

BugReportTool: windows driver store and network registry (bugref:8169)

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 25.4 KB
 
1/* $Id: VBoxBugReport.cpp 65456 2017-01-26 15:14:27Z vboxsync $ */
2/** @file
3 * VBoxBugReport - VirtualBox command-line diagnostics tool, main file.
4 */
5
6/*
7 * Copyright (C) 2006-2016 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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
19#include <VBox/com/com.h>
20#include <VBox/com/string.h>
21#include <VBox/com/array.h>
22//#include <VBox/com/Guid.h>
23#include <VBox/com/ErrorInfo.h>
24#include <VBox/com/errorprint.h>
25#include <VBox/com/VirtualBox.h>
26
27#include <VBox/version.h>
28
29#include <iprt/buildconfig.h>
30#include <iprt/env.h>
31#include <iprt/file.h>
32#include <iprt/getopt.h>
33#include <iprt/initterm.h>
34#include <iprt/path.h>
35#include <iprt/process.h>
36#include <iprt/zip.h>
37#include <iprt/cpp/exception.h>
38
39#include <list>
40
41#include "VBoxBugReport.h"
42
43/* Implementation - Base */
44
45#ifndef RT_OS_WINDOWS
46/** @todo Replace with platform-specific implementations. */
47void createBugReportOsSpecific(BugReport *pReport, const char *pszHome)
48{
49 RT_NOREF(pReport, pszHome);
50}
51#endif /* !RT_OS_WINDOWS */
52
53
54/* Globals */
55
56static char *g_pszVBoxManage = NULL;
57
58static const RTGETOPTDEF g_aOptions[] =
59{
60 { "-all", 'A', RTGETOPT_REQ_NOTHING },
61 { "--all", 'A', RTGETOPT_REQ_NOTHING },
62 { "-output", 'o', RTGETOPT_REQ_STRING },
63 { "--output", 'o', RTGETOPT_REQ_STRING },
64 { "-text", 't', RTGETOPT_REQ_NOTHING },
65 { "--text", 't', RTGETOPT_REQ_NOTHING }
66};
67
68static const char g_szUsage[] =
69 "Usage: %s [-h|-?|--help] [-A|--all|<vmname>...] [-o <file>|--output=<file>]\n"
70 " Several VM names can be specified at once to be included into single report.\n"
71 " If none is given then no machines will be included. Specifying -A overrides\n"
72 " any VM names provided and included all registered machines.\n"
73 "Options:\n"
74 " -h, -help, --help Print usage information\n"
75 " -A, -all, --all Include all registered machines\n"
76 " -o, -output, --output Specifies the name of the output file\n"
77 " -t, -text, --text Produce a single text file instead of compressed TAR\n"
78 " -V, -version, --version Print version number and exit\n"
79 "\n";
80
81
82/*
83 * This class stores machine-specific file paths that are obtained via
84 * VirtualBox API. In case API is not functioning properly these paths
85 * will be deduced on the best effort basis.
86 */
87class MachineInfo
88{
89public:
90 MachineInfo(const char *name, const char *logFolder, const char *settingsFile);
91 ~MachineInfo();
92 const char *getName() const { return m_name; };
93 const char *getLogPath() const { return m_logpath; };
94 const char *getSettingsFile() const { return m_settings; };
95private:
96 char *m_name;
97 char *m_logpath;
98 char *m_settings;
99};
100
101MachineInfo::MachineInfo(const char *name, const char *logFolder, const char *settingsFile)
102{
103 m_name = RTStrDup(name);
104 m_logpath = RTStrDup(logFolder);
105 m_settings = RTStrDup(settingsFile);
106}
107
108MachineInfo::~MachineInfo()
109{
110 RTStrFree(m_logpath);
111 RTStrFree(m_name);
112 RTStrFree(m_settings);
113 m_logpath = m_name = m_settings = 0;
114}
115
116typedef std::list<MachineInfo*> MachineInfoList;
117
118
119class VBRDir
120{
121public:
122 VBRDir(const char *pcszPath)
123 {
124 int rc = RTDirOpenFiltered(&m_pDir, pcszPath, RTDIRFILTER_WINNT, 0);
125 if (RT_FAILURE(rc))
126 throw RTCError(com::Utf8StrFmt("Failed to open directory '%s'\n", pcszPath));
127 };
128 ~VBRDir()
129 {
130 int rc = RTDirClose(m_pDir);
131 AssertRC(rc);
132 };
133 const char *next(void)
134 {
135 int rc = RTDirRead(m_pDir, &m_DirEntry, NULL);
136 if (RT_SUCCESS(rc))
137 return m_DirEntry.szName;
138 else if (rc == VERR_NO_MORE_FILES)
139 return NULL;
140 throw RTCError("Failed to read directory element\n");
141 };
142
143private:
144 PRTDIR m_pDir;
145 RTDIRENTRY m_DirEntry;
146};
147
148/*
149 * An abstract class serving as the root of the bug report item tree.
150 */
151BugReportItem::BugReportItem(const char *pszTitle)
152{
153 m_pszTitle = RTStrDup(pszTitle);
154}
155
156BugReportItem::~BugReportItem()
157{
158 RTStrFree(m_pszTitle);
159}
160
161const char * BugReportItem::getTitle(void)
162{
163 return m_pszTitle;
164}
165
166
167BugReport::BugReport(const char *pszFileName)
168{
169 m_pszFileName = RTStrDup(pszFileName);
170}
171
172BugReport::~BugReport()
173{
174 for (unsigned i = 0; i < m_Items.size(); ++i)
175 {
176 delete m_Items[i];
177 }
178 RTStrFree(m_pszFileName);
179}
180
181int BugReport::getItemCount(void)
182{
183 return (int)m_Items.size();
184}
185
186void BugReport::addItem(BugReportItem* item)
187{
188 if (item)
189 m_Items.append(item);
190}
191
192void BugReport::process(void)
193{
194 for (unsigned i = 0; i < m_Items.size(); ++i)
195 {
196 BugReportItem *pItem = m_Items[i];
197 RTPrintf("%3u%% - collecting %s...\n", i * 100 / m_Items.size(), pItem->getTitle());
198 processItem(pItem);
199 }
200 RTPrintf("100%% - compressing...\n\n");
201}
202
203
204BugReportStream::BugReportStream(const char *pszTitle) : BugReportItem(pszTitle)
205{
206 handleRtError(RTPathTemp(m_szFileName, RTPATH_MAX),
207 "Failed to obtain path to temporary folder");
208 handleRtError(RTPathAppend(m_szFileName, RTPATH_MAX, "BugRepXXXXX.tmp"),
209 "Failed to append path");
210 handleRtError(RTFileCreateTemp(m_szFileName, 0600),
211 "Failed to create temporary file '%s'", m_szFileName);
212 handleRtError(RTStrmOpen(m_szFileName, "w", &m_Strm),
213 "Failed to open '%s'", m_szFileName);
214}
215
216BugReportStream::~BugReportStream()
217{
218 if (m_Strm)
219 RTStrmClose(m_Strm);
220 RTFileDelete(m_szFileName);
221}
222
223int BugReportStream::printf(const char *pszFmt, ...)
224{
225 va_list va;
226 va_start(va, pszFmt);
227 int cb = RTStrmPrintfV(m_Strm, pszFmt, va);
228 va_end(va);
229 return cb;
230}
231
232int BugReportStream::putStr(const char *pszString)
233{
234 return RTStrmPutStr(m_Strm, pszString);
235}
236
237PRTSTREAM BugReportStream::getStream(void)
238{
239 RTStrmClose(m_Strm);
240 handleRtError(RTStrmOpen(m_szFileName, "r", &m_Strm),
241 "Failed to open '%s'", m_szFileName);
242 return m_Strm;
243}
244
245
246/* Implementation - Generic */
247
248BugReportFile::BugReportFile(const char *pszPath, const char *pszShortName) : BugReportItem(pszShortName)
249{
250 m_Strm = 0;
251 m_pszPath = RTStrDup(pszPath);
252}
253
254BugReportFile::~BugReportFile()
255{
256 if (m_Strm)
257 RTStrmClose(m_Strm);
258 if (m_pszPath)
259 RTStrFree(m_pszPath);
260}
261
262PRTSTREAM BugReportFile::getStream(void)
263{
264 handleRtError(RTStrmOpen(m_pszPath, "rb", &m_Strm),
265 "Failed to open '%s'", m_pszPath);
266 return m_Strm;
267}
268
269
270BugReportCommand::BugReportCommand(const char *pszTitle, const char *pszExec, ...)
271 : BugReportItem(pszTitle), m_Strm(NULL)
272{
273 unsigned cArgs = 0;
274 m_papszArgs[cArgs++] = RTStrDup(pszExec);
275
276 const char *pszArg;
277 va_list va;
278 va_start(va, pszExec);
279 do
280 {
281 if (cArgs >= RT_ELEMENTS(m_papszArgs))
282 {
283 va_end(va);
284 throw RTCError(com::Utf8StrFmt("Too many arguments (%u > %u)\n", cArgs+1, RT_ELEMENTS(m_papszArgs)));
285 }
286 pszArg = va_arg(va, const char *);
287 m_papszArgs[cArgs++] = pszArg ? RTStrDup(pszArg) : NULL;
288 } while (pszArg);
289 va_end(va);
290}
291
292BugReportCommand::~BugReportCommand()
293{
294 if (m_Strm)
295 RTStrmClose(m_Strm);
296 RTFileDelete(m_szFileName);
297 for (size_t i = 0; i < RT_ELEMENTS(m_papszArgs) && m_papszArgs[i]; ++i)
298 RTStrFree(m_papszArgs[i]);
299}
300
301PRTSTREAM BugReportCommand::getStream(void)
302{
303 handleRtError(RTPathTemp(m_szFileName, RTPATH_MAX),
304 "Failed to obtain path to temporary folder");
305 handleRtError(RTPathAppend(m_szFileName, RTPATH_MAX, "BugRepXXXXX.tmp"),
306 "Failed to append path");
307 handleRtError(RTFileCreateTemp(m_szFileName, 0600),
308 "Failed to create temporary file '%s'", m_szFileName);
309
310 RTHANDLE hStdOutErr;
311 hStdOutErr.enmType = RTHANDLETYPE_FILE;
312 handleRtError(RTFileOpen(&hStdOutErr.u.hFile, m_szFileName,
313 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE),
314 "Failed to open temporary file '%s'", m_szFileName);
315
316 RTPROCESS hProcess;
317 handleRtError(RTProcCreateEx(m_papszArgs[0], m_papszArgs, RTENV_DEFAULT, 0,
318 NULL, &hStdOutErr, &hStdOutErr,
319 NULL, NULL, &hProcess),
320 "Failed to create process '%s'", m_papszArgs[0]);
321 RTPROCSTATUS status;
322 handleRtError(RTProcWait(hProcess, RTPROCWAIT_FLAGS_BLOCK, &status),
323 "Process wait failed");
324 //if (status.enmReason == RTPROCEXITREASON_NORMAL) {}
325 RTFileClose(hStdOutErr.u.hFile);
326
327 handleRtError(RTStrmOpen(m_szFileName, "r", &m_Strm),
328 "Failed to open '%s'", m_szFileName);
329 return m_Strm;
330}
331
332
333BugReportCommandTemp::BugReportCommandTemp(const char *pszTitle, const char *pszExec, ...)
334 : BugReportItem(pszTitle), m_Strm(NULL)
335{
336 handleRtError(RTPathTemp(m_szFileName, RTPATH_MAX),
337 "Failed to obtain path to temporary folder");
338 handleRtError(RTPathAppend(m_szFileName, RTPATH_MAX, "BugRepXXXXX.tmp"),
339 "Failed to append path");
340 handleRtError(RTFileCreateTemp(m_szFileName, 0600),
341 "Failed to create temporary file '%s'", m_szFileName);
342
343 unsigned cArgs = 0;
344 m_papszArgs[cArgs++] = RTStrDup(pszExec);
345
346 const char *pszArg;
347 va_list va;
348 va_start(va, pszExec);
349 do
350 {
351 if (cArgs >= RT_ELEMENTS(m_papszArgs) - 1)
352 {
353 va_end(va);
354 throw RTCError(com::Utf8StrFmt("Too many arguments (%u > %u)\n", cArgs+1, RT_ELEMENTS(m_papszArgs)));
355 }
356 pszArg = va_arg(va, const char *);
357 m_papszArgs[cArgs++] = RTStrDup(pszArg ? pszArg : m_szFileName);
358 } while (pszArg);
359 va_end(va);
360
361 m_papszArgs[cArgs++] = NULL;
362}
363
364BugReportCommandTemp::~BugReportCommandTemp()
365{
366 if (m_Strm)
367 RTStrmClose(m_Strm);
368 RTFileDelete(m_szErrFileName);
369 RTFileDelete(m_szFileName);
370 for (size_t i = 0; i < RT_ELEMENTS(m_papszArgs) && m_papszArgs[i]; ++i)
371 RTStrFree(m_papszArgs[i]);
372}
373
374PRTSTREAM BugReportCommandTemp::getStream(void)
375{
376 handleRtError(RTPathTemp(m_szErrFileName, RTPATH_MAX),
377 "Failed to obtain path to temporary folder");
378 handleRtError(RTPathAppend(m_szErrFileName, RTPATH_MAX, "BugRepErrXXXXX.tmp"),
379 "Failed to append path");
380 handleRtError(RTFileCreateTemp(m_szErrFileName, 0600),
381 "Failed to create temporary file '%s'", m_szErrFileName);
382
383 RTHANDLE hStdOutErr;
384 hStdOutErr.enmType = RTHANDLETYPE_FILE;
385 handleRtError(RTFileOpen(&hStdOutErr.u.hFile, m_szErrFileName,
386 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE),
387 "Failed to open temporary file '%s'", m_szErrFileName);
388
389 /* Remove the output file to prevent errors or confirmation prompts */
390 handleRtError(RTFileDelete(m_szFileName),
391 "Failed to delete temporary file '%s'", m_szFileName);
392
393 RTPROCESS hProcess;
394 handleRtError(RTProcCreateEx(m_papszArgs[0], m_papszArgs, RTENV_DEFAULT, 0,
395 NULL, &hStdOutErr, &hStdOutErr,
396 NULL, NULL, &hProcess),
397 "Failed to create process '%s'", m_papszArgs[0]);
398 RTPROCSTATUS status;
399 handleRtError(RTProcWait(hProcess, RTPROCWAIT_FLAGS_BLOCK, &status),
400 "Process wait failed");
401 RTFileClose(hStdOutErr.u.hFile);
402
403 if (status.enmReason == RTPROCEXITREASON_NORMAL && status.iStatus == 0)
404 handleRtError(RTStrmOpen(m_szFileName, "r", &m_Strm), "Failed to open '%s'", m_szFileName);
405 else
406 handleRtError(RTStrmOpen(m_szErrFileName, "r", &m_Strm), "Failed to open '%s'", m_szErrFileName);
407 return m_Strm;
408}
409
410
411BugReportText::BugReportText(const char *pszFileName) : BugReport(pszFileName)
412{
413 handleRtError(RTStrmOpen(pszFileName, "w", &m_StrmTxt),
414 "Failed to open '%s'", pszFileName);
415}
416
417BugReportText::~BugReportText()
418{
419 if (m_StrmTxt)
420 RTStrmClose(m_StrmTxt);
421}
422
423void BugReportText::processItem(BugReportItem* item)
424{
425 int cb = RTStrmPrintf(m_StrmTxt, "[ %s ] -------------------------------------------\n", item->getTitle());
426 if (!cb)
427 throw RTCError(com::Utf8StrFmt("Write failure (cb=%d)\n", cb));
428
429 PRTSTREAM strmIn = NULL;
430 try
431 {
432 strmIn = item->getStream();
433 }
434 catch (RTCError &e)
435 {
436 strmIn = NULL;
437 RTStrmPutStr(m_StrmTxt, e.what());
438 }
439
440 int rc = VINF_SUCCESS;
441
442 if (strmIn)
443 {
444 char buf[64*1024];
445 size_t cbRead, cbWritten;
446 cbRead = cbWritten = 0;
447 while (RT_SUCCESS(rc = RTStrmReadEx(strmIn, buf, sizeof(buf), &cbRead)) && cbRead)
448 {
449 rc = RTStrmWriteEx(m_StrmTxt, buf, cbRead, &cbWritten);
450 if (RT_FAILURE(rc) || cbRead != cbWritten)
451 throw RTCError(com::Utf8StrFmt("Write failure (rc=%d, cbRead=%lu, cbWritten=%lu)\n",
452 rc, cbRead, cbWritten));
453 }
454 }
455
456 handleRtError(RTStrmPutCh(m_StrmTxt, '\n'), "Write failure");
457}
458
459
460BugReportTarGzip::BugReportTarGzip(const char *pszFileName)
461 : BugReport(pszFileName), m_hTar(NIL_RTTAR), m_hTarFile(NIL_RTTARFILE)
462{
463 VfsIoStreamHandle hVfsOut;
464 handleRtError(RTVfsIoStrmOpenNormal(pszFileName, RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE,
465 hVfsOut.getPtr()),
466 "Failed to create output file '%s'", pszFileName);
467 handleRtError(RTZipGzipCompressIoStream(hVfsOut.get(), 0, 6, m_hVfsGzip.getPtr()),
468 "Failed to create compressed stream for '%s'", pszFileName);
469
470 handleRtError(RTPathTemp(m_szTarName, RTPATH_MAX),
471 "Failed to obtain path to temporary folder");
472 handleRtError(RTPathAppend(m_szTarName, RTPATH_MAX, "BugRepXXXXX.tar"),
473 "Failed to append path");
474 handleRtError(RTFileCreateTemp(m_szTarName, 0600),
475 "Failed to create temporary file '%s'", m_szTarName);
476 handleRtError(RTFileDelete(m_szTarName),
477 "Failed to delete temporary file '%s'", m_szTarName);
478 handleRtError(RTTarOpen(&m_hTar, m_szTarName, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL),
479 "Failed to create TAR file '%s'", m_szTarName);
480
481}
482
483BugReportTarGzip::~BugReportTarGzip()
484{
485 if (m_hTarFile != NIL_RTTARFILE)
486 RTTarFileClose(m_hTarFile);
487 if (m_hTar != NIL_RTTAR)
488 RTTarClose(m_hTar);
489}
490
491void BugReportTarGzip::processItem(BugReportItem* item)
492{
493 /*
494 * @todo Our TAR implementation does not support names larger than 100 characters.
495 * We truncate the title to make sure it will fit into 100-character field of TAR header.
496 */
497 RTCString strTarFile = RTCString(item->getTitle()).substr(0, RTStrNLen(item->getTitle(), 99));
498 handleRtError(RTTarFileOpen(m_hTar, &m_hTarFile, strTarFile.c_str(),
499 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE),
500 "Failed to open '%s' in TAR", strTarFile.c_str());
501
502 PRTSTREAM strmIn = NULL;
503 try
504 {
505 strmIn = item->getStream();
506 }
507 catch (RTCError &e)
508 {
509 strmIn = NULL;
510 handleRtError(RTTarFileWriteAt(m_hTarFile, 0, e.what(), RTStrNLen(e.what(), 1024), NULL),
511 "Failed to write %u bytes to TAR", RTStrNLen(e.what(), 1024));
512 }
513
514 int rc = VINF_SUCCESS;
515
516 if (strmIn)
517 {
518 char buf[64*1024];
519 size_t cbRead = 0;
520 for (uint64_t offset = 0;
521 RT_SUCCESS(rc = RTStrmReadEx(strmIn, buf, sizeof(buf), &cbRead)) && cbRead;
522 offset += cbRead)
523 {
524 handleRtError(RTTarFileWriteAt(m_hTarFile, offset, buf, cbRead, NULL),
525 "Failed to write %u bytes to TAR", cbRead);
526 }
527 }
528
529 if (m_hTarFile)
530 {
531 handleRtError(RTTarFileClose(m_hTarFile), "Failed to close '%s' in TAR", strTarFile.c_str());
532 m_hTarFile = NIL_RTTARFILE;
533 }
534}
535
536void BugReportTarGzip::complete(void)
537{
538 if (m_hTarFile != NIL_RTTARFILE)
539 {
540 RTTarFileClose(m_hTarFile);
541 m_hTarFile = NIL_RTTARFILE;
542 }
543 if (m_hTar != NIL_RTTAR)
544 {
545 RTTarClose(m_hTar);
546 m_hTar = NIL_RTTAR;
547 }
548
549 VfsIoStreamHandle hVfsIn;
550 handleRtError(RTVfsIoStrmOpenNormal(m_szTarName, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
551 hVfsIn.getPtr()),
552 "Failed to open TAR file '%s'", m_szTarName);
553
554 int rc;
555 char buf[_64K];
556 size_t cbRead = 0;
557 while (RT_SUCCESS(rc = RTVfsIoStrmRead(hVfsIn.get(), buf, sizeof(buf), true, &cbRead)) && cbRead)
558 handleRtError(RTVfsIoStrmWrite(m_hVfsGzip.get(), buf, cbRead, true, NULL),
559 "Failed to write into compressed stream");
560 handleRtError(rc, "Failed to read from TAR stream");
561 handleRtError(RTVfsIoStrmFlush(m_hVfsGzip.get()), "Failed to flush output stream");
562 m_hVfsGzip.release();
563}
564
565
566/* Implementation - Main */
567
568void createBugReport(BugReport* report, const char *pszHome, MachineInfoList& machines)
569{
570 /* Collect all log files from VBoxSVC */
571 VBRDir HomeDir(PathJoin(pszHome, "VBoxSVC.log*"));
572 const char *pcszSvcLogFile = HomeDir.next();
573 while (pcszSvcLogFile)
574 {
575 report->addItem(new BugReportFile(PathJoin(pszHome, pcszSvcLogFile), pcszSvcLogFile));
576 pcszSvcLogFile = HomeDir.next();
577 }
578
579 report->addItem(new BugReportFile(PathJoin(pszHome, "VirtualBox.xml"), "VirtualBox.xml"));
580 report->addItem(new BugReportCommand("HostUsbDevices", g_pszVBoxManage, "list", "usbhost", NULL));
581 report->addItem(new BugReportCommand("HostUsbFilters", g_pszVBoxManage, "list", "usbfilters", NULL));
582 for (MachineInfoList::iterator it = machines.begin(); it != machines.end(); ++it)
583 {
584 VBRDir VmDir(PathJoin((*it)->getLogPath(), "VBox.log*"));
585 const char *pcszVmLogFile = HomeDir.next();
586 while (pcszVmLogFile)
587 {
588 report->addItem(new BugReportFile(PathJoin((*it)->getLogPath(), pcszVmLogFile),
589 PathJoin((*it)->getName(), pcszVmLogFile)));
590 pcszVmLogFile = HomeDir.next();
591 }
592 report->addItem(new BugReportFile((*it)->getSettingsFile(),
593 PathJoin((*it)->getName(), RTPathFilename((*it)->getSettingsFile()))));
594 report->addItem(new BugReportCommand(PathJoin((*it)->getName(), "GuestProperties"),
595 g_pszVBoxManage, "guestproperty", "enumerate",
596 (*it)->getName(), NULL));
597 }
598
599 createBugReportOsSpecific(report, pszHome);
600}
601
602void addMachine(MachineInfoList& list, ComPtr<IMachine> machine)
603{
604 com::Bstr name, logFolder, settingsFile;
605 handleComError(machine->COMGETTER(Name)(name.asOutParam()),
606 "Failed to get VM name");
607 handleComError(machine->COMGETTER(LogFolder)(logFolder.asOutParam()),
608 "Failed to get VM log folder");
609 handleComError(machine->COMGETTER(SettingsFilePath)(settingsFile.asOutParam()),
610 "Failed to get VM settings file path");
611 list.push_back(new MachineInfo(com::Utf8Str(name).c_str(),
612 com::Utf8Str(logFolder).c_str(),
613 com::Utf8Str(settingsFile).c_str()));
614}
615
616
617static void printHeader(void)
618{
619 RTStrmPrintf(g_pStdErr, VBOX_PRODUCT " Bug Report Tool " VBOX_VERSION_STRING "\n"
620 "(C) " VBOX_C_YEAR " " VBOX_VENDOR "\n"
621 "All rights reserved.\n\n");
622}
623
624int main(int argc, char *argv[])
625{
626 /*
627 * Initialize the VBox runtime without loading
628 * the support driver.
629 */
630 RTR3InitExe(argc, &argv, 0);
631
632 bool fAllMachines = false;
633 bool fTextOutput = false;
634 const char *pszOutputFile = NULL;
635 std::list<const char *> nameList;
636 RTGETOPTUNION ValueUnion;
637 RTGETOPTSTATE GetState;
638 int ret = RTGetOptInit(&GetState, argc, argv,
639 g_aOptions, RT_ELEMENTS(g_aOptions),
640 1 /* First */, 0 /*fFlags*/);
641 if (RT_FAILURE(ret))
642 return ret;
643 int ch;
644 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
645 {
646 switch(ch)
647 {
648 case 'h':
649 printHeader();
650 RTStrmPrintf(g_pStdErr, g_szUsage, argv[0]);
651 return 0;
652 case 'A':
653 fAllMachines = true;
654 break;
655 case 'o':
656 pszOutputFile = ValueUnion.psz;
657 break;
658 case 't':
659 fTextOutput = true;
660 break;
661 case 'V':
662 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
663 return 0;
664 case VINF_GETOPT_NOT_OPTION:
665 nameList.push_back(ValueUnion.psz);
666 break;
667 default:
668 return RTGetOptPrintError(ch, &ValueUnion);
669 }
670 }
671
672 printHeader();
673
674 HRESULT hr = S_OK;
675 char homeDir[RTPATH_MAX];
676 com::GetVBoxUserHomeDirectory(homeDir, sizeof(homeDir));
677
678 try
679 {
680 /* Figure out the full path to VBoxManage */
681 char szVBoxBin[RTPATH_MAX];
682 if (!RTProcGetExecutablePath(szVBoxBin, sizeof(szVBoxBin)))
683 throw RTCError("RTProcGetExecutablePath failed\n");
684 RTPathStripFilename(szVBoxBin);
685 g_pszVBoxManage = RTPathJoinA(szVBoxBin, VBOXMANAGE);
686 if (!g_pszVBoxManage)
687 throw RTCError("Out of memory\n");
688
689 handleComError(com::Initialize(), "Failed to initialize COM");
690
691 MachineInfoList list;
692
693 do
694 {
695 ComPtr<IVirtualBoxClient> virtualBoxClient;
696 ComPtr<IVirtualBox> virtualBox;
697 ComPtr<ISession> session;
698
699 hr = virtualBoxClient.createLocalObject(CLSID_VirtualBoxClient);
700 if (SUCCEEDED(hr))
701 hr = virtualBoxClient->COMGETTER(VirtualBox)(virtualBox.asOutParam());
702 else
703 hr = virtualBox.createLocalObject(CLSID_VirtualBox);
704 if (FAILED(hr))
705 RTStrmPrintf(g_pStdErr, "WARNING: Failed to create the VirtualBox object (hr=0x%x)\n", hr);
706 else
707 {
708 hr = session.createInprocObject(CLSID_Session);
709 if (FAILED(hr))
710 RTStrmPrintf(g_pStdErr, "WARNING: Failed to create a session object (hr=0x%x)\n", hr);
711 }
712
713 if (SUCCEEDED(hr))
714 {
715 if (fAllMachines)
716 {
717 com::SafeIfaceArray<IMachine> machines;
718 hr = virtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
719 if (SUCCEEDED(hr))
720 {
721 for (size_t i = 0; i < machines.size(); ++i)
722 {
723 if (machines[i])
724 addMachine(list, machines[i]);
725 }
726 }
727 }
728 else
729 {
730 for ( std::list<const char *>::iterator it = nameList.begin(); it != nameList.end(); ++it)
731 {
732 ComPtr<IMachine> machine;
733 handleComError(virtualBox->FindMachine(com::Bstr(*it).raw(), machine.asOutParam()),
734 "No such machine '%s'", *it);
735 addMachine(list, machine);
736 }
737 }
738 }
739
740 }
741 while(0);
742
743 RTTIMESPEC TimeSpec;
744 RTTIME Time;
745 RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
746 RTCStringFmt strOutFile("%04d-%02d-%02d-%02d-%02d-%02d-bugreport.%s",
747 Time.i32Year, Time.u8Month, Time.u8MonthDay,
748 Time.u8Hour, Time.u8Minute, Time.u8Second,
749 fTextOutput ? "txt" : "tgz");
750 RTCString strFallbackOutFile;
751 if (!pszOutputFile)
752 {
753 RTFILE tmp;
754 pszOutputFile = strOutFile.c_str();
755 int rc = RTFileOpen(&tmp, pszOutputFile, RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
756 if (rc == VERR_ACCESS_DENIED)
757 {
758 char szUserHome[RTPATH_MAX];
759 handleRtError(RTPathUserHome(szUserHome, sizeof(szUserHome)), "Failed to obtain home directory");
760 strFallbackOutFile.printf("%s/%s", szUserHome, strOutFile.c_str());
761 pszOutputFile = strFallbackOutFile.c_str();
762 }
763 else if (RT_SUCCESS(rc))
764 {
765 RTFileClose(tmp);
766 RTFileDelete(pszOutputFile);
767 }
768 }
769 BugReport *pReport;
770 if (fTextOutput)
771 pReport = new BugReportText(pszOutputFile);
772 else
773 pReport = new BugReportTarGzip(pszOutputFile);
774 createBugReport(pReport, homeDir, list);
775 pReport->process();
776 pReport->complete();
777 RTPrintf("Report was written to '%s'\n", pszOutputFile);
778 delete pReport;
779 }
780 catch (RTCError &e)
781 {
782 RTStrmPrintf(g_pStdErr, "ERROR: %s\n", e.what());
783 }
784
785 com::Shutdown();
786
787 if (g_pszVBoxManage)
788 RTStrFree(g_pszVBoxManage);
789
790 return SUCCEEDED(hr) ? 0 : 1;
791}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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