VirtualBox

Ignore:
Timestamp:
Feb 14, 2012 1:45:25 PM (13 years ago)
Author:
vboxsync
Message:

VBoxService: Added release logging to stdout/file (using --logfile <file>); also can be used when running in SCM (service) mode; fixed error message when VBoxService is already running.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp

    r39843 r40129  
    3636#endif
    3737
     38#include <package-generated.h>
    3839#include "product-generated.h"
     40
    3941#include <iprt/asm.h>
    4042#include <iprt/buildconfig.h>
     
    4547#include <iprt/message.h>
    4648#include <iprt/path.h>
     49#include <iprt/process.h>
    4750#include <iprt/semaphore.h>
    4851#include <iprt/string.h>
    4952#include <iprt/stream.h>
     53#include <iprt/system.h>
    5054#include <iprt/thread.h>
    5155
     
    5963*******************************************************************************/
    6064/** The program name (derived from argv[0]). */
    61 char *g_pszProgName =  (char *)"";
     65char                *g_pszProgName =  (char *)"";
    6266/** The current verbosity level. */
    63 int g_cVerbosity = 0;
     67int                  g_cVerbosity = 0;
     68/** Logging parameters. */
     69/** @todo Make this configurable later. */
     70static PRTLOGGER     g_pLoggerRelease = NULL;
     71static uint32_t      g_cHistory = 10;                   /* Enable log rotation, 10 files. */
     72static uint32_t      g_uHistoryFileTime = RT_SEC_1DAY;  /* Max 1 day per file. */
     73static uint64_t      g_uHistoryFileSize = 100 * _1M;    /* Max 100MB per file. */
    6474/** Critical section for (debug) logging. */
    6575#ifdef DEBUG
    66  RTCRITSECT g_csLog;
     76 RTCRITSECT          g_csLog;
    6777#endif
    6878/** The default service interval (the -i | --interval) option). */
    69 uint32_t g_DefaultInterval = 0;
     79uint32_t             g_DefaultInterval = 0;
    7080#ifdef RT_OS_WINDOWS
    7181/** Signal shutdown to the Windows service thread. */
    7282static bool volatile g_fWindowsServiceShutdown;
    7383/** Event the Windows service thread waits for shutdown. */
    74 static RTSEMEVENT g_hEvtWindowsService;
     84static RTSEMEVENT    g_hEvtWindowsService;
    7585#endif
    7686
     
    127137
    128138/**
     139 * Release logger callback.
     140 *
     141 * @return  IPRT status code.
     142 * @param   pLoggerRelease
     143 * @param   enmPhase
     144 * @param   pfnLog
     145 */
     146static void VBoxServiceLogHeaderFooter(PRTLOGGER pLoggerRelease, RTLOGPHASE enmPhase, PFNRTLOGPHASEMSG pfnLog)
     147{
     148    /* Some introductory information. */
     149    static RTTIMESPEC s_TimeSpec;
     150    char szTmp[256];
     151    if (enmPhase == RTLOGPHASE_BEGIN)
     152        RTTimeNow(&s_TimeSpec);
     153    RTTimeSpecToString(&s_TimeSpec, szTmp, sizeof(szTmp));
     154
     155    switch (enmPhase)
     156    {
     157        case RTLOGPHASE_BEGIN:
     158        {
     159            pfnLog(pLoggerRelease,
     160                   "VBoxService %s r%s (verbosity: %d) %s (%s %s) release log\n"
     161                   "Log opened %s\n",
     162                   RTBldCfgVersion(), RTBldCfgRevisionStr(), g_cVerbosity, VBOX_BUILD_TARGET,
     163                   __DATE__, __TIME__, szTmp);
     164
     165            int vrc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szTmp, sizeof(szTmp));
     166            if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
     167                pfnLog(pLoggerRelease, "OS Product: %s\n", szTmp);
     168            vrc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szTmp, sizeof(szTmp));
     169            if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
     170                pfnLog(pLoggerRelease, "OS Release: %s\n", szTmp);
     171            vrc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szTmp, sizeof(szTmp));
     172            if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
     173                pfnLog(pLoggerRelease, "OS Version: %s\n", szTmp);
     174            if (RT_SUCCESS(vrc) || vrc == VERR_BUFFER_OVERFLOW)
     175                pfnLog(pLoggerRelease, "OS Service Pack: %s\n", szTmp);
     176
     177            /* the package type is interesting for Linux distributions */
     178            char szExecName[RTPATH_MAX];
     179            char *pszExecName = RTProcGetExecutablePath(szExecName, sizeof(szExecName));
     180            pfnLog(pLoggerRelease,
     181                   "Executable: %s\n"
     182                   "Process ID: %u\n"
     183                   "Package type: %s"
     184#ifdef VBOX_OSE
     185                   " (OSE)"
     186#endif
     187                   "\n",
     188                   pszExecName ? pszExecName : "unknown",
     189                   RTProcSelf(),
     190                   VBOX_PACKAGE_STRING);
     191            break;
     192        }
     193
     194        case RTLOGPHASE_PREROTATE:
     195            pfnLog(pLoggerRelease, "Log rotated - Log started %s\n", szTmp);
     196            break;
     197
     198        case RTLOGPHASE_POSTROTATE:
     199            pfnLog(pLoggerRelease, "Log continuation - Log started %s\n", szTmp);
     200            break;
     201
     202        case RTLOGPHASE_END:
     203            pfnLog(pLoggerRelease, "End of log file - Log started %s\n", szTmp);
     204            break;
     205
     206        default:
     207            /* nothing */;
     208    }
     209}
     210
     211
     212/**
     213 * Creates the default release logger outputting to the specified file.
     214 *
     215 * @return  IPRT status code.
     216 * @param   pszLogFile              Filename for log output.  Optional.
     217 */
     218static int VBoxServiceLogCreate(const char *pszLogFile)
     219{
     220    /* Create release logger (stdout + file). */
     221    static const char * const s_apszGroups[] = VBOX_LOGGROUP_NAMES;
     222    RTUINT fFlags = RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG;
     223#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
     224    fFlags |= RTLOGFLAGS_USECRLF;
     225#endif
     226    char szError[RTPATH_MAX + 128] = "";
     227    int rc = RTLogCreateEx(&g_pLoggerRelease, fFlags, "all",
     228                           "VBOXSERVICE_RELEASE_LOG", RT_ELEMENTS(s_apszGroups), s_apszGroups,
     229                           RTLOGDEST_STDOUT,
     230                           VBoxServiceLogHeaderFooter, g_cHistory, g_uHistoryFileSize, g_uHistoryFileTime,
     231                           szError, sizeof(szError), pszLogFile);
     232    if (RT_SUCCESS(rc))
     233    {
     234        /* register this logger as the release logger */
     235        RTLogRelSetDefaultInstance(g_pLoggerRelease);
     236
     237        /* Explicitly flush the log in case of VBOXSERVICE_RELEASE_LOG=buffered. */
     238        RTLogFlush(g_pLoggerRelease);
     239    }
     240
     241    return rc;
     242}
     243
     244static void VBoxServiceLogDestroy(void)
     245{
     246    RTLogDestroy(g_pLoggerRelease);
     247}
     248
     249
     250/**
    129251 * Displays the program usage message.
    130252 *
     
    134256{
    135257    RTPrintf("Usage:\n"
    136              " %-12s [-f|--foreground] [-v|--verbose] [-i|--interval <seconds>]\n"
     258             " %-12s [-f|--foreground] [-v|--verbose] [-l|--logfile <file>]\n"
     259             "              [-i|--interval <seconds>]\n"
    137260             "              [--disable-<service>] [--enable-<service>]\n"
    138261             "              [--only-<service>] [-h|-?|--help]\n", g_pszProgName);
     
    147270             "    -i | --interval         The default interval.\n"
    148271             "    -f | --foreground       Don't daemonize the program. For debugging.\n"
     272             "    -l | --logfile <file>   Enables logging to a file.\n"
    149273             "    -v | --verbose          Increment the verbosity level. For debugging.\n"
    150274             "    -V | --version          Show version information.\n"
     
    174298
    175299/**
    176  * Displays a syntax error message.
    177  *
    178  * @returns RTEXITCODE_SYNTAX.
    179  * @param   pszFormat   The message text.
    180  * @param   ...         Format arguments.
    181  */
    182 RTEXITCODE VBoxServiceSyntax(const char *pszFormat, ...)
    183 {
    184     RTStrmPrintf(g_pStdErr, "%s: syntax error: ", g_pszProgName);
    185 
    186     va_list va;
    187     va_start(va, pszFormat);
    188     RTStrmPrintfV(g_pStdErr, pszFormat, va);
    189     va_end(va);
    190 
    191     return RTEXITCODE_SYNTAX;
    192 }
    193 
    194 
    195 /**
    196300 * Displays an error message.
    197301 *
     
    202306RTEXITCODE VBoxServiceError(const char *pszFormat, ...)
    203307{
    204     RTStrmPrintf(g_pStdErr, "%s: error: ", g_pszProgName);
    205 
    206     va_list va;
    207     va_start(va, pszFormat);
    208     RTStrmPrintfV(g_pStdErr, pszFormat, va);
    209     va_end(va);
    210 
    211     va_start(va, pszFormat);
    212     LogRel(("%s: Error: %N", g_pszProgName, pszFormat, &va));
    213     va_end(va);
     308    va_list args;
     309    va_start(args, pszFormat);
     310    char *psz = NULL;
     311    RTStrAPrintfV(&psz, pszFormat, args);
     312    va_end(args);
     313
     314    AssertPtr(psz);
     315    LogRel(("Error: %s", psz));
     316
     317    RTStrFree(psz);
    214318
    215319    return RTEXITCODE_FAILURE;
     
    220324 * Displays a verbose message.
    221325 *
    222  * @returns 1
    223326 * @param   iLevel      Minimum log level required to display this message.
    224327 * @param   pszFormat   The message text.
     
    233336        if (RT_SUCCESS(rc))
    234337        {
    235             const char *pszThreadName = RTThreadSelfName();
    236             AssertPtr(pszThreadName);
    237             RTStrmPrintf(g_pStdOut, "%s [%s]: ",
    238                          g_pszProgName, pszThreadName);
    239 #else
    240             RTStrmPrintf(g_pStdOut, "%s: ", g_pszProgName);
    241 #endif
    242             va_list va;
    243             va_start(va, pszFormat);
    244             RTStrmPrintfV(g_pStdOut, pszFormat, va);
    245             va_end(va);
    246             va_start(va, pszFormat);
    247             LogRel(("%s: %N", g_pszProgName, pszFormat, &va));
    248             va_end(va);
     338#endif
     339            va_list args;
     340            va_start(args, pszFormat);
     341            char *psz = NULL;
     342            RTStrAPrintfV(&psz, pszFormat, args);
     343            va_end(args);
     344
     345            AssertPtr(psz);
     346            LogRel(("%s", psz));
     347
     348            RTStrFree(psz);
    249349#ifdef DEBUG
    250350            RTCritSectLeave(&g_csLog);
     
    287387/**
    288388 * Gets a 32-bit value argument.
     389 * @todo Get rid of this and VBoxServiceArgString() as soon as we have RTOpt handling.
    289390 *
    290391 * @returns 0 on success, non-zero exit code on error.
     
    304405    {
    305406        if (*pi + 1 >= argc)
    306             return VBoxServiceSyntax("Missing value for the '%s' argument\n", argv[*pi]);
     407            return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing value for the '%s' argument\n", argv[*pi]);
    307408        psz = argv[++*pi];
    308409    }
     
    311412    int rc = RTStrToUInt32Ex(psz, &pszNext, 0, pu32);
    312413    if (RT_FAILURE(rc) || *pszNext)
    313         return VBoxServiceSyntax("Failed to convert interval '%s' to a number.\n", psz);
     414        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Failed to convert interval '%s' to a number\n", psz);
    314415    if (*pu32 < u32Min || *pu32 > u32Max)
    315         return VBoxServiceSyntax("The timesync interval of %RU32 seconds is out of range [%RU32..%RU32].\n",
    316                                  *pu32, u32Min, u32Max);
     416        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The timesync interval of %RU32 seconds is out of range [%RU32..%RU32]\n",
     417                              *pu32, u32Min, u32Max);
    317418    return 0;
    318419}
     420
     421/** @todo Get rid of this and VBoxServiceArgUInt32() as soon as we have RTOpt handling. */
     422int VBoxServiceArgString(int argc, char **argv, const char *psz, int *pi, char *pszBuf, size_t cbBuf)
     423{
     424    AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
     425    AssertPtrReturn(cbBuf, VERR_INVALID_PARAMETER);
     426
     427    if (*psz == ':' || *psz == '=')
     428        psz++;
     429    if (!*psz)
     430    {
     431        if (*pi + 1 >= argc)
     432            return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Missing string for the '%s' argument\n", argv[*pi]);
     433        psz = argv[++*pi];
     434    }
     435
     436    if (!RTStrPrintf(pszBuf, cbBuf, "%s", psz))
     437        return RTMsgErrorExit(RTEXITCODE_FAILURE, "String for '%s' argument too big\n", argv[*pi]);
     438    return 0;
     439}
     440
    319441
    320442
     
    659781    {
    660782        if (rc == VERR_ACCESS_DENIED)
    661             return VBoxServiceError("Insufficient privileges to start %s! Please start with Administrator/root privileges!\n",
     783            return RTMsgErrorExit(RTEXITCODE_FAILURE, "Insufficient privileges to start %s! Please start with Administrator/root privileges!\n",
    662784                                    g_pszProgName);
    663         return VBoxServiceError("VbglR3Init failed with rc=%Rrc.\n", rc);
     785        return RTMsgErrorExit(RTEXITCODE_FAILURE, "VbglR3Init failed with rc=%Rrc\n", rc);
    664786    }
    665787
     
    674796#endif
    675797
     798    char szLogFile[RTPATH_MAX + 128] = "";
     799
    676800    /*
    677801     * Parse the arguments.
     
    685809        const char *psz = argv[i];
    686810        if (*psz != '-')
    687             return VBoxServiceSyntax("Unknown argument '%s'\n", psz);
     811            return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'\n", psz);
    688812        psz++;
    689813
     
    711835                psz = "u";
    712836#endif
     837            else if (MATCHES("logfile"))
     838                psz = "l";
    713839            else if (MATCHES("daemonized"))
    714840            {
     
    732858                if (cch > sizeof("only-") && !memcmp(psz, "only-", sizeof("only-") - 1))
    733859                    for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++)
     860                    {
    734861                        g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName);
     862                        if (g_aServices[j].fEnabled)
     863                            fFound = true;
     864                    }
    735865
    736866                if (!fFound)
     
    739869                    if (rcExit != RTEXITCODE_SUCCESS)
    740870                        return rcExit;
    741 
    742871                    for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++)
    743872                    {
    744873                        rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i);
    745                         fFound = rc == 0;
     874                        fFound = rc == VINF_SUCCESS;
    746875                        if (fFound)
    747876                            break;
     
    751880                }
    752881                if (!fFound)
    753                     return VBoxServiceSyntax("Unknown option '%s'\n", argv[i]);
     882                    return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%s'\n", argv[i]);
    754883                continue;
    755884            }
     
    793922                    return VBoxServiceWinUninstall();
    794923#endif
     924
     925                case 'l':
     926                {
     927                    rc = VBoxServiceArgString(argc, argv, psz + 1, &i,
     928                                              szLogFile, sizeof(szLogFile));
     929                    if (rc)
     930                        return rc;
     931                    psz = NULL;
     932                    break;
     933                }
    795934
    796935                default:
     
    811950                    }
    812951                    if (!fFound)
    813                         return VBoxServiceSyntax("Unknown option '%c' (%s)\n", *psz, argv[i]);
     952                        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%c' (%s)\n", *psz, argv[i]);
    814953                    break;
    815954                }
     
    820959    /* Check that at least one service is enabled. */
    821960    if (vboxServiceCountEnabledServices() == 0)
    822         return VBoxServiceSyntax("At least one service must be enabled.\n");
     961        return RTMsgErrorExit(RTEXITCODE_SYNTAX, "At least one service must be enabled\n");
     962
     963    rc = VBoxServiceLogCreate(strlen(szLogFile) ? szLogFile : NULL);
     964    if (RT_FAILURE(rc))
     965        return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to create release log (%s, %Rrc)",
     966                              strlen(szLogFile) ? szLogFile : "<None>", rc);
    823967
    824968    /* Call pre-init if we didn't do it already. */
     
    851995    if (hMutexAppRunning == NULL)
    852996    {
     997        DWORD dwErr = GetLastError();
     998        if (   dwErr == ERROR_ALREADY_EXISTS
     999            || dwErr == ERROR_ACCESS_DENIED)
     1000        {
     1001            VBoxServiceError("%s is already running! Terminating.", g_pszProgName);
     1002            return RTEXITCODE_FAILURE;
     1003        }
     1004
    8531005        VBoxServiceError("CreateMutex failed with last error %u! Terminating", GetLastError());
    8541006        return RTEXITCODE_FAILURE;
    8551007    }
    856     if (GetLastError() == ERROR_ALREADY_EXISTS)
    857     {
    858         VBoxServiceError("%s is already running! Terminating.", g_pszProgName);
    859         CloseHandle(hMutexAppRunning);
    860         return RTEXITCODE_FAILURE;
    861     }
     1008
    8621009#else  /* !RT_OS_WINDOWS */
    8631010    /** @todo Add PID file creation here? */
     
    9401087    //RTMemTrackerDumpAllToStdOut();
    9411088#endif
     1089
     1090    VBoxServiceLogDestroy();
     1091
    9421092    return rcExit;
    9431093}
Note: See TracChangeset for help on using the changeset viewer.

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