VirtualBox

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

Last change on this file since 63384 was 63384, checked in by vboxsync, 8 years ago

Frontends: warnings (gcc)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.2 KB
Line 
1/* $Id: VBoxBugReport.cpp 63384 2016-08-12 18:57:52Z 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.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
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
119/*
120 * An abstract class serving as the root of the bug report item tree.
121 */
122BugReportItem::BugReportItem(const char *pszTitle)
123{
124 m_pszTitle = RTStrDup(pszTitle);
125}
126
127BugReportItem::~BugReportItem()
128{
129 RTStrFree(m_pszTitle);
130}
131
132const char * BugReportItem::getTitle(void)
133{
134 return m_pszTitle;
135}
136
137
138BugReport::BugReport(const char *pszFileName)
139{
140 m_pszFileName = RTStrDup(pszFileName);
141}
142
143BugReport::~BugReport()
144{
145 for (unsigned i = 0; i < m_Items.size(); ++i)
146 {
147 delete m_Items[i];
148 }
149 RTStrFree(m_pszFileName);
150}
151
152int BugReport::getItemCount(void)
153{
154 return (int)m_Items.size();
155}
156
157void BugReport::addItem(BugReportItem* item)
158{
159 if (item)
160 m_Items.append(item);
161}
162
163void BugReport::process(void)
164{
165 for (unsigned i = 0; i < m_Items.size(); ++i)
166 {
167 BugReportItem *pItem = m_Items[i];
168 RTPrintf("%3u%% - collecting %s...\n", i * 100 / m_Items.size(), pItem->getTitle());
169 processItem(pItem);
170 }
171 RTPrintf("100%% - compressing...\n\n");
172}
173
174
175BugReportStream::BugReportStream(const char *pszTitle) : BugReportItem(pszTitle)
176{
177 handleRtError(RTPathTemp(m_szFileName, RTPATH_MAX),
178 "Failed to obtain path to temporary folder");
179 handleRtError(RTPathAppend(m_szFileName, RTPATH_MAX, "BugRepXXXXX.tmp"),
180 "Failed to append path");
181 handleRtError(RTFileCreateTemp(m_szFileName, 0600),
182 "Failed to create temporary file '%s'", m_szFileName);
183 handleRtError(RTStrmOpen(m_szFileName, "w", &m_Strm),
184 "Failed to open '%s'", m_szFileName);
185}
186
187BugReportStream::~BugReportStream()
188{
189 if (m_Strm)
190 RTStrmClose(m_Strm);
191 RTFileDelete(m_szFileName);
192}
193
194int BugReportStream::printf(const char *pszFmt, ...)
195{
196 va_list va;
197 va_start(va, pszFmt);
198 int cb = RTStrmPrintfV(m_Strm, pszFmt, va);
199 va_end(va);
200 return cb;
201}
202
203int BugReportStream::putStr(const char *pszString)
204{
205 return RTStrmPutStr(m_Strm, pszString);
206}
207
208PRTSTREAM BugReportStream::getStream(void)
209{
210 RTStrmClose(m_Strm);
211 handleRtError(RTStrmOpen(m_szFileName, "r", &m_Strm),
212 "Failed to open '%s'", m_szFileName);
213 return m_Strm;
214}
215
216
217/* Implementation - Generic */
218
219BugReportFile::BugReportFile(const char *pszPath, const char *pszShortName) : BugReportItem(pszShortName)
220{
221 m_Strm = 0;
222 m_pszPath = RTStrDup(pszPath);
223}
224
225BugReportFile::~BugReportFile()
226{
227 if (m_Strm)
228 RTStrmClose(m_Strm);
229 if (m_pszPath)
230 RTStrFree(m_pszPath);
231}
232
233PRTSTREAM BugReportFile::getStream(void)
234{
235 handleRtError(RTStrmOpen(m_pszPath, "rb", &m_Strm),
236 "Failed to open '%s'", m_pszPath);
237 return m_Strm;
238}
239
240
241BugReportCommand::BugReportCommand(const char *pszTitle, const char *pszExec, ...)
242 : BugReportItem(pszTitle), m_Strm(NULL)
243{
244 unsigned cArgs = 0;
245 m_papszArgs[cArgs++] = RTStrDup(pszExec);
246
247 const char *pszArg;
248 va_list va;
249 va_start(va, pszExec);
250 do
251 {
252 if (cArgs >= RT_ELEMENTS(m_papszArgs))
253 {
254 va_end(va);
255 throw RTCError(com::Utf8StrFmt("Too many arguments (%u > %u)\n", cArgs+1, RT_ELEMENTS(m_papszArgs)));
256 }
257 pszArg = va_arg(va, const char *);
258 m_papszArgs[cArgs++] = pszArg ? RTStrDup(pszArg) : NULL;
259 } while (pszArg);
260 va_end(va);
261}
262
263BugReportCommand::~BugReportCommand()
264{
265 if (m_Strm)
266 RTStrmClose(m_Strm);
267 RTFileDelete(m_szFileName);
268 for (size_t i = 0; i < RT_ELEMENTS(m_papszArgs) && m_papszArgs[i]; ++i)
269 RTStrFree(m_papszArgs[i]);
270}
271
272PRTSTREAM BugReportCommand::getStream(void)
273{
274 handleRtError(RTPathTemp(m_szFileName, RTPATH_MAX),
275 "Failed to obtain path to temporary folder");
276 handleRtError(RTPathAppend(m_szFileName, RTPATH_MAX, "BugRepXXXXX.tmp"),
277 "Failed to append path");
278 handleRtError(RTFileCreateTemp(m_szFileName, 0600),
279 "Failed to create temporary file '%s'", m_szFileName);
280
281 RTHANDLE hStdOutErr;
282 hStdOutErr.enmType = RTHANDLETYPE_FILE;
283 handleRtError(RTFileOpen(&hStdOutErr.u.hFile, m_szFileName,
284 RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_WRITE),
285 "Failed to open temporary file '%s'", m_szFileName);
286
287 RTPROCESS hProcess;
288 handleRtError(RTProcCreateEx(m_papszArgs[0], m_papszArgs, RTENV_DEFAULT, 0,
289 NULL, &hStdOutErr, &hStdOutErr,
290 NULL, NULL, &hProcess),
291 "Failed to create process '%s'", m_papszArgs[0]);
292 RTPROCSTATUS status;
293 handleRtError(RTProcWait(hProcess, RTPROCWAIT_FLAGS_BLOCK, &status),
294 "Process wait failed");
295 //if (status.enmReason == RTPROCEXITREASON_NORMAL) {}
296 RTFileClose(hStdOutErr.u.hFile);
297
298 handleRtError(RTStrmOpen(m_szFileName, "r", &m_Strm),
299 "Failed to open '%s'", m_szFileName);
300 return m_Strm;
301}
302
303
304BugReportText::BugReportText(const char *pszFileName) : BugReport(pszFileName)
305{
306 handleRtError(RTStrmOpen(pszFileName, "w", &m_StrmTxt),
307 "Failed to open '%s'", pszFileName);
308}
309
310BugReportText::~BugReportText()
311{
312 if (m_StrmTxt)
313 RTStrmClose(m_StrmTxt);
314}
315
316void BugReportText::processItem(BugReportItem* item)
317{
318 int cb = RTStrmPrintf(m_StrmTxt, "[ %s ] -------------------------------------------\n", item->getTitle());
319 if (!cb)
320 throw RTCError(com::Utf8StrFmt("Write failure (cb=%d)\n", cb));
321
322 PRTSTREAM strmIn = NULL;
323 try
324 {
325 strmIn = item->getStream();
326 }
327 catch (RTCError &e)
328 {
329 strmIn = NULL;
330 RTStrmPutStr(m_StrmTxt, e.what());
331 }
332
333 int rc = VINF_SUCCESS;
334
335 if (strmIn)
336 {
337 char buf[64*1024];
338 size_t cbRead, cbWritten;
339 cbRead = cbWritten = 0;
340 while (RT_SUCCESS(rc = RTStrmReadEx(strmIn, buf, sizeof(buf), &cbRead)) && cbRead)
341 {
342 rc = RTStrmWriteEx(m_StrmTxt, buf, cbRead, &cbWritten);
343 if (RT_FAILURE(rc) || cbRead != cbWritten)
344 throw RTCError(com::Utf8StrFmt("Write failure (rc=%d, cbRead=%lu, cbWritten=%lu)\n",
345 rc, cbRead, cbWritten));
346 }
347 }
348
349 handleRtError(RTStrmPutCh(m_StrmTxt, '\n'), "Write failure");
350}
351
352
353BugReportTarGzip::BugReportTarGzip(const char *pszFileName)
354 : BugReport(pszFileName), m_hTar(NIL_RTTAR), m_hTarFile(NIL_RTTARFILE)
355{
356 VfsIoStreamHandle hVfsOut;
357 handleRtError(RTVfsIoStrmOpenNormal(pszFileName, RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE,
358 hVfsOut.getPtr()),
359 "Failed to create output file '%s'", pszFileName);
360 handleRtError(RTZipGzipCompressIoStream(hVfsOut.get(), 0, 6, m_hVfsGzip.getPtr()),
361 "Failed to create compressed stream for '%s'", pszFileName);
362
363 handleRtError(RTPathTemp(m_szTarName, RTPATH_MAX),
364 "Failed to obtain path to temporary folder");
365 handleRtError(RTPathAppend(m_szTarName, RTPATH_MAX, "BugRepXXXXX.tar"),
366 "Failed to append path");
367 handleRtError(RTFileCreateTemp(m_szTarName, 0600),
368 "Failed to create temporary file '%s'", m_szTarName);
369 handleRtError(RTFileDelete(m_szTarName),
370 "Failed to delete temporary file '%s'", m_szTarName);
371 handleRtError(RTTarOpen(&m_hTar, m_szTarName, RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_ALL),
372 "Failed to create TAR file '%s'", m_szTarName);
373
374}
375
376BugReportTarGzip::~BugReportTarGzip()
377{
378 if (m_hTarFile != NIL_RTTARFILE)
379 RTTarFileClose(m_hTarFile);
380 if (m_hTar != NIL_RTTAR)
381 RTTarClose(m_hTar);
382}
383
384void BugReportTarGzip::processItem(BugReportItem* item)
385{
386 /*
387 * @todo Our TAR implementation does not support names larger than 100 characters.
388 * We truncate the title to make sure it will fit into 100-character field of TAR header.
389 */
390 RTCString strTarFile = RTCString(item->getTitle()).substr(0, RTStrNLen(item->getTitle(), 99));
391 handleRtError(RTTarFileOpen(m_hTar, &m_hTarFile, strTarFile.c_str(),
392 RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE),
393 "Failed to open '%s' in TAR", strTarFile.c_str());
394
395 PRTSTREAM strmIn = NULL;
396 try
397 {
398 strmIn = item->getStream();
399 }
400 catch (RTCError &e)
401 {
402 strmIn = NULL;
403 handleRtError(RTTarFileWriteAt(m_hTarFile, 0, e.what(), RTStrNLen(e.what(), 1024), NULL),
404 "Failed to write %u bytes to TAR", RTStrNLen(e.what(), 1024));
405 }
406
407 int rc = VINF_SUCCESS;
408
409 if (strmIn)
410 {
411 char buf[64*1024];
412 size_t cbRead = 0;
413 for (uint64_t offset = 0;
414 RT_SUCCESS(rc = RTStrmReadEx(strmIn, buf, sizeof(buf), &cbRead)) && cbRead;
415 offset += cbRead)
416 {
417 handleRtError(RTTarFileWriteAt(m_hTarFile, offset, buf, cbRead, NULL),
418 "Failed to write %u bytes to TAR", cbRead);
419 }
420 }
421
422 if (m_hTarFile)
423 {
424 handleRtError(RTTarFileClose(m_hTarFile), "Failed to close '%s' in TAR", strTarFile.c_str());
425 m_hTarFile = NIL_RTTARFILE;
426 }
427}
428
429void BugReportTarGzip::complete(void)
430{
431 if (m_hTarFile != NIL_RTTARFILE)
432 {
433 RTTarFileClose(m_hTarFile);
434 m_hTarFile = NIL_RTTARFILE;
435 }
436 if (m_hTar != NIL_RTTAR)
437 {
438 RTTarClose(m_hTar);
439 m_hTar = NIL_RTTAR;
440 }
441
442 VfsIoStreamHandle hVfsIn;
443 handleRtError(RTVfsIoStrmOpenNormal(m_szTarName, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE,
444 hVfsIn.getPtr()),
445 "Failed to open TAR file '%s'", m_szTarName);
446
447 int rc;
448 char buf[_64K];
449 size_t cbRead = 0;
450 while (RT_SUCCESS(rc = RTVfsIoStrmRead(hVfsIn.get(), buf, sizeof(buf), true, &cbRead)) && cbRead)
451 handleRtError(RTVfsIoStrmWrite(m_hVfsGzip.get(), buf, cbRead, true, NULL),
452 "Failed to write into compressed stream");
453 handleRtError(rc, "Failed to read from TAR stream");
454 handleRtError(RTVfsIoStrmFlush(m_hVfsGzip.get()), "Failed to flush output stream");
455 m_hVfsGzip.release();
456}
457
458
459/* Implementation - Main */
460
461void createBugReport(BugReport* report, const char *pszHome, MachineInfoList& machines)
462{
463 report->addItem(new BugReportFile(PathJoin(pszHome, "VBoxSVC.log"), "VBoxSVC.log"));
464 report->addItem(new BugReportFile(PathJoin(pszHome, "VBoxSVC.log.1"), "VBoxSVC.log.1"));
465 report->addItem(new BugReportFile(PathJoin(pszHome, "VirtualBox.xml"), "VirtualBox.xml"));
466 report->addItem(new BugReportCommand("HostUsbDevices", g_pszVBoxManage, "list", "usbhost", NULL));
467 report->addItem(new BugReportCommand("HostUsbFilters", g_pszVBoxManage, "list", "usbfilters", NULL));
468 for (MachineInfoList::iterator it = machines.begin(); it != machines.end(); ++it)
469 {
470 report->addItem(new BugReportFile(PathJoin((*it)->getLogPath(), "VBox.log"),
471 PathJoin((*it)->getName(), "VBox.log")));
472 report->addItem(new BugReportFile((*it)->getSettingsFile(),
473 PathJoin((*it)->getName(), RTPathFilename((*it)->getSettingsFile()))));
474 report->addItem(new BugReportCommand(PathJoin((*it)->getName(), "GuestProperties"),
475 g_pszVBoxManage, "guestproperty", "enumerate",
476 (*it)->getName(), NULL));
477 }
478
479 createBugReportOsSpecific(report, pszHome);
480}
481
482void addMachine(MachineInfoList& list, ComPtr<IMachine> machine)
483{
484 com::Bstr name, logFolder, settingsFile;
485 handleComError(machine->COMGETTER(Name)(name.asOutParam()),
486 "Failed to get VM name");
487 handleComError(machine->COMGETTER(LogFolder)(logFolder.asOutParam()),
488 "Failed to get VM log folder");
489 handleComError(machine->COMGETTER(SettingsFilePath)(settingsFile.asOutParam()),
490 "Failed to get VM settings file path");
491 list.push_back(new MachineInfo(com::Utf8Str(name).c_str(),
492 com::Utf8Str(logFolder).c_str(),
493 com::Utf8Str(settingsFile).c_str()));
494}
495
496
497static void printHeader(void)
498{
499 RTStrmPrintf(g_pStdErr, VBOX_PRODUCT " Bug Report Tool " VBOX_VERSION_STRING "\n"
500 "(C) " VBOX_C_YEAR " " VBOX_VENDOR "\n"
501 "All rights reserved.\n\n");
502}
503
504int main(int argc, char *argv[])
505{
506 /*
507 * Initialize the VBox runtime without loading
508 * the support driver.
509 */
510 RTR3InitExe(argc, &argv, 0);
511
512 bool fAllMachines = false;
513 bool fTextOutput = false;
514 const char *pszOutputFile = NULL;
515 std::list<const char *> nameList;
516 RTGETOPTUNION ValueUnion;
517 RTGETOPTSTATE GetState;
518 int ret = RTGetOptInit(&GetState, argc, argv,
519 g_aOptions, RT_ELEMENTS(g_aOptions),
520 1 /* First */, 0 /*fFlags*/);
521 if (RT_FAILURE(ret))
522 return ret;
523 int ch;
524 while ((ch = RTGetOpt(&GetState, &ValueUnion)))
525 {
526 switch(ch)
527 {
528 case 'h':
529 printHeader();
530 RTStrmPrintf(g_pStdErr, g_szUsage, argv[0]);
531 return 0;
532 case 'A':
533 fAllMachines = true;
534 break;
535 case 'o':
536 pszOutputFile = ValueUnion.psz;
537 break;
538 case 't':
539 fTextOutput = true;
540 break;
541 case 'V':
542 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
543 return 0;
544 case VINF_GETOPT_NOT_OPTION:
545 nameList.push_back(ValueUnion.psz);
546 break;
547 default:
548 return RTGetOptPrintError(ch, &ValueUnion);
549 }
550 }
551
552 printHeader();
553
554 HRESULT hr = S_OK;
555 char homeDir[RTPATH_MAX];
556 com::GetVBoxUserHomeDirectory(homeDir, sizeof(homeDir));
557
558 try
559 {
560 /* Figure out full path to VBoxManage */
561 char *pszVBoxBin = RTStrDup(argv[0]);
562 if (!pszVBoxBin)
563 throw RTCError("Out of memory\n");
564 RTPathStripFilename(pszVBoxBin);
565 g_pszVBoxManage = RTPathJoinA(pszVBoxBin, VBOXMANAGE);
566 if (!g_pszVBoxManage)
567 throw RTCError("Out of memory\n");
568 RTStrFree(pszVBoxBin);
569
570 handleComError(com::Initialize(), "Failed to initialize COM");
571
572 MachineInfoList list;
573
574 do
575 {
576 ComPtr<IVirtualBoxClient> virtualBoxClient;
577 ComPtr<IVirtualBox> virtualBox;
578 ComPtr<ISession> session;
579
580 hr = virtualBoxClient.createLocalObject(CLSID_VirtualBoxClient);
581 if (SUCCEEDED(hr))
582 hr = virtualBoxClient->COMGETTER(VirtualBox)(virtualBox.asOutParam());
583 if (FAILED(hr))
584 RTStrmPrintf(g_pStdErr, "WARNING: Failed to create the VirtualBox object (hr=0x%x)\n", hr);
585 else
586 {
587 hr = session.createInprocObject(CLSID_Session);
588 if (FAILED(hr))
589 RTStrmPrintf(g_pStdErr, "WARNING: Failed to create a session object (hr=0x%x)\n", hr);
590 }
591
592 if (SUCCEEDED(hr))
593 {
594 if (fAllMachines)
595 {
596 com::SafeIfaceArray<IMachine> machines;
597 hr = virtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
598 if (SUCCEEDED(hr))
599 {
600 for (size_t i = 0; i < machines.size(); ++i)
601 {
602 if (machines[i])
603 addMachine(list, machines[i]);
604 }
605 }
606 }
607 else
608 {
609 for ( std::list<const char *>::iterator it = nameList.begin(); it != nameList.end(); ++it)
610 {
611 ComPtr<IMachine> machine;
612 handleComError(virtualBox->FindMachine(com::Bstr(*it).raw(), machine.asOutParam()),
613 "No such machine '%s'", *it);
614 addMachine(list, machine);
615 }
616 }
617 }
618
619 }
620 while(0);
621
622 RTTIMESPEC TimeSpec;
623 RTTIME Time;
624 RTTimeExplode(&Time, RTTimeNow(&TimeSpec));
625 RTCStringFmt strOutFile("%04d-%02d-%02d-%02d-%02d-%02d-bugreport.%s",
626 Time.i32Year, Time.u8Month, Time.u8MonthDay,
627 Time.u8Hour, Time.u8Minute, Time.u8Second,
628 fTextOutput ? "txt" : "tgz");
629 RTCString strFallbackOutFile;
630 if (!pszOutputFile)
631 {
632 RTFILE tmp;
633 pszOutputFile = strOutFile.c_str();
634 int rc = RTFileOpen(&tmp, pszOutputFile, RTFILE_O_WRITE | RTFILE_O_CREATE | RTFILE_O_DENY_WRITE);
635 if (rc == VERR_ACCESS_DENIED)
636 {
637 char szUserHome[RTPATH_MAX];
638 handleRtError(RTPathUserHome(szUserHome, sizeof(szUserHome)), "Failed to obtain home directory");
639 strFallbackOutFile.printf("%s/%s", szUserHome, strOutFile.c_str());
640 pszOutputFile = strFallbackOutFile.c_str();
641 }
642 else if (RT_SUCCESS(rc))
643 {
644 RTFileClose(tmp);
645 RTFileDelete(pszOutputFile);
646 }
647 }
648 BugReport *pReport;
649 if (fTextOutput)
650 pReport = new BugReportText(pszOutputFile);
651 else
652 pReport = new BugReportTarGzip(pszOutputFile);
653 createBugReport(pReport, homeDir, list);
654 pReport->process();
655 pReport->complete();
656 RTPrintf("Report was written to '%s'\n", pszOutputFile);
657 delete pReport;
658 }
659 catch (RTCError &e)
660 {
661 RTStrmPrintf(g_pStdErr, "ERROR: %s\n", e.what());
662 }
663
664 com::Shutdown();
665
666 if (g_pszVBoxManage)
667 RTStrFree(g_pszVBoxManage);
668
669 return SUCCEEDED(hr) ? 0 : 1;
670}
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