VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp@ 69987

Last change on this file since 69987 was 69987, checked in by vboxsync, 7 years ago

VBoxService: Added "/VirtualBox/GuestAdd/VBoxService/--timesync-verbosity" guest property to make the time syncing service more verbose. Untested.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 40.8 KB
Line 
1/* $Id: VBoxService.cpp 69987 2017-12-07 16:02:40Z vboxsync $ */
2/** @file
3 * VBoxService - Guest Additions Service Skeleton.
4 */
5
6/*
7 * Copyright (C) 2007-2017 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/** @page pg_vgsvc VBoxService
20 *
21 * VBoxService is a root daemon for implementing guest additions features.
22 *
23 * It is structured as one binary that contains many sub-services. The reason
24 * for this is partially historical and partially practical. The practical
25 * reason is that the VBoxService binary is typically statically linked, at
26 * least with IPRT and the guest library, so we save quite a lot of space having
27 * on single binary instead individual binaries for each sub-service and their
28 * helpers (currently up to 9 subservices and 8 helpers). The historical is
29 * simply that it started its life on OS/2 dreaming of conquring Windows next,
30 * so it kind of felt natural to have it all in one binary.
31 *
32 * Even if it's structured as a single binary, it is possible, by using command
33 * line options, to start each subservice as an individual process.
34 *
35 * Subservices:
36 * - @subpage pg_vgsvc_timesync "Time Synchronization"
37 * - @subpage pg_vgsvc_vminfo "VM Information"
38 * - @subpage pg_vgsvc_vmstats "VM Statistics"
39 * - @subpage pg_vgsvc_gstctrl "Guest Control"
40 * - @subpage pg_vgsvc_pagesharing "Page Sharing"
41 * - @subpage pg_vgsvc_memballoon "Memory Balooning"
42 * - @subpage pg_vgsvc_cpuhotplug "CPU Hot-Plugging"
43 * - @subpage pg_vgsvc_automount "Shared Folder Automounting"
44 * - @subpage pg_vgsvc_clipboard "Clipboard (OS/2 only)"
45 *
46 * Now, since the service predates a lot of stuff, including RTGetOpt, we're
47 * currently doing our own version of argument parsing here, which is kind of
48 * stupid. That will hopefully be cleaned up eventually.
49 */
50
51
52/*********************************************************************************************************************************
53* Header Files *
54*********************************************************************************************************************************/
55/** @todo LOG_GROUP*/
56#ifndef _MSC_VER
57# include <unistd.h>
58#endif
59#include <errno.h>
60#ifndef RT_OS_WINDOWS
61# include <signal.h>
62# ifdef RT_OS_OS2
63# define pthread_sigmask sigprocmask
64# endif
65#endif
66#ifdef RT_OS_FREEBSD
67# include <pthread.h>
68#endif
69
70#include <package-generated.h>
71#include "product-generated.h"
72
73#include <iprt/asm.h>
74#include <iprt/buildconfig.h>
75#include <iprt/initterm.h>
76#include <iprt/file.h>
77#ifdef DEBUG
78# include <iprt/memtracker.h>
79#endif
80#include <iprt/message.h>
81#include <iprt/path.h>
82#include <iprt/process.h>
83#include <iprt/semaphore.h>
84#include <iprt/string.h>
85#include <iprt/stream.h>
86#include <iprt/system.h>
87#include <iprt/thread.h>
88
89#include <VBox/log.h>
90
91#include "VBoxServiceInternal.h"
92#ifdef VBOX_WITH_VBOXSERVICE_CONTROL
93# include "VBoxServiceControl.h"
94#endif
95#ifdef VBOX_WITH_VBOXSERVICE_TOOLBOX
96# include "VBoxServiceToolBox.h"
97#endif
98
99
100/*********************************************************************************************************************************
101* Global Variables *
102*********************************************************************************************************************************/
103/** The program name (derived from argv[0]). */
104char *g_pszProgName = (char *)"";
105/** The current verbosity level. */
106unsigned g_cVerbosity = 0;
107char g_szLogFile[RTPATH_MAX + 128] = "";
108char g_szPidFile[RTPATH_MAX] = "";
109/** Logging parameters. */
110/** @todo Make this configurable later. */
111static PRTLOGGER g_pLoggerRelease = NULL;
112static uint32_t g_cHistory = 10; /* Enable log rotation, 10 files. */
113static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /* Max 1 day per file. */
114static uint64_t g_uHistoryFileSize = 100 * _1M; /* Max 100MB per file. */
115/** Critical section for (debug) logging. */
116#ifdef DEBUG
117 RTCRITSECT g_csLog;
118#endif
119/** The default service interval (the -i | --interval) option). */
120uint32_t g_DefaultInterval = 0;
121#ifdef RT_OS_WINDOWS
122/** Signal shutdown to the Windows service thread. */
123static bool volatile g_fWindowsServiceShutdown;
124/** Event the Windows service thread waits for shutdown. */
125static RTSEMEVENT g_hEvtWindowsService;
126#endif
127
128/**
129 * The details of the services that has been compiled in.
130 */
131static struct
132{
133 /** Pointer to the service descriptor. */
134 PCVBOXSERVICE pDesc;
135 /** The worker thread. NIL_RTTHREAD if it's the main thread. */
136 RTTHREAD Thread;
137 /** Whether Pre-init was called. */
138 bool fPreInited;
139 /** Shutdown indicator. */
140 bool volatile fShutdown;
141 /** Indicator set by the service thread exiting. */
142 bool volatile fStopped;
143 /** Whether the service was started or not. */
144 bool fStarted;
145 /** Whether the service is enabled or not. */
146 bool fEnabled;
147} g_aServices[] =
148{
149#ifdef VBOX_WITH_VBOXSERVICE_CONTROL
150 { &g_Control, NIL_RTTHREAD, false, false, false, false, true },
151#endif
152#ifdef VBOX_WITH_VBOXSERVICE_TIMESYNC
153 { &g_TimeSync, NIL_RTTHREAD, false, false, false, false, true },
154#endif
155#ifdef VBOX_WITH_VBOXSERVICE_CLIPBOARD
156 { &g_Clipboard, NIL_RTTHREAD, false, false, false, false, true },
157#endif
158#ifdef VBOX_WITH_VBOXSERVICE_VMINFO
159 { &g_VMInfo, NIL_RTTHREAD, false, false, false, false, true },
160#endif
161#ifdef VBOX_WITH_VBOXSERVICE_CPUHOTPLUG
162 { &g_CpuHotPlug, NIL_RTTHREAD, false, false, false, false, true },
163#endif
164#ifdef VBOX_WITH_VBOXSERVICE_MANAGEMENT
165# ifdef VBOX_WITH_MEMBALLOON
166 { &g_MemBalloon, NIL_RTTHREAD, false, false, false, false, true },
167# endif
168 { &g_VMStatistics, NIL_RTTHREAD, false, false, false, false, true },
169#endif
170#if defined(VBOX_WITH_VBOXSERVICE_PAGE_SHARING)
171 { &g_PageSharing, NIL_RTTHREAD, false, false, false, false, true },
172#endif
173#ifdef VBOX_WITH_SHARED_FOLDERS
174 { &g_AutoMount, NIL_RTTHREAD, false, false, false, false, true },
175#endif
176};
177
178
179/*
180 * Default call-backs for services which do not need special behaviour.
181 */
182
183/**
184 * @interface_method_impl{VBOXSERVICE,pfnPreInit, Default Implementation}
185 */
186DECLCALLBACK(int) VGSvcDefaultPreInit(void)
187{
188 return VINF_SUCCESS;
189}
190
191
192/**
193 * @interface_method_impl{VBOXSERVICE,pfnOption, Default Implementation}
194 */
195DECLCALLBACK(int) VGSvcDefaultOption(const char **ppszShort, int argc,
196 char **argv, int *pi)
197{
198 NOREF(ppszShort);
199 NOREF(argc);
200 NOREF(argv);
201 NOREF(pi);
202
203 return -1;
204}
205
206
207/**
208 * @interface_method_impl{VBOXSERVICE,pfnInit, Default Implementation}
209 */
210DECLCALLBACK(int) VGSvcDefaultInit(void)
211{
212 return VINF_SUCCESS;
213}
214
215
216/**
217 * @interface_method_impl{VBOXSERVICE,pfnTerm, Default Implementation}
218 */
219DECLCALLBACK(void) VGSvcDefaultTerm(void)
220{
221 return;
222}
223
224
225/**
226 * @callback_method_impl{FNRTLOGPHASE, Release logger callback}
227 */
228static DECLCALLBACK(void) vgsvcLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
229{
230 /* Some introductory information. */
231 static RTTIMESPEC s_TimeSpec;
232 char szTmp[256];
233 if (enmPhase == RTLOGPHASE_BEGIN)
234 RTTimeNow(&s_TimeSpec);
235 RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp));
236
237 switch (enmPhase)
238 {
239 case RTLOGPHASE_BEGIN:
240 {
241 pfnLog(pLoggerRelease,
242 "VBoxService %s r%s (verbosity: %u) %s (%s %s) release log\n"
243 "Log opened %s\n",
244 RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity, VBOX_BUILD_TARGET,
245 __DATE__, __TIME__, szTmp);
246
247 int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
248 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
249 pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp);
250 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
251 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
252 pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp);
253 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
254 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
255 pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp);
256 vrc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szTmp, sizeof(szTmp));
257 if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
258 pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp);
259
260 /* the package type is interesting for Linux distributions */
261 char szExecName[RTPATH_MAX];
262 char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
263 pfnLog(pLoggerRelease,
264 "Executable: %s\n"
265 "Process ID: %u\n"
266 "Package type: %s"
267#ifdef VBOX_OSE
268 " (OSE)"
269#endif
270 "\n",
271 pszExecName ? pszExecName : "unknown",
272 RTProcSelf(),
273 VBOX_PACKAGE_STRING);
274 break;
275 }
276
277 case RTLOGPHASE_PREROTATE:
278 pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp);
279 break;
280
281 case RTLOGPHASE_POSTROTATE:
282 pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp);
283 break;
284
285 case RTLOGPHASE_END:
286 pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp);
287 break;
288
289 default:
290 /* nothing */
291 break;
292 }
293}
294
295
296/**
297 * Creates the default release logger outputting to the specified file.
298 *
299 * Pass NULL to disabled logging.
300 *
301 * @return IPRT status code.
302 * @param pszLogFile Filename for log output. NULL disables logging
303 * (r=bird: No, it doesn't!).
304 */
305int VGSvcLogCreate(const char *pszLogFile)
306{
307 /* Create release logger (stdout + file). */
308 static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
309 RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG;
310#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
311 fFlags |= RTLOGFLAGS_USECRLF;
312#endif
313 int rc = RTLogCreateEx(&g_pLoggerRelease, fFlags, "all",
314#ifdef DEBUG
315 "VBOXSERVICE_LOG",
316#else
317 "VBOXSERVICE_RELEASE_LOG",
318#endif
319 RT_ELEMENTS(s_apszGroups), s_apszGroups,
320 RTLOGDEST_STDOUT | RTLOGDEST_USER,
321 vgsvcLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
322 NULL /*pErrInfo*/, "%s", pszLogFile ? pszLogFile : "");
323 if (RT_SUCCESS(rc))
324 {
325 /* register this logger as the release logger */
326 RTLogRelSetDefaultInstance(g_pLoggerRelease);
327
328 /* Explicitly flush the log in case of VBOXSERVICE_RELEASE_LOG=buffered. */
329 RTLogFlush(g_pLoggerRelease);
330 }
331
332 return rc;
333}
334
335
336/**
337 * Logs a verbose message.
338 *
339 * @param pszFormat The message text.
340 * @param ... Format arguments.
341 */
342void VGSvcLog(const char *pszFormat, ...)
343{
344#ifdef DEBUG
345 int rc = RTCritSectEnter(&g_csLog);
346 if (RT_SUCCESS(rc))
347 {
348#endif
349 va_list args;
350 va_start(args, pszFormat);
351 char *psz = NULL;
352 RTStrAPrintfV(&psz, pszFormat, args);
353 va_end(args);
354
355 AssertPtr(psz);
356 LogRel(("%s", psz));
357
358 RTStrFree(psz);
359#ifdef DEBUG
360 RTCritSectLeave(&g_csLog);
361 }
362#endif
363}
364
365
366/**
367 * Destroys the currently active logging instance.
368 */
369void VGSvcLogDestroy(void)
370{
371 RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
372}
373
374
375/**
376 * Displays the program usage message.
377 *
378 * @returns 1.
379 */
380static int vgsvcUsage(void)
381{
382 RTPrintf("Usage:\n"
383 " %-12s [-f|--foreground] [-v|--verbose] [-l|--logfile <file>]\n"
384 " [-p|--pidfile <file>] [-i|--interval <seconds>]\n"
385 " [--disable-<service>] [--enable-<service>]\n"
386 " [--only-<service>] [-h|-?|--help]\n", g_pszProgName);
387#ifdef RT_OS_WINDOWS
388 RTPrintf(" [-r|--register] [-u|--unregister]\n");
389#endif
390 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
391 if (g_aServices[j].pDesc->pszUsage)
392 RTPrintf("%s\n", g_aServices[j].pDesc->pszUsage);
393 RTPrintf("\n"
394 "Options:\n"
395 " -i | --interval The default interval.\n"
396 " -f | --foreground Don't daemonize the program. For debugging.\n"
397 " -l | --logfile <file> Enables logging to a file.\n"
398 " -p | --pidfile <file> Write the process ID to a file.\n"
399 " -v | --verbose Increment the verbosity level. For debugging.\n"
400 " -V | --version Show version information.\n"
401 " -h | -? | --help Show this message and exit with status 1.\n"
402 );
403#ifdef RT_OS_WINDOWS
404 RTPrintf(" -r | --register Installs the service.\n"
405 " -u | --unregister Uninstall service.\n");
406#endif
407
408 RTPrintf("\n"
409 "Service-specific options:\n");
410 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
411 {
412 RTPrintf(" --enable-%-14s Enables the %s service. (default)\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
413 RTPrintf(" --disable-%-13s Disables the %s service.\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
414 RTPrintf(" --only-%-16s Only enables the %s service.\n", g_aServices[j].pDesc->pszName, g_aServices[j].pDesc->pszName);
415 if (g_aServices[j].pDesc->pszOptions)
416 RTPrintf("%s", g_aServices[j].pDesc->pszOptions);
417 }
418 RTPrintf("\n"
419 " Copyright (C) 2009-" VBOX_C_YEAR " " VBOX_VENDOR "\n");
420
421 return 1;
422}
423
424
425/**
426 * Displays an error message.
427 *
428 * @returns RTEXITCODE_FAILURE.
429 * @param pszFormat The message text.
430 * @param ... Format arguments.
431 */
432RTEXITCODE VGSvcError(const char *pszFormat, ...)
433{
434 va_list args;
435 va_start(args, pszFormat);
436 char *psz = NULL;
437 RTStrAPrintfV(&psz, pszFormat, args);
438 va_end(args);
439
440 AssertPtr(psz);
441 LogRel(("Error: %s", psz));
442
443 RTStrFree(psz);
444
445 return RTEXITCODE_FAILURE;
446}
447
448
449/**
450 * Displays a verbose message based on the currently
451 * set global verbosity level.
452 *
453 * @param iLevel Minimum log level required to display this message.
454 * @param pszFormat The message text.
455 * @param ... Format arguments.
456 */
457void VGSvcVerbose(unsigned iLevel, const char *pszFormat, ...)
458{
459 if (iLevel <= g_cVerbosity)
460 {
461 va_list args;
462 va_start(args, pszFormat);
463
464 VGSvcLog(pszFormat, args);
465
466 va_end(args);
467 }
468}
469
470
471/**
472 * Reports the current VBoxService status to the host.
473 *
474 * This makes sure that the Failed state is sticky.
475 *
476 * @return IPRT status code.
477 * @param enmStatus Status to report to the host.
478 */
479int VGSvcReportStatus(VBoxGuestFacilityStatus enmStatus)
480{
481 /*
482 * VBoxGuestFacilityStatus_Failed is sticky.
483 */
484 static VBoxGuestFacilityStatus s_enmLastStatus = VBoxGuestFacilityStatus_Inactive;
485 VGSvcVerbose(4, "Setting VBoxService status to %u\n", enmStatus);
486 if (s_enmLastStatus != VBoxGuestFacilityStatus_Failed)
487 {
488 int rc = VbglR3ReportAdditionsStatus(VBoxGuestFacilityType_VBoxService, enmStatus, 0 /* Flags */);
489 if (RT_FAILURE(rc))
490 {
491 VGSvcError("Could not report VBoxService status (%u), rc=%Rrc\n", enmStatus, rc);
492 return rc;
493 }
494 s_enmLastStatus = enmStatus;
495 }
496 return VINF_SUCCESS;
497}
498
499
500/**
501 * Gets a 32-bit value argument.
502 * @todo Get rid of this and VGSvcArgString() as soon as we have RTOpt handling.
503 *
504 * @returns 0 on success, non-zero exit code on error.
505 * @param argc The argument count.
506 * @param argv The argument vector
507 * @param psz Where in *pi to start looking for the value argument.
508 * @param pi Where to find and perhaps update the argument index.
509 * @param pu32 Where to store the 32-bit value.
510 * @param u32Min The minimum value.
511 * @param u32Max The maximum value.
512 */
513int VGSvcArgUInt32(int argc, char **argv, const char *psz, int *pi, uint32_t *pu32, uint32_t u32Min, uint32_t u32Max)
514{
515 if (*psz == ':' || *psz == '=')
516 psz++;
517 if (!*psz)
518 {
519 if (*pi + 1 >= argc)
520 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing value for the '%s' argument\n", argv[*pi]);
521 psz = argv[++*pi];
522 }
523
524 char *pszNext;
525 int rc = RTStrToUInt32Ex(psz, &pszNext, 0, pu32);
526 if (RT_FAILURE(rc) || *pszNext)
527 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Failed to convert interval '%s' to a number\n", psz);
528 if (*pu32 < u32Min || *pu32 > u32Max)
529 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The timesync interval of %RU32 seconds is out of range [%RU32..%RU32]\n",
530 *pu32, u32Min, u32Max);
531 return 0;
532}
533
534
535/** @todo Get rid of this and VGSvcArgUInt32() as soon as we have RTOpt handling. */
536static int vgsvcArgString(int argc, char **argv, const char *psz, int *pi, char *pszBuf, size_t cbBuf)
537{
538 AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
539 AssertPtrReturn(cbBuf, VERR_INVALID_PARAMETER);
540
541 if (*psz == ':' || *psz == '=')
542 psz++;
543 if (!*psz)
544 {
545 if (*pi + 1 >= argc)
546 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing string for the '%s' argument\n", argv[*pi]);
547 psz = argv[++*pi];
548 }
549
550 if (!RTStrPrintf(pszBuf, cbBuf, "%s", psz))
551 return RTMsgErrorExit(RTEXITCODE_FAILURE, "String for '%s' argument too big\n", argv[*pi]);
552 return 0;
553}
554
555
556/**
557 * The service thread.
558 *
559 * @returns Whatever the worker function returns.
560 * @param ThreadSelf My thread handle.
561 * @param pvUser The service index.
562 */
563static DECLCALLBACK(int) vgsvcThread(RTTHREAD ThreadSelf, void *pvUser)
564{
565 const unsigned i = (uintptr_t)pvUser;
566
567#ifndef RT_OS_WINDOWS
568 /*
569 * Block all signals for this thread. Only the main thread will handle signals.
570 */
571 sigset_t signalMask;
572 sigfillset(&signalMask);
573 pthread_sigmask(SIG_BLOCK, &signalMask, NULL);
574#endif
575
576 int rc = g_aServices[i].pDesc->pfnWorker(&g_aServices[i].fShutdown);
577 ASMAtomicXchgBool(&g_aServices[i].fShutdown, true);
578 RTThreadUserSignal(ThreadSelf);
579 return rc;
580}
581
582
583/**
584 * Lazily calls the pfnPreInit method on each service.
585 *
586 * @returns VBox status code, error message displayed.
587 */
588static RTEXITCODE vgsvcLazyPreInit(void)
589{
590 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
591 if (!g_aServices[j].fPreInited)
592 {
593 int rc = g_aServices[j].pDesc->pfnPreInit();
594 if (RT_FAILURE(rc))
595 return VGSvcError("Service '%s' failed pre-init: %Rrc\n", g_aServices[j].pDesc->pszName, rc);
596 g_aServices[j].fPreInited = true;
597 }
598 return RTEXITCODE_SUCCESS;
599}
600
601
602/**
603 * Count the number of enabled services.
604 */
605static unsigned vgsvcCountEnabledServices(void)
606{
607 unsigned cEnabled = 0;
608 for (unsigned i = 0; i < RT_ELEMENTS(g_aServices); i++)
609 cEnabled += g_aServices[i].fEnabled;
610 return cEnabled;
611}
612
613
614#ifdef RT_OS_WINDOWS
615/**
616 * Console control event callback.
617 *
618 * @returns TRUE if handled, FALSE if not.
619 * @param dwCtrlType The control event type.
620 *
621 * @remarks This is generally called on a new thread, so we're racing every
622 * other thread in the process.
623 */
624static BOOL WINAPI vgsvcWinConsoleControlHandler(DWORD dwCtrlType)
625{
626 int rc = VINF_SUCCESS;
627 bool fEventHandled = FALSE;
628 switch (dwCtrlType)
629 {
630 /* User pressed CTRL+C or CTRL+BREAK or an external event was sent
631 * via GenerateConsoleCtrlEvent(). */
632 case CTRL_BREAK_EVENT:
633 case CTRL_CLOSE_EVENT:
634 case CTRL_C_EVENT:
635 VGSvcVerbose(2, "ControlHandler: Received break/close event\n");
636 rc = VGSvcStopServices();
637 fEventHandled = TRUE;
638 break;
639 default:
640 break;
641 /** @todo Add other events here. */
642 }
643
644 if (RT_FAILURE(rc))
645 VGSvcError("ControlHandler: Event %ld handled with error rc=%Rrc\n",
646 dwCtrlType, rc);
647 return fEventHandled;
648}
649#endif /* RT_OS_WINDOWS */
650
651
652/**
653 * Starts the service.
654 *
655 * @returns VBox status code, errors are fully bitched.
656 *
657 * @remarks Also called from VBoxService-win.cpp, thus not static.
658 */
659int VGSvcStartServices(void)
660{
661 int rc;
662
663 VGSvcReportStatus(VBoxGuestFacilityStatus_Init);
664
665 /*
666 * Initialize the services.
667 */
668 VGSvcVerbose(2, "Initializing services ...\n");
669 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
670 if (g_aServices[j].fEnabled)
671 {
672 rc = g_aServices[j].pDesc->pfnInit();
673 if (RT_FAILURE(rc))
674 {
675 if (rc != VERR_SERVICE_DISABLED)
676 {
677 VGSvcError("Service '%s' failed to initialize: %Rrc\n", g_aServices[j].pDesc->pszName, rc);
678 VGSvcReportStatus(VBoxGuestFacilityStatus_Failed);
679 return rc;
680 }
681 g_aServices[j].fEnabled = false;
682 VGSvcVerbose(0, "Service '%s' was disabled because of missing functionality\n", g_aServices[j].pDesc->pszName);
683
684 }
685 }
686
687 /*
688 * Start the service(s).
689 */
690 VGSvcVerbose(2, "Starting services ...\n");
691 rc = VINF_SUCCESS;
692 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
693 {
694 if (!g_aServices[j].fEnabled)
695 continue;
696
697 VGSvcVerbose(2, "Starting service '%s' ...\n", g_aServices[j].pDesc->pszName);
698 rc = RTThreadCreate(&g_aServices[j].Thread, vgsvcThread, (void *)(uintptr_t)j, 0,
699 RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, g_aServices[j].pDesc->pszName);
700 if (RT_FAILURE(rc))
701 {
702 VGSvcError("RTThreadCreate failed, rc=%Rrc\n", rc);
703 break;
704 }
705 g_aServices[j].fStarted = true;
706
707 /* Wait for the thread to initialize. */
708 /** @todo There is a race between waiting and checking
709 * the fShutdown flag of a thread here and processing
710 * the thread's actual worker loop. If the thread decides
711 * to exit the loop before we skipped the fShutdown check
712 * below the service will fail to start! */
713 /** @todo This presumably means either a one-shot service or that
714 * something has gone wrong. In the second case treating it as failure
715 * to start is probably right, so we need a way to signal the first
716 * rather than leaving the idle thread hanging around. A flag in the
717 * service description? */
718 RTThreadUserWait(g_aServices[j].Thread, 60 * 1000);
719 if (g_aServices[j].fShutdown)
720 {
721 VGSvcError("Service '%s' failed to start!\n", g_aServices[j].pDesc->pszName);
722 rc = VERR_GENERAL_FAILURE;
723 }
724 }
725
726 if (RT_SUCCESS(rc))
727 VGSvcVerbose(1, "All services started.\n");
728 else
729 {
730 VGSvcError("An error occcurred while the services!\n");
731 VGSvcReportStatus(VBoxGuestFacilityStatus_Failed);
732 }
733 return rc;
734}
735
736
737/**
738 * Stops and terminates the services.
739 *
740 * This should be called even when VBoxServiceStartServices fails so it can
741 * clean up anything that we succeeded in starting.
742 *
743 * @remarks Also called from VBoxService-win.cpp, thus not static.
744 */
745int VGSvcStopServices(void)
746{
747 VGSvcReportStatus(VBoxGuestFacilityStatus_Terminating);
748
749 /*
750 * Signal all the services.
751 */
752 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
753 ASMAtomicWriteBool(&g_aServices[j].fShutdown, true);
754
755 /*
756 * Do the pfnStop callback on all running services.
757 */
758 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
759 if (g_aServices[j].fStarted)
760 {
761 VGSvcVerbose(3, "Calling stop function for service '%s' ...\n", g_aServices[j].pDesc->pszName);
762 g_aServices[j].pDesc->pfnStop();
763 }
764
765 VGSvcVerbose(3, "All stop functions for services called\n");
766
767 /*
768 * Wait for all the service threads to complete.
769 */
770 int rc = VINF_SUCCESS;
771 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
772 {
773 if (!g_aServices[j].fEnabled) /* Only stop services which were started before. */
774 continue;
775 if (g_aServices[j].Thread != NIL_RTTHREAD)
776 {
777 VGSvcVerbose(2, "Waiting for service '%s' to stop ...\n", g_aServices[j].pDesc->pszName);
778 int rc2 = VINF_SUCCESS;
779 for (int i = 0; i < 30; i++) /* Wait 30 seconds in total */
780 {
781 rc2 = RTThreadWait(g_aServices[j].Thread, 1000 /* Wait 1 second */, NULL);
782 if (RT_SUCCESS(rc2))
783 break;
784#ifdef RT_OS_WINDOWS
785 /* Notify SCM that it takes a bit longer ... */
786 VGSvcWinSetStopPendingStatus(i + j*32);
787#endif
788 }
789 if (RT_FAILURE(rc2))
790 {
791 VGSvcError("Service '%s' failed to stop. (%Rrc)\n", g_aServices[j].pDesc->pszName, rc2);
792 rc = rc2;
793 }
794 }
795 VGSvcVerbose(3, "Terminating service '%s' (%d) ...\n", g_aServices[j].pDesc->pszName, j);
796 g_aServices[j].pDesc->pfnTerm();
797 }
798
799#ifdef RT_OS_WINDOWS
800 /*
801 * Wake up and tell the main() thread that we're shutting down (it's
802 * sleeping in VBoxServiceMainWait).
803 */
804 ASMAtomicWriteBool(&g_fWindowsServiceShutdown, true);
805 if (g_hEvtWindowsService != NIL_RTSEMEVENT)
806 {
807 VGSvcVerbose(3, "Stopping the main thread...\n");
808 int rc2 = RTSemEventSignal(g_hEvtWindowsService);
809 AssertRC(rc2);
810 }
811#endif
812
813 VGSvcVerbose(2, "Stopping services returning: %Rrc\n", rc);
814 VGSvcReportStatus(RT_SUCCESS(rc) ? VBoxGuestFacilityStatus_Paused : VBoxGuestFacilityStatus_Failed);
815 return rc;
816}
817
818
819/**
820 * Block the main thread until the service shuts down.
821 *
822 * @remarks Also called from VBoxService-win.cpp, thus not static.
823 */
824void VGSvcMainWait(void)
825{
826 int rc;
827
828 VGSvcReportStatus(VBoxGuestFacilityStatus_Active);
829
830#ifdef RT_OS_WINDOWS
831 /*
832 * Wait for the semaphore to be signalled.
833 */
834 VGSvcVerbose(1, "Waiting in main thread\n");
835 rc = RTSemEventCreate(&g_hEvtWindowsService);
836 AssertRC(rc);
837 while (!ASMAtomicReadBool(&g_fWindowsServiceShutdown))
838 {
839 rc = RTSemEventWait(g_hEvtWindowsService, RT_INDEFINITE_WAIT);
840 AssertRC(rc);
841 }
842 RTSemEventDestroy(g_hEvtWindowsService);
843 g_hEvtWindowsService = NIL_RTSEMEVENT;
844#else
845 /*
846 * Wait explicitly for a HUP, INT, QUIT, ABRT or TERM signal, blocking
847 * all important signals.
848 *
849 * The annoying EINTR/ERESTART loop is for the benefit of Solaris where
850 * sigwait returns when we receive a SIGCHLD. Kind of makes sense since
851 */
852 sigset_t signalMask;
853 sigemptyset(&signalMask);
854 sigaddset(&signalMask, SIGHUP);
855 sigaddset(&signalMask, SIGINT);
856 sigaddset(&signalMask, SIGQUIT);
857 sigaddset(&signalMask, SIGABRT);
858 sigaddset(&signalMask, SIGTERM);
859 pthread_sigmask(SIG_BLOCK, &signalMask, NULL);
860
861 int iSignal;
862 do
863 {
864 iSignal = -1;
865 rc = sigwait(&signalMask, &iSignal);
866 }
867 while ( rc == EINTR
868# ifdef ERESTART
869 || rc == ERESTART
870# endif
871 );
872
873 VGSvcVerbose(3, "VGSvcMainWait: Received signal %d (rc=%d)\n", iSignal, rc);
874#endif /* !RT_OS_WINDOWS */
875}
876
877
878int main(int argc, char **argv)
879{
880 RTEXITCODE rcExit;
881
882 /*
883 * Init globals and such.
884 */
885 int rc = RTR3InitExe(argc, &argv, 0);
886 if (RT_FAILURE(rc))
887 return RTMsgInitFailure(rc);
888 g_pszProgName = RTPathFilename(argv[0]);
889#ifdef DEBUG
890 rc = RTCritSectInit(&g_csLog);
891 AssertRC(rc);
892#endif
893
894#ifdef VBOX_WITH_VBOXSERVICE_TOOLBOX
895 /*
896 * Run toolbox code before all other stuff since these things are simpler
897 * shell/file/text utility like programs that just happens to be inside
898 * VBoxService and shouldn't be subject to /dev/vboxguest, pid-files and
899 * global mutex restrictions.
900 */
901 if (VGSvcToolboxMain(argc, argv, &rcExit))
902 return rcExit;
903#endif
904
905 bool fUserSession = false;
906#ifdef VBOX_WITH_VBOXSERVICE_CONTROL
907 /*
908 * Check if we're the specially spawned VBoxService.exe process that
909 * handles a guest control session.
910 */
911 if ( argc >= 2
912 && !RTStrICmp(argv[1], "guestsession"))
913 fUserSession = true;
914#endif
915
916 /*
917 * Connect to the kernel part before daemonizing so we can fail and
918 * complain if there is some kind of problem. We need to initialize the
919 * guest lib *before* we do the pre-init just in case one of services needs
920 * do to some initial stuff with it.
921 */
922 if (fUserSession)
923 rc = VbglR3InitUser();
924 else
925 rc = VbglR3Init();
926 if (RT_FAILURE(rc))
927 {
928 if (rc == VERR_ACCESS_DENIED)
929 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Insufficient privileges to start %s! Please start with Administrator/root privileges!\n",
930 g_pszProgName);
931 return RTMsgErrorExit(RTEXITCODE_FAILURE, "VbglR3Init failed with rc=%Rrc\n", rc);
932 }
933
934#ifdef RT_OS_WINDOWS
935 /*
936 * Check if we're the specially spawned VBoxService.exe process that
937 * handles page fusion. This saves an extra statically linked executable.
938 */
939 if ( argc == 2
940 && !RTStrICmp(argv[1], "pagefusion"))
941 return VGSvcPageSharingWorkerChild();
942#endif
943
944#ifdef VBOX_WITH_VBOXSERVICE_CONTROL
945 /*
946 * Check if we're the specially spawned VBoxService.exe process that
947 * handles a guest control session.
948 */
949 if (fUserSession)
950 return VGSvcGstCtrlSessionSpawnInit(argc, argv);
951#endif
952
953 /*
954 * Parse the arguments.
955 *
956 * Note! This code predates RTGetOpt, thus the manual parsing.
957 */
958 bool fDaemonize = true;
959 bool fDaemonized = false;
960 for (int i = 1; i < argc; i++)
961 {
962 const char *psz = argv[i];
963 if (*psz != '-')
964 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'\n", psz);
965 psz++;
966
967 /* translate long argument to short */
968 if (*psz == '-')
969 {
970 psz++;
971 size_t cch = strlen(psz);
972#define MATCHES(strconst) ( cch == sizeof(strconst) - 1 \
973 && !memcmp(psz, strconst, sizeof(strconst) - 1) )
974 if (MATCHES("foreground"))
975 psz = "f";
976 else if (MATCHES("verbose"))
977 psz = "v";
978 else if (MATCHES("version"))
979 psz = "V";
980 else if (MATCHES("help"))
981 psz = "h";
982 else if (MATCHES("interval"))
983 psz = "i";
984#ifdef RT_OS_WINDOWS
985 else if (MATCHES("register"))
986 psz = "r";
987 else if (MATCHES("unregister"))
988 psz = "u";
989#endif
990 else if (MATCHES("logfile"))
991 psz = "l";
992 else if (MATCHES("pidfile"))
993 psz = "p";
994 else if (MATCHES("daemonized"))
995 {
996 fDaemonized = true;
997 continue;
998 }
999 else
1000 {
1001 bool fFound = false;
1002
1003 if (cch > sizeof("enable-") && !memcmp(psz, RT_STR_TUPLE("enable-")))
1004 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
1005 if ((fFound = !RTStrICmp(psz + sizeof("enable-") - 1, g_aServices[j].pDesc->pszName)))
1006 g_aServices[j].fEnabled = true;
1007
1008 if (cch > sizeof("disable-") && !memcmp(psz, RT_STR_TUPLE("disable-")))
1009 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
1010 if ((fFound = !RTStrICmp(psz + sizeof("disable-") - 1, g_aServices[j].pDesc->pszName)))
1011 g_aServices[j].fEnabled = false;
1012
1013 if (cch > sizeof("only-") && !memcmp(psz, RT_STR_TUPLE("only-")))
1014 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
1015 {
1016 g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName);
1017 if (g_aServices[j].fEnabled)
1018 fFound = true;
1019 }
1020
1021 if (!fFound)
1022 {
1023 rcExit = vgsvcLazyPreInit();
1024 if (rcExit != RTEXITCODE_SUCCESS)
1025 return rcExit;
1026 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
1027 {
1028 rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
1029 fFound = rc == VINF_SUCCESS;
1030 if (fFound)
1031 break;
1032 if (rc != -1)
1033 return rc;
1034 }
1035 }
1036 if (!fFound)
1037 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%s'\n", argv[i]);
1038 continue;
1039 }
1040#undef MATCHES
1041 }
1042
1043 /* handle the string of short options. */
1044 do
1045 {
1046 switch (*psz)
1047 {
1048 case 'i':
1049 rc = VGSvcArgUInt32(argc, argv, psz + 1, &i,
1050 &g_DefaultInterval, 1, (UINT32_MAX / 1000) - 1);
1051 if (rc)
1052 return rc;
1053 psz = NULL;
1054 break;
1055
1056 case 'f':
1057 fDaemonize = false;
1058 break;
1059
1060 case 'v':
1061 g_cVerbosity++;
1062 break;
1063
1064 case 'V':
1065 RTPrintf("%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
1066 return RTEXITCODE_SUCCESS;
1067
1068 case 'h':
1069 case '?':
1070 return vgsvcUsage();
1071
1072#ifdef RT_OS_WINDOWS
1073 case 'r':
1074 return VGSvcWinInstall();
1075
1076 case 'u':
1077 return VGSvcWinUninstall();
1078#endif
1079
1080 case 'l':
1081 {
1082 rc = vgsvcArgString(argc, argv, psz + 1, &i,
1083 g_szLogFile, sizeof(g_szLogFile));
1084 if (rc)
1085 return rc;
1086 psz = NULL;
1087 break;
1088 }
1089
1090 case 'p':
1091 {
1092 rc = vgsvcArgString(argc, argv, psz + 1, &i,
1093 g_szPidFile, sizeof(g_szPidFile));
1094 if (rc)
1095 return rc;
1096 psz = NULL;
1097 break;
1098 }
1099
1100 default:
1101 {
1102 rcExit = vgsvcLazyPreInit();
1103 if (rcExit != RTEXITCODE_SUCCESS)
1104 return rcExit;
1105
1106 bool fFound = false;
1107 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
1108 {
1109 rc = g_aServices[j].pDesc->pfnOption(&psz, argc, argv, &i);
1110 fFound = rc == VINF_SUCCESS;
1111 if (fFound)
1112 break;
1113 if (rc != -1)
1114 return rc;
1115 }
1116 if (!fFound)
1117 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%c' (%s)\n", *psz, argv[i]);
1118 break;
1119 }
1120 }
1121 } while (psz && *++psz);
1122 }
1123
1124 /* Check that at least one service is enabled. */
1125 if (vgsvcCountEnabledServices() == 0)
1126 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "At least one service must be enabled\n");
1127
1128 rc = VGSvcLogCreate(g_szLogFile[0] ? g_szLogFile : NULL);
1129 if (RT_FAILURE(rc))
1130 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log '%s', rc=%Rrc\n",
1131 g_szLogFile[0] ? g_szLogFile : "<None>", rc);
1132
1133 /* Call pre-init if we didn't do it already. */
1134 rcExit = vgsvcLazyPreInit();
1135 if (rcExit != RTEXITCODE_SUCCESS)
1136 return rcExit;
1137
1138#ifdef RT_OS_WINDOWS
1139 /*
1140 * Make sure only one instance of VBoxService runs at a time. Create a
1141 * global mutex for that.
1142 *
1143 * Note! The \\Global\ namespace was introduced with Win2K, thus the
1144 * version check.
1145 * Note! If the mutex exists CreateMutex will open it and set last error to
1146 * ERROR_ALREADY_EXISTS.
1147 */
1148 OSVERSIONINFOEX OSInfoEx;
1149 RT_ZERO(OSInfoEx);
1150 OSInfoEx.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
1151
1152 SetLastError(NO_ERROR);
1153 HANDLE hMutexAppRunning;
1154 if ( GetVersionEx((LPOSVERSIONINFO)&OSInfoEx)
1155 && OSInfoEx.dwPlatformId == VER_PLATFORM_WIN32_NT
1156 && OSInfoEx.dwMajorVersion >= 5 /* NT 5.0 a.k.a W2K */)
1157 hMutexAppRunning = CreateMutex(NULL, FALSE, "Global\\" VBOXSERVICE_NAME);
1158 else
1159 hMutexAppRunning = CreateMutex(NULL, FALSE, VBOXSERVICE_NAME);
1160 if (hMutexAppRunning == NULL)
1161 {
1162 DWORD dwErr = GetLastError();
1163 if ( dwErr == ERROR_ALREADY_EXISTS
1164 || dwErr == ERROR_ACCESS_DENIED)
1165 {
1166 VGSvcError("%s is already running! Terminating.\n", g_pszProgName);
1167 return RTEXITCODE_FAILURE;
1168 }
1169
1170 VGSvcError("CreateMutex failed with last error %u! Terminating.\n", GetLastError());
1171 return RTEXITCODE_FAILURE;
1172 }
1173
1174#else /* !RT_OS_WINDOWS */
1175 /** @todo Add PID file creation here? */
1176#endif /* !RT_OS_WINDOWS */
1177
1178 VGSvcVerbose(0, "%s r%s started. Verbose level = %d\n", RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity);
1179
1180 /*
1181 * Daemonize if requested.
1182 */
1183 if (fDaemonize && !fDaemonized)
1184 {
1185#ifdef RT_OS_WINDOWS
1186 VGSvcVerbose(2, "Starting service dispatcher ...\n");
1187 rcExit = VGSvcWinEnterCtrlDispatcher();
1188#else
1189 VGSvcVerbose(1, "Daemonizing...\n");
1190 rc = VbglR3Daemonize(false /* fNoChDir */, false /* fNoClose */,
1191 false /* fRespawn */, NULL /* pcRespawn */);
1192 if (RT_FAILURE(rc))
1193 return VGSvcError("Daemon failed: %Rrc\n", rc);
1194 /* in-child */
1195#endif
1196 }
1197#ifdef RT_OS_WINDOWS
1198 else
1199#endif
1200 {
1201 /*
1202 * Windows: We're running the service as a console application now. Start the
1203 * services, enter the main thread's run loop and stop them again
1204 * when it returns.
1205 *
1206 * POSIX: This is used for both daemons and console runs. Start all services
1207 * and return immediately.
1208 */
1209#ifdef RT_OS_WINDOWS
1210# ifndef RT_OS_NT4 /** @todo r=bird: What's RT_OS_NT4??? */
1211 /* Install console control handler. */
1212 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)vgsvcWinConsoleControlHandler, TRUE /* Add handler */))
1213 {
1214 VGSvcError("Unable to add console control handler, error=%ld\n", GetLastError());
1215 /* Just skip this error, not critical. */
1216 }
1217# endif /* !RT_OS_NT4 */
1218#endif /* RT_OS_WINDOWS */
1219 rc = VGSvcStartServices();
1220 RTFILE hPidFile = NIL_RTFILE;
1221 if (RT_SUCCESS(rc))
1222 if (g_szPidFile[0])
1223 rc = VbglR3PidFile(g_szPidFile, &hPidFile);
1224 rcExit = RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
1225 if (RT_SUCCESS(rc))
1226 VGSvcMainWait();
1227 if (g_szPidFile[0] && hPidFile != NIL_RTFILE)
1228 VbglR3ClosePidFile(g_szPidFile, hPidFile);
1229#ifdef RT_OS_WINDOWS
1230# ifndef RT_OS_NT4
1231 /* Uninstall console control handler. */
1232 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE)NULL, FALSE /* Remove handler */))
1233 {
1234 VGSvcError("Unable to remove console control handler, error=%ld\n", GetLastError());
1235 /* Just skip this error, not critical. */
1236 }
1237# endif /* !RT_OS_NT4 */
1238#else /* !RT_OS_WINDOWS */
1239 /* On Windows - since we're running as a console application - we already stopped all services
1240 * through the console control handler. So only do the stopping of services here on other platforms
1241 * where the break/shutdown/whatever signal was just received. */
1242 VGSvcStopServices();
1243#endif /* RT_OS_WINDOWS */
1244 }
1245 VGSvcReportStatus(VBoxGuestFacilityStatus_Terminated);
1246
1247#ifdef RT_OS_WINDOWS
1248 /*
1249 * Cleanup mutex.
1250 */
1251 CloseHandle(hMutexAppRunning);
1252#endif
1253
1254 VGSvcVerbose(0, "Ended.\n");
1255
1256#ifdef DEBUG
1257 RTCritSectDelete(&g_csLog);
1258 //RTMemTrackerDumpAllToStdOut();
1259#endif
1260
1261 VGSvcLogDestroy();
1262
1263 return rcExit;
1264}
1265
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