VirtualBox

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

Last change on this file since 61864 was 61864, checked in by vboxsync, 9 years ago

VBoxBugReport: va_end before we throw

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