VirtualBox

source: vbox/trunk/src/VBox/Main/ExtPackManagerImpl.cpp@ 33582

最後變更 在這個檔案從33582是 33523,由 vboxsync 提交於 14 年 前

ExtPack: -> laptop.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 31.2 KB
 
1/* $Id: ExtPackManagerImpl.cpp 33523 2010-10-27 16:05:52Z vboxsync $ */
2/** @file
3 * VirtualBox Main - interface for Extension Packs, VBoxSVC & VBoxC.
4 */
5
6/*
7 * Copyright (C) 2010 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/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include "ExtPackManagerImpl.h"
23
24#include <iprt/ctype.h>
25#include <iprt/dir.h>
26#include <iprt/env.h>
27#include <iprt/file.h>
28#include <iprt/ldr.h>
29#include <iprt/param.h>
30#include <iprt/path.h>
31#include <iprt/pipe.h>
32#include <iprt/process.h>
33#include <iprt/string.h>
34#include <iprt/cpp/xml.h>
35
36#include <VBox/com/array.h>
37#include <VBox/com/ErrorInfo.h>
38#include <VBox/log.h>
39#include "AutoCaller.h"
40
41
42/*******************************************************************************
43* Defined Constants And Macros *
44*******************************************************************************/
45/** @name VBOX_EXTPACK_HELPER_NAME
46 * The name of the utility program we employ to install and uninstall the
47 * extension packs. This is a set-uid-to-root binary on unixy platforms, which
48 * is why it has to be a separate program.
49 */
50#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
51# define VBOX_EXTPACK_HELPER_NAME "VBoxExtPackHelper.exe"
52#else
53# define VBOX_EXTPACK_HELPER_NAME "VBoxExtPackHelper"
54#endif
55/** @name VBOX_EXTPACK_DESCRIPTION_NAME
56 * The name of the description file in an extension pack. */
57#define VBOX_EXTPACK_DESCRIPTION_NAME "ExtPack.xml"
58
59
60/*******************************************************************************
61* Structures and Typedefs *
62*******************************************************************************/
63/**
64 * Private extension pack data.
65 */
66struct ExtPack::Data
67{
68 /** @name IExtPack Attributes.
69 * @{ */
70 /** The name. */
71 Utf8Str strName;
72 /** The version string. */
73 Utf8Str strVersion;
74 /** The revision. */
75 uint32_t uRevision;
76 /** Whether it's usable or not. */
77 bool fUsable;
78 /** Why it is unusable. */
79 Utf8Str strWhyUnusable;
80 /** @} */
81
82 /** Where the extension pack is located. */
83 Utf8Str strPath;
84 /** The module handle of the main extension pack module. */
85 RTLDRMOD hMainMod;
86};
87
88/** List of extension packs. */
89typedef std::list< ComObjPtr<ExtPack> > ExtPackList;
90
91/**
92 * Private extension pack manager data.
93 */
94struct ExtPackManager::Data
95{
96 /** Where the directory where the extension packs are installed. */
97 Utf8Str strBasePath;
98 /** The list of installed extension packs. */
99 ExtPackList llInstalledExtPacks;
100};
101
102
103DEFINE_EMPTY_CTOR_DTOR(ExtPack)
104
105/**
106 * Called by ComObjPtr::createObject when creating the object.
107 *
108 * Just initialize the basic object state, do the rest in init().
109 *
110 * @returns S_OK.
111 */
112HRESULT ExtPack::FinalConstruct()
113{
114 m = NULL;
115 return S_OK;
116}
117
118/**
119 * Initializes the extension pack by reading its file.
120 *
121 * @returns COM status code.
122 * @param a_pszName The name of the extension pack. This is also the
123 * name of the subdirector under @a a_pszParentDir
124 * where the extension pack is installed.
125 * @param a_pszParentDir The parent directory.
126 */
127HRESULT ExtPack::init(const char *a_pszName, const char *a_pszParentDir)
128{
129 /*
130 * Figure out where we live and allocate+initialize our private data.
131 */
132 char szDir[RTPATH_MAX];
133 int vrc = RTPathJoin(szDir, sizeof(szDir), a_pszParentDir, a_pszName);
134 AssertLogRelRCReturn(vrc, E_FAIL);
135
136 m = new Data;
137 m->strName = a_pszName;
138 m->strVersion = "";
139 m->uRevision = 0;
140 m->fUsable = false;
141 m->strWhyUnusable = tr("ExtPack::init failed");
142
143 m->strPath = szDir;
144 m->hMainMod = NIL_RTLDRMOD;
145
146 /*
147 * Read the description file.
148 */
149 char szFile[RTPATH_MAX];
150 vrc = RTPathJoin(szFile, sizeof(szFile), szDir, VBOX_EXTPACK_DESCRIPTION_NAME);
151 AssertLogRelRCReturn(vrc, E_FAIL);
152
153 xml::Document Doc;
154 xml::XmlFileParser Parser;
155 try
156 {
157 Parser.read(szFile, Doc);
158 xml::ElementNode *pRoot = Doc.getRootElement();
159 NOREF(pRoot);
160 }
161 catch (xml::XmlError Err)
162 {
163 m->fUsable = true;
164 m->strWhyUnusable = tr("");
165 }
166
167 return S_OK;
168}
169
170/**
171 * COM cruft.
172 */
173void ExtPack::FinalRelease()
174{
175 uninit();
176}
177
178/**
179 * Do the actual cleanup.
180 */
181void ExtPack::uninit()
182{
183 /* Enclose the state transition Ready->InUninit->NotReady */
184 AutoUninitSpan autoUninitSpan(this);
185 if (!autoUninitSpan.uninitDone() && m != NULL)
186 {
187 if (m->hMainMod != NIL_RTLDRMOD)
188 {
189 RTLdrClose(m->hMainMod);
190 m->hMainMod = NIL_RTLDRMOD;
191 }
192
193 delete m;
194 m = NULL;
195 }
196}
197
198
199
200
201STDMETHODIMP ExtPack::COMGETTER(Name)(BSTR *a_pbstrName)
202{
203 CheckComArgOutPointerValid(a_pbstrName);
204
205 AutoCaller autoCaller(this);
206 HRESULT hrc = autoCaller.rc();
207 if (SUCCEEDED(hrc))
208 m->strName.cloneTo(a_pbstrName);
209 return hrc;
210}
211
212STDMETHODIMP ExtPack::COMGETTER(Version)(BSTR *a_pbstrVersion)
213{
214 CheckComArgOutPointerValid(a_pbstrVersion);
215
216 AutoCaller autoCaller(this);
217 HRESULT hrc = autoCaller.rc();
218 if (SUCCEEDED(hrc))
219 m->strVersion.cloneTo(a_pbstrVersion);
220 return hrc;
221}
222
223STDMETHODIMP ExtPack::COMGETTER(Revision)(ULONG *a_puRevision)
224{
225 CheckComArgOutPointerValid(a_puRevision);
226
227 AutoCaller autoCaller(this);
228 HRESULT hrc = autoCaller.rc();
229 if (SUCCEEDED(hrc))
230 *a_puRevision = m->uRevision;
231 return hrc;
232}
233
234STDMETHODIMP ExtPack::COMGETTER(Usable)(BOOL *a_pfUsable)
235{
236 CheckComArgOutPointerValid(a_pfUsable);
237
238 AutoCaller autoCaller(this);
239 HRESULT hrc = autoCaller.rc();
240 if (SUCCEEDED(hrc))
241 *a_pfUsable = m->fUsable;
242 return hrc;
243}
244
245STDMETHODIMP ExtPack::COMGETTER(WhyUnusable)(BSTR *a_pbstrWhy)
246{
247 CheckComArgOutPointerValid(a_pbstrWhy);
248
249 AutoCaller autoCaller(this);
250 HRESULT hrc = autoCaller.rc();
251 if (SUCCEEDED(hrc))
252 m->strWhyUnusable.cloneTo(a_pbstrWhy);
253 return hrc;
254}
255
256
257
258void *ExtPack::getCallbackTable()
259{
260 return NULL;
261}
262
263/**
264 * Refreshes the extension pack state.
265 *
266 * This is called by the manager so that the on disk changes are picked up.
267 *
268 * @returns S_OK or COM error status with error information.
269 * @param pfCanDelete Optional can-delete-this-object output indicator.
270 */
271HRESULT ExtPack::refresh(bool *pfCanDelete)
272{
273 if (pfCanDelete)
274 *pfCanDelete = false;
275 return S_OK;
276}
277
278
279
280
281DEFINE_EMPTY_CTOR_DTOR(ExtPackManager)
282
283/**
284 * Called by ComObjPtr::createObject when creating the object.
285 *
286 * Just initialize the basic object state, do the rest in init().
287 *
288 * @returns S_OK.
289 */
290HRESULT ExtPackManager::FinalConstruct()
291{
292 m = NULL;
293 return S_OK;
294}
295
296/**
297 * Initializes the extension pack manager.
298 *
299 * @returns COM status code.
300 */
301HRESULT ExtPackManager::init()
302{
303 /*
304 * Figure some stuff out before creating the instance data.
305 */
306 char szBasePath[RTPATH_MAX];
307 int rc = RTPathAppPrivateArch(szBasePath, sizeof(szBasePath));
308 AssertLogRelRCReturn(rc, E_FAIL);
309 rc = RTPathAppend(szBasePath, sizeof(szBasePath), "ExtensionPacks");
310 AssertLogRelRCReturn(rc, E_FAIL);
311
312 /*
313 * Allocate and initialize the instance data.
314 */
315 m = new Data;
316 m->strBasePath = szBasePath;
317
318 /*
319 * Go looking for extensions. The RTDirOpen may fail if nothing has been
320 * installed yet, or if root is paranoid and has revoked our access to them.
321 *
322 * We ASSUME that there are no files, directories or stuff in the directory
323 * that exceed the max name length in RTDIRENTRYEX.
324 */
325 PRTDIR pDir;
326 int vrc = RTDirOpen(&pDir, szBasePath);
327 if (RT_FAILURE(vrc))
328 return S_OK;
329 HRESULT hrc = S_OK;
330 for (;;)
331 {
332 RTDIRENTRYEX Entry;
333 vrc = RTDirReadEx(pDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
334 if (RT_FAILURE(vrc))
335 {
336 AssertLogRelMsg(vrc == VERR_NO_MORE_FILES, ("%Rrc\n", vrc));
337 break;
338 }
339 if ( RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)
340 && strcmp(Entry.szName, ".") != 0
341 && strcmp(Entry.szName, "..") != 0 )
342 {
343 /*
344 * All directories are extensions, the shall be nothing but
345 * extensions in this subdirectory.
346 */
347 ComObjPtr<ExtPack> NewExtPack;
348 HRESULT hrc2 = NewExtPack.createObject();
349 if (SUCCEEDED(hrc2))
350 hrc2 = NewExtPack->init(Entry.szName, szBasePath);
351 if (SUCCEEDED(hrc2))
352 m->llInstalledExtPacks.push_back(NewExtPack);
353 else if (SUCCEEDED(rc))
354 hrc = hrc2;
355 }
356 }
357 RTDirClose(pDir);
358
359 return hrc;
360}
361
362/**
363 * COM cruft.
364 */
365void ExtPackManager::FinalRelease()
366{
367 uninit();
368}
369
370/**
371 * Do the actual cleanup.
372 */
373void ExtPackManager::uninit()
374{
375 /* Enclose the state transition Ready->InUninit->NotReady */
376 AutoUninitSpan autoUninitSpan(this);
377 if (!autoUninitSpan.uninitDone() && m != NULL)
378 {
379 /** @todo do unload notifications */
380
381 delete m;
382 m = NULL;
383 }
384}
385
386
387STDMETHODIMP ExtPackManager::COMGETTER(InstalledExtPacks)(ComSafeArrayOut(IExtPack *, a_paExtPacks))
388{
389 CheckComArgSafeArrayNotNull(a_paExtPacks);
390
391 AutoCaller autoCaller(this);
392 HRESULT hrc = autoCaller.rc();
393 if (SUCCEEDED(hrc))
394 {
395 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
396
397 SafeIfaceArray<IExtPack> SaExtPacks(m->llInstalledExtPacks);
398 SaExtPacks.detachTo(ComSafeArrayOutArg(a_paExtPacks));
399 }
400
401 return hrc;
402}
403
404STDMETHODIMP ExtPackManager::Find(IN_BSTR a_bstrName, IExtPack **a_pExtPack)
405{
406 CheckComArgNotNull(a_bstrName);
407 CheckComArgOutPointerValid(a_pExtPack);
408 Utf8Str strName(a_bstrName);
409
410 AutoCaller autoCaller(this);
411 HRESULT hrc = autoCaller.rc();
412 if (SUCCEEDED(hrc))
413 {
414 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
415
416 ComPtr<ExtPack> ptrExtPack = findExtPack(strName.c_str());
417 if (!ptrExtPack.isNull())
418 ptrExtPack.queryInterfaceTo(a_pExtPack);
419 else
420 hrc = VBOX_E_OBJECT_NOT_FOUND;
421 }
422
423 return hrc;
424}
425
426STDMETHODIMP ExtPackManager::Install(IN_BSTR a_bstrTarball, BSTR *a_pbstrName)
427{
428 CheckComArgNotNull(a_bstrTarball);
429 CheckComArgOutPointerValid(a_pbstrName);
430 Utf8Str strTarball(a_bstrTarball);
431
432 AutoCaller autoCaller(this);
433 HRESULT hrc = autoCaller.rc();
434 if (SUCCEEDED(hrc))
435 {
436 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
437
438 /*
439 * Check that the file exists and that we can access it.
440 */
441 if (RTFileExists(strTarball.c_str()))
442 {
443 RTFILE hFile;
444 int vrc = RTFileOpen(&hFile, strTarball.c_str(), RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN);
445 if (RT_SUCCESS(vrc))
446 {
447 RTFSOBJINFO ObjInfo;
448 vrc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING);
449 if ( RT_SUCCESS(vrc)
450 && RTFS_IS_FILE(ObjInfo.Attr.fMode))
451 {
452 /*
453 * Derive the name of the extension pack from the file
454 * name.
455 *
456 * RESTRICTION: The name can only contain english alphabet
457 * charactes, decimal digits and space.
458 * Impose a max length of 64 chars.
459 */
460 char *pszName = RTStrDup(RTPathFilename(strTarball.c_str()));
461 if (pszName)
462 {
463 char *pszEnd = pszName;
464 while (RT_C_IS_ALNUM(*pszEnd) || *pszEnd == ' ')
465 pszEnd++;
466 if ( pszEnd == pszName
467 || pszEnd - pszName <= 64)
468 {
469 *pszEnd = '\0';
470
471 /*
472 * Refresh the data we have on the extension pack
473 * as it may be made stale by direct meddling or
474 * some other user.
475 */
476 ExtPack *pExtPack;
477 hrc = refreshExtPack(pszName, false /*a_fUnsuableIsError*/, &pExtPack);
478 if (SUCCEEDED(hrc) && !pExtPack)
479 {
480 /*
481 * Run the set-uid-to-root binary that performs the actual
482 * installation. Then create an object for the packet (we
483 * do this even on failure, to be on the safe side).
484 */
485 char szTarballFd[64];
486 RTStrPrintf(szTarballFd, sizeof(szTarballFd), "0x%RX64",
487 (uint64_t)RTFileToNative(hFile));
488
489 hrc = runSetUidToRootHelper("install",
490 "--basepath", m->strBasePath.c_str(),
491 "--name", pszName,
492 "--tarball", strTarball.c_str(),
493 "--tarball-fd", &szTarballFd[0],
494 NULL);
495 if (SUCCEEDED(hrc))
496 {
497 hrc = refreshExtPack(pszName, true /*a_fUnsuableIsError*/, &pExtPack);
498 if (SUCCEEDED(hrc))
499 LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pszName));
500 }
501 else
502 {
503 ErrorInfoKeeper Eik;
504 refreshExtPack(pszName, false /*a_fUnsuableIsError*/, NULL);
505 }
506 }
507 else if (SUCCEEDED(hrc))
508 hrc = setError(E_FAIL,
509 tr("Extension pack '%s' is already installed."
510 " In case of a reinstallation, please uninstall it first"),
511 pszName);
512 }
513 else
514 hrc = setError(E_FAIL, tr("Malformed '%s' file name"), strTarball.c_str());
515 }
516 else
517 hrc = E_OUTOFMEMORY;
518 }
519 else if (RT_SUCCESS(vrc))
520 hrc = setError(E_FAIL, tr("'%s' is not a regular file"), strTarball.c_str());
521 else
522 hrc = setError(E_FAIL, tr("Failed to query info on '%s' (%Rrc)"), strTarball.c_str(), vrc);
523 RTFileClose(hFile);
524 }
525 else
526 hrc = setError(E_FAIL, tr("Failed to open '%s' (%Rrc)"), strTarball.c_str(), vrc);
527 }
528 else if (RTPathExists(strTarball.c_str()))
529 hrc = setError(E_FAIL, tr("'%s' is not a regular file"), strTarball.c_str());
530 else
531 hrc = setError(E_FAIL, tr("File '%s' was inaccessible or not found"), strTarball.c_str());
532 }
533
534 return hrc;
535}
536
537STDMETHODIMP ExtPackManager::Uninstall(IN_BSTR a_bstrName, BOOL a_fForcedRemoval)
538{
539 CheckComArgNotNull(a_bstrName);
540 Utf8Str strName(a_bstrName);
541
542 AutoCaller autoCaller(this);
543 HRESULT hrc = autoCaller.rc();
544 if (SUCCEEDED(hrc))
545 {
546 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
547
548 /*
549 * Refresh the data we have on the extension pack as it may be made
550 * stale by direct meddling or some other user.
551 */
552 ExtPack *pExtPack;
553 hrc = refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, &pExtPack);
554 if (SUCCEEDED(hrc))
555 {
556 if (!pExtPack)
557 {
558 LogRel(("ExtPackManager: Extension pack '%s' is not installed, so nothing to uninstall.\n", strName.c_str()));
559 hrc = S_OK; /* nothing to uninstall */
560 }
561 else
562 {
563 /*
564 * Run the set-uid-to-root binary that performs the
565 * uninstallation. Then refresh the object.
566 *
567 * This refresh is theorically subject to races, but it's of
568 * the don't-do-that variety.
569 */
570 const char *pszForcedOpt = a_fForcedRemoval ? "--forced" : NULL;
571 hrc = runSetUidToRootHelper("uninstall",
572 "--basepath", m->strBasePath.c_str(),
573 "--name", strName.c_str(),
574 pszForcedOpt, /* Last as it may be NULL. */
575 NULL);
576 if (SUCCEEDED(hrc))
577 {
578 hrc = refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, &pExtPack);
579 if (SUCCEEDED(hrc))
580 {
581 if (!pExtPack)
582 LogRel(("ExtPackManager: Successfully uninstalled extension pack '%s'.\n", strName.c_str()));
583 else
584 hrc = setError(E_UNEXPECTED,
585 tr("Uninstall extension pack '%s' failed under mysterious circumstances"),
586 strName.c_str());
587 }
588 }
589 else
590 {
591 ErrorInfoKeeper Eik;
592 refreshExtPack(strName.c_str(), false /*a_fUnsuableIsError*/, NULL);
593 }
594
595 }
596 }
597 }
598
599 return hrc;
600}
601
602
603/**
604 * Runs the helper program that does the privileged operations.
605 *
606 * @returns S_OK or a failure status with error information set.
607 * @param a_pszCommand The command to execute.
608 * @param ... The argument strings that goes along with the
609 * command. Maximum is about 16. Terminated by a
610 * NULL.
611 */
612HRESULT ExtPackManager::runSetUidToRootHelper(const char *a_pszCommand, ...)
613{
614 /*
615 * Calculate the path to the helper program.
616 */
617 char szExecName[RTPATH_MAX];
618 int vrc = RTPathAppPrivateArch(szExecName, sizeof(szExecName));
619 AssertLogRelRCReturn(vrc, E_UNEXPECTED);
620
621 vrc = RTPathAppend(szExecName, sizeof(szExecName), VBOX_EXTPACK_HELPER_NAME);
622 AssertLogRelRCReturn(vrc, E_UNEXPECTED);
623
624 /*
625 * Convert the variable argument list to a RTProcCreate argument vector.
626 */
627 const char *apszArgs[20];
628 unsigned cArgs = 0;
629 apszArgs[cArgs++] = &szExecName[0];
630 apszArgs[cArgs++] = a_pszCommand;
631
632 va_list va;
633 va_start(va, a_pszCommand);
634 const char *pszLastArg;
635 LogRel(("ExtPack: Executing '%s'", szExecName));
636 do
637 {
638 LogRel((" '%s'", apszArgs[cArgs - 1]));
639 AssertReturn(cArgs < RT_ELEMENTS(apszArgs) - 1, E_UNEXPECTED);
640 pszLastArg = va_arg(va, const char *);
641 apszArgs[cArgs++] = pszLastArg;
642 } while (pszLastArg != NULL);
643 LogRel(("\n"));
644 va_end(va);
645 apszArgs[cArgs] = NULL;
646
647 /*
648 * Create a PIPE which we attach to stderr so that we can read the error
649 * message on failure and report it back to the caller.
650 */
651 RTPIPE hPipeR;
652 RTHANDLE hStdErrPipe;
653 hStdErrPipe.enmType = RTHANDLETYPE_PIPE;
654 vrc = RTPipeCreate(&hPipeR, &hStdErrPipe.u.hPipe, RTPIPE_C_INHERIT_WRITE);
655 AssertLogRelRCReturn(vrc, E_UNEXPECTED);
656
657 /*
658 * Spawn the process.
659 */
660 HRESULT hrc;
661 RTPROCESS hProcess;
662 vrc = RTProcCreateEx(szExecName,
663 apszArgs,
664 RTENV_DEFAULT,
665 0 /*fFlags*/,
666 NULL /*phStdIn*/,
667 NULL /*phStdOut*/,
668 &hStdErrPipe,
669 NULL /*pszAsUser*/,
670 NULL /*pszPassword*/,
671 &hProcess);
672 if (RT_SUCCESS(vrc))
673 {
674 vrc = RTPipeClose(hStdErrPipe.u.hPipe);
675 hStdErrPipe.u.hPipe = NIL_RTPIPE;
676
677 /*
678 * Read the pipe output until the process completes.
679 */
680 RTPROCSTATUS ProcStatus = { -42, RTPROCEXITREASON_ABEND };
681 size_t cbStdErrBuf = 0;
682 size_t offStdErrBuf = 0;
683 char *pszStdErrBuf = NULL;
684 do
685 {
686 /*
687 * Service the pipe. Block waiting for output or the pipe breaking
688 * when the process terminates.
689 */
690 if (hPipeR != NIL_RTPIPE)
691 {
692 char achBuf[16]; //1024
693 size_t cbRead;
694 vrc = RTPipeReadBlocking(hPipeR, achBuf, sizeof(achBuf), &cbRead);
695 if (RT_SUCCESS(vrc))
696 {
697 /* grow the buffer? */
698 size_t cbBufReq = offStdErrBuf + cbRead + 1;
699 if ( cbBufReq > cbStdErrBuf
700 && cbBufReq < _256K)
701 {
702 size_t cbNew = RT_ALIGN_Z(cbBufReq, 16); // 1024
703 void *pvNew = RTMemRealloc(pszStdErrBuf, cbNew);
704 if (pvNew)
705 {
706 pszStdErrBuf = (char *)pvNew;
707 cbStdErrBuf = cbNew;
708 }
709 }
710
711 /* append if we've got room. */
712 if (cbBufReq <= cbStdErrBuf)
713 {
714 memcpy(&pszStdErrBuf[offStdErrBuf], achBuf, cbRead);
715 offStdErrBuf = offStdErrBuf + cbRead;
716 pszStdErrBuf[offStdErrBuf] = '\0';
717 }
718 }
719 else
720 {
721 AssertLogRelMsg(vrc == VERR_BROKEN_PIPE, ("%Rrc\n", vrc));
722 RTPipeClose(hPipeR);
723 hPipeR = NIL_RTPIPE;
724 }
725 }
726
727 /*
728 * Service the process. Block if we have no pipe.
729 */
730 if (hProcess != NIL_RTPROCESS)
731 {
732 vrc = RTProcWait(hProcess,
733 hPipeR == NIL_RTPIPE ? RTPROCWAIT_FLAGS_BLOCK : RTPROCWAIT_FLAGS_NOBLOCK,
734 &ProcStatus);
735 if (RT_SUCCESS(vrc))
736 hProcess = NIL_RTPROCESS;
737 else
738 AssertLogRelMsgStmt(vrc != VERR_PROCESS_RUNNING, ("%Rrc\n", vrc), hProcess = NIL_RTPROCESS);
739 }
740 } while ( hPipeR != NIL_RTPIPE
741 || hProcess != NIL_RTPROCESS);
742
743 /*
744 * Compose the status code and, on failure, error message.
745 */
746 LogRel(("ExtPack: enmReason=%d iStatus=%d stderr='%s'\n",
747 ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""));
748
749 if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
750 && ProcStatus.iStatus == 0
751 && offStdErrBuf == 0)
752 hrc = S_OK;
753 else if (ProcStatus.enmReason == RTPROCEXITREASON_NORMAL)
754 {
755 AssertMsg(ProcStatus.iStatus != 0, ("%s\n", pszStdErrBuf));
756 hrc = setError(E_UNEXPECTED, tr("The installer failed with exit code %d: %s"),
757 ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : "");
758 }
759 else if (ProcStatus.enmReason == RTPROCEXITREASON_SIGNAL)
760 hrc = setError(E_UNEXPECTED, tr("The installer was killed by signal #d (stderr: %s)"),
761 ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : "");
762 else if (ProcStatus.enmReason == RTPROCEXITREASON_ABEND)
763 hrc = setError(E_UNEXPECTED, tr("The installer aborted abnormally (stderr: %s)"),
764 offStdErrBuf ? pszStdErrBuf : "");
765 else
766 hrc = setError(E_UNEXPECTED, tr("internal error: enmReason=%d iStatus=%d stderr='%s'"),
767 ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : "");
768
769 RTMemFree(pszStdErrBuf);
770 }
771 else
772 hrc = setError(VBOX_E_IPRT_ERROR, tr("Failed to launch the helper application '%s' (%Rrc)"), szExecName, vrc);
773
774 RTPipeClose(hPipeR);
775 RTPipeClose(hStdErrPipe.u.hPipe);
776
777 return hrc;
778}
779
780/**
781 * Finds an installed extension pack.
782 *
783 * @returns Pointer to the extension pack if found, NULL if not. (No reference
784 * counting problem here since the caller must be holding the lock.)
785 * @param a_pszName The name of the extension pack.
786 */
787ExtPack *ExtPackManager::findExtPack(const char *a_pszName)
788{
789 size_t cchName = strlen(a_pszName);
790
791 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
792 it != m->llInstalledExtPacks.end();
793 it++)
794 {
795 ExtPack::Data *pExtPackData = (*it)->m;
796 if ( pExtPackData
797 && pExtPackData->strName.length() == cchName
798 && pExtPackData->strName.compare(a_pszName, iprt::MiniString::CaseInsensitive) == 0)
799 return (*it);
800 }
801 return NULL;
802}
803
804/**
805 * Removes an installed extension pack from the internal list.
806 *
807 * The package is expected to exist!
808 *
809 * @param a_pszName The name of the extension pack.
810 */
811void ExtPackManager::removeExtPack(const char *a_pszName)
812{
813 size_t cchName = strlen(a_pszName);
814
815 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
816 it != m->llInstalledExtPacks.end();
817 it++)
818 {
819 ExtPack::Data *pExtPackData = (*it)->m;
820 if ( pExtPackData
821 && pExtPackData->strName.length() == cchName
822 && pExtPackData->strName.compare(a_pszName, iprt::MiniString::CaseInsensitive) == 0)
823 {
824 m->llInstalledExtPacks.erase(it);
825 return;
826 }
827 }
828 AssertMsgFailed(("%s\n", a_pszName));
829}
830
831/**
832 * Refreshes the specified extension pack.
833 *
834 * This may remove the extension pack from the list, so any non-smart pointers
835 * to the extension pack object may become invalid.
836 *
837 * @returns S_OK and *ppExtPack on success, COM status code and error message
838 * on failure.
839 * @param a_pszName The extension to update..
840 * @param a_fUnsuableIsError If @c true, report an unusable extension pack
841 * as an error.
842 * @param a_ppExtPack Where to store the pointer to the extension
843 * pack of it is still around after the refresh.
844 * This is optional.
845 */
846HRESULT ExtPackManager::refreshExtPack(const char *a_pszName, bool a_fUnsuableIsError, ExtPack **a_ppExtPack)
847{
848 HRESULT hrc;
849 ExtPack *pExtPack = findExtPack(a_pszName);
850 if (pExtPack)
851 {
852 /*
853 * Refresh existing object.
854 */
855 bool fCanDelete;
856 hrc = pExtPack->refresh(&fCanDelete);
857 if (SUCCEEDED(hrc))
858 {
859 if (fCanDelete)
860 {
861 removeExtPack(a_pszName);
862 pExtPack = NULL;
863 }
864 }
865 }
866 else
867 {
868 /*
869 * Does the dir exist? Make some special effort to deal with case
870 * sensitivie file systems (a_pszName is case insensitive).
871 */
872 char szDir[RTPATH_MAX];
873 int vrc = RTPathJoin(szDir, sizeof(szDir), m->strBasePath.c_str(), a_pszName);
874 AssertLogRelRCReturn(vrc, E_FAIL);
875
876 RTDIRENTRYEX Entry;
877 RTFSOBJINFO ObjInfo;
878 vrc = RTPathQueryInfoEx(szDir, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
879 bool fExists = RT_SUCCESS(vrc) && RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode);
880 if (!fExists)
881 {
882 PRTDIR pDir;
883 vrc = RTDirOpen(&pDir, m->strBasePath.c_str());
884 if (RT_SUCCESS(vrc))
885 {
886 for (;;)
887 {
888 vrc = RTDirReadEx(pDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
889 if (RT_FAILURE(vrc))
890 {
891 AssertLogRelMsg(vrc == VERR_NO_MORE_FILES, ("%Rrc\n", vrc));
892 break;
893 }
894 if ( RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)
895 && !RTStrICmp(Entry.szName, a_pszName))
896 {
897 /*
898 * The installed extension pack has a uses different case.
899 * Update the name and directory variables.
900 */
901 vrc = RTPathJoin(szDir, sizeof(szDir), m->strBasePath.c_str(), Entry.szName); /* not really necessary */
902 AssertLogRelRCReturnStmt(vrc, E_UNEXPECTED, RTDirClose(pDir));
903 a_pszName = Entry.szName;
904 fExists = true;
905 break;
906 }
907 }
908 RTDirClose(pDir);
909 }
910 }
911 if (fExists)
912 {
913 /*
914 * We've got something, create a new extension pack object for it.
915 */
916 ComObjPtr<ExtPack> NewExtPack;
917 hrc = NewExtPack.createObject();
918 if (SUCCEEDED(hrc))
919 hrc = NewExtPack->init(a_pszName, m->strBasePath.c_str());
920 if (SUCCEEDED(hrc))
921 {
922 m->llInstalledExtPacks.push_back(NewExtPack);
923 if (NewExtPack->m->fUsable)
924 LogRel(("ExtPackManager: Found extension pack '%s'.\n", a_pszName));
925 else
926 LogRel(("ExtPackManager: Found bad extension pack '%s': %s\n",
927 a_pszName, NewExtPack->m->strWhyUnusable.c_str() ));
928 pExtPack = NewExtPack;
929 }
930 }
931 else
932 hrc = S_OK;
933 }
934
935 /*
936 * Report error if not usable, if that is desired.
937 */
938 if ( SUCCEEDED(hrc)
939 && pExtPack
940 && a_fUnsuableIsError
941 && !pExtPack->m->fUsable)
942 hrc = setError(E_FAIL, "%s", pExtPack->m->strWhyUnusable.c_str());
943
944 if (a_ppExtPack)
945 *a_ppExtPack = pExtPack;
946 return hrc;
947}
948
949
950
951int ExtPackManager::callAllConfigHooks(IConsole *a_pConsole, PVM a_pVM)
952{
953 NOREF(a_pConsole); NOREF(a_pVM);
954 return VINF_SUCCESS;
955}
956
957int ExtPackManager::callAllNewMachineHooks(IMachine *a_pMachine)
958{
959 NOREF(a_pMachine);
960 return VINF_SUCCESS;
961}
962
963
964/* vi: set tabstop=4 shiftwidth=4 expandtab: */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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