VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/win/svcmain.cpp@ 62370

最後變更 在這個檔案從62370是 62222,由 vboxsync 提交於 9 年 前

Main/server: add a BUILDID to the server similar to what we have in VBoxC to be able to identify core dumps generated from VBoxSVC

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 14.2 KB
 
1/* $Id: svcmain.cpp 62222 2016-07-13 15:49:00Z vboxsync $ */
2/** @file
3 *
4 * SVCMAIN - COM out-of-proc server main entry
5 */
6
7/*
8 * Copyright (C) 2004-2016 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.alldomusa.eu.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <Windows.h>
20#include <stdio.h>
21#include <stdlib.h>
22#include <tchar.h>
23
24#include "VBox/com/defs.h"
25
26#include "VBox/com/com.h"
27
28#include "VBox/com/VirtualBox.h"
29
30#include "VirtualBoxImpl.h"
31#include "Logging.h"
32
33#include "svchlp.h"
34
35#include <VBox/err.h>
36#include <iprt/buildconfig.h>
37#include <iprt/initterm.h>
38#include <iprt/string.h>
39#include <iprt/uni.h>
40#include <iprt/path.h>
41#include <iprt/getopt.h>
42#include <iprt/message.h>
43
44class CExeModule : public ATL::CComModule
45{
46public:
47 LONG Unlock();
48 DWORD dwThreadID;
49 HANDLE hEventShutdown;
50 void MonitorShutdown();
51 bool StartMonitor();
52 bool bActivity;
53};
54
55const DWORD dwTimeOut = 5000; /* time for EXE to be idle before shutting down */
56const DWORD dwPause = 100; /* time to wait for threads to finish up */
57
58/* Passed to CreateThread to monitor the shutdown event */
59static DWORD WINAPI MonitorProc(void* pv)
60{
61 CExeModule* p = (CExeModule*)pv;
62 p->MonitorShutdown();
63 return 0;
64}
65
66LONG CExeModule::Unlock()
67{
68 LONG l = ATL::CComModule::Unlock();
69 if (l == 0)
70 {
71 bActivity = true;
72 SetEvent(hEventShutdown); /* tell monitor that we transitioned to zero */
73 }
74 return l;
75}
76
77/* Monitors the shutdown event */
78void CExeModule::MonitorShutdown()
79{
80 while (1)
81 {
82 WaitForSingleObject(hEventShutdown, INFINITE);
83 DWORD dwWait=0;
84 do
85 {
86 bActivity = false;
87 dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
88 } while (dwWait == WAIT_OBJECT_0);
89 /* timed out */
90 if (!bActivity && GetLockCount() == 0) /* if no activity let's really bail */
91 {
92 /* Disable log rotation at this point, worst case a log file
93 * becomes slightly bigger than it should. Avoids quirks with
94 * log rotation: there might be another API service process
95 * running at this point which would rotate the logs concurrently,
96 * creating a mess. */
97 PRTLOGGER pReleaseLogger = RTLogRelGetDefaultInstance();
98 if (pReleaseLogger)
99 {
100 char szDest[1024];
101 int rc = RTLogGetDestinations(pReleaseLogger, szDest, sizeof(szDest));
102 if (RT_SUCCESS(rc))
103 {
104 rc = RTStrCat(szDest, sizeof(szDest), " nohistory");
105 if (RT_SUCCESS(rc))
106 {
107 rc = RTLogDestinations(pReleaseLogger, szDest);
108 AssertRC(rc);
109 }
110 }
111 }
112#if _WIN32_WINNT >= 0x0400
113 CoSuspendClassObjects();
114 if (!bActivity && GetLockCount() == 0)
115#endif
116 break;
117 }
118 }
119 CloseHandle(hEventShutdown);
120 PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
121}
122
123bool CExeModule::StartMonitor()
124{
125 hEventShutdown = CreateEvent(NULL, false, false, NULL);
126 if (hEventShutdown == NULL)
127 return false;
128 DWORD dwThreadID;
129 HANDLE h = CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID);
130 return (h != NULL);
131}
132
133
134BEGIN_OBJECT_MAP(ObjectMap)
135 OBJECT_ENTRY(CLSID_VirtualBox, VirtualBox)
136END_OBJECT_MAP()
137
138
139/////////////////////////////////////////////////////////////////////////////
140//
141int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/)
142{
143 int argc = __argc;
144 char **argv = __argv;
145
146 /*
147 * Need to parse the command line before initializing the VBox runtime so we can
148 * change to the user home directory before logs are being created.
149 */
150 for (int i = 1; i < argc; i++)
151 if ( (argv[i][0] == '/' || argv[i][0] == '-')
152 && stricmp(&argv[i][1], "embedding") == 0) /* ANSI */
153 {
154 /* %HOMEDRIVE%%HOMEPATH% */
155 wchar_t wszHome[RTPATH_MAX];
156 DWORD cEnv = GetEnvironmentVariable(L"HOMEDRIVE", &wszHome[0], RTPATH_MAX);
157 if (cEnv && cEnv < RTPATH_MAX)
158 {
159 DWORD cwc = cEnv; /* doesn't include NUL */
160 cEnv = GetEnvironmentVariable(L"HOMEPATH", &wszHome[cEnv], RTPATH_MAX - cwc);
161 if (cEnv && cEnv < RTPATH_MAX - cwc)
162 {
163 /* If this fails there is nothing we can do. Ignore. */
164 SetCurrentDirectory(wszHome);
165 }
166 }
167 }
168
169 /*
170 * Initialize the VBox runtime without loading
171 * the support driver.
172 */
173 RTR3InitExe(argc, &argv, 0);
174 CExeModule _Module;
175
176 /* Note that all options are given lowercase/camel case/uppercase to
177 * approximate case insensitive matching, which RTGetOpt doesn't offer. */
178 static const RTGETOPTDEF s_aOptions[] =
179 {
180 { "--embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
181 { "-embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
182 { "/embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
183 { "--unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
184 { "-unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
185 { "/unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
186 { "--regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
187 { "-regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
188 { "/regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
189 { "--reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
190 { "-reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
191 { "/reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
192 { "--helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
193 { "-helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
194 { "/helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
195 { "--logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
196 { "-logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
197 { "/logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
198 { "--logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
199 { "-logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
200 { "/logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
201 { "--logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
202 { "-logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
203 { "/logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
204 { "--loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
205 { "-loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
206 { "/loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
207 };
208
209 bool fRun = true;
210 bool fRegister = false;
211 bool fUnregister = false;
212 const char *pszPipeName = NULL;
213 const char *pszLogFile = NULL;
214 uint32_t cHistory = 10; // enable log rotation, 10 files
215 uint32_t uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file
216 uint64_t uHistoryFileSize = 100 * _1M; // max 100MB per file
217
218 RTGETOPTSTATE GetOptState;
219 int vrc = RTGetOptInit(&GetOptState, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
220 AssertRC(vrc);
221
222 RTGETOPTUNION ValueUnion;
223 while ((vrc = RTGetOpt(&GetOptState, &ValueUnion)))
224 {
225 switch (vrc)
226 {
227 case 'e':
228 /* already handled above */
229 break;
230
231 case 'u':
232 fUnregister = true;
233 fRun = false;
234 break;
235
236 case 'r':
237 fRegister = true;
238 fRun = false;
239 break;
240
241 case 'f':
242 fUnregister = true;
243 fRegister = true;
244 fRun = false;
245 break;
246
247 case 'H':
248 pszPipeName = ValueUnion.psz;
249 if (!pszPipeName)
250 pszPipeName = "";
251 fRun = false;
252 break;
253
254 case 'F':
255 pszLogFile = ValueUnion.psz;
256 break;
257
258 case 'R':
259 cHistory = ValueUnion.u32;
260 break;
261
262 case 'S':
263 uHistoryFileSize = ValueUnion.u64;
264 break;
265
266 case 'I':
267 uHistoryFileTime = ValueUnion.u32;
268 break;
269
270 case 'h':
271 {
272 TCHAR txt[]= L"Options:\n\n"
273 L"/RegServer:\tregister COM out-of-proc server\n"
274 L"/UnregServer:\tunregister COM out-of-proc server\n"
275 L"/ReregServer:\tunregister and register COM server\n"
276 L"no options:\trun the server";
277 TCHAR title[]=_T("Usage");
278 fRun = false;
279 MessageBox(NULL, txt, title, MB_OK);
280 return 0;
281 }
282
283 case 'V':
284 {
285 char *psz = NULL;
286 RTStrAPrintf(&psz, "%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
287 PRTUTF16 txt = NULL;
288 RTStrToUtf16(psz, &txt);
289 TCHAR title[]=_T("Version");
290 fRun = false;
291 MessageBox(NULL, txt, title, MB_OK);
292 RTStrFree(psz);
293 RTUtf16Free(txt);
294 return 0;
295 }
296
297 default:
298 /** @todo this assumes that stderr is visible, which is not
299 * true for standard Windows applications. */
300 /* continue on command line errors... */
301 RTGetOptPrintError(vrc, &ValueUnion);
302 }
303 }
304
305 /* Only create the log file when running VBoxSVC normally, but not when
306 * registering/unregistering or calling the helper functionality. */
307 if (fRun)
308 {
309 /** @todo Merge this code with server.cpp (use Logging.cpp?). */
310 char szLogFile[RTPATH_MAX];
311 if (!pszLogFile)
312 {
313 vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
314 if (RT_SUCCESS(vrc))
315 vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log");
316 }
317 else
318 {
319 if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", pszLogFile))
320 vrc = VERR_NO_MEMORY;
321 }
322 if (RT_FAILURE(vrc))
323 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to create logging file name, rc=%Rrc", vrc);
324
325 char szError[RTPATH_MAX + 128];
326 vrc = com::VBoxLogRelCreate("COM Server", szLogFile,
327 RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
328 VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG",
329 RTLOGDEST_FILE, UINT32_MAX /* cMaxEntriesPerGroup */,
330 cHistory, uHistoryFileTime, uHistoryFileSize,
331 szError, sizeof(szError));
332 if (RT_FAILURE(vrc))
333 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", szError, vrc);
334 }
335
336 /* Set up a build identifier so that it can be seen from core dumps what
337 * exact build was used to produce the core. Same as in Console::i_powerUpThread(). */
338 static char saBuildID[48];
339 RTStrPrintf(saBuildID, sizeof(saBuildID), "%s%s%s%s VirtualBox %s r%u %s%s%s%s",
340 "BU", "IL", "DI", "D", RTBldCfgVersion(), RTBldCfgRevision(), "BU", "IL", "DI", "D");
341
342 int nRet = 0;
343 HRESULT hRes = com::Initialize(false /*fGui*/, fRun /*fAutoRegUpdate*/);
344
345 _ASSERTE(SUCCEEDED(hRes));
346 _Module.Init(ObjectMap, hInstance, &LIBID_VirtualBox);
347 _Module.dwThreadID = GetCurrentThreadId();
348
349 if (!fRun)
350 {
351#ifndef VBOX_WITH_MIDL_PROXY_STUB /* VBoxProxyStub.dll does all the registration work. */
352 if (fUnregister)
353 {
354 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE);
355 nRet = _Module.UnregisterServer(TRUE);
356 }
357 if (fRegister)
358 {
359 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE);
360 nRet = _Module.RegisterServer(TRUE);
361 }
362#endif
363 if (pszPipeName)
364 {
365 Log(("SVCMAIN: Processing Helper request (cmdline=\"%s\")...\n", pszPipeName));
366
367 if (!*pszPipeName)
368 vrc = VERR_INVALID_PARAMETER;
369
370 if (RT_SUCCESS(vrc))
371 {
372 /* do the helper job */
373 SVCHlpServer server;
374 vrc = server.open(pszPipeName);
375 if (RT_SUCCESS(vrc))
376 vrc = server.run();
377 }
378 if (RT_FAILURE(vrc))
379 {
380 Log(("SVCMAIN: Failed to process Helper request (%Rrc).", vrc));
381 nRet = 1;
382 }
383 }
384 }
385 else
386 {
387 _Module.StartMonitor();
388#if _WIN32_WINNT >= 0x0400
389 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
390 _ASSERTE(SUCCEEDED(hRes));
391 hRes = CoResumeClassObjects();
392#else
393 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
394#endif
395 _ASSERTE(SUCCEEDED(hRes));
396
397 MSG msg;
398 while (GetMessage(&msg, 0, 0, 0))
399 DispatchMessage(&msg);
400
401 _Module.RevokeClassObjects();
402 Sleep(dwPause); //wait for any threads to finish
403 }
404
405 _Module.Term();
406
407 com::Shutdown();
408
409 Log(("SVCMAIN: Returning, COM server process ends.\n"));
410 return nRet;
411}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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