VirtualBox

Changeset 42527 in vbox for trunk


Ignore:
Timestamp:
Aug 2, 2012 11:01:56 AM (13 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
79697
Message:

FE/VBoxAutostart: Refactoring

Location:
trunk/src/VBox/Frontends/VBoxAutostart
Files:
4 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VBoxAutostart/Makefile.kmk

    r41999 r42527  
    2222 VBoxAutostart_TEMPLATE   = VBOXMAINCLIENTEXE
    2323 VBoxAutostart_SOURCES    = \
    24         VBoxAutostart.cpp
     24        VBoxAutostart.cpp \
     25        VBoxAutostartCfg.cpp \
     26        VBoxAutostartStart.cpp \
     27        VBoxAutostartStop.cpp
    2528
    2629include $(FILE_KBUILD_SUB_FOOTER)
  • trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.cpp

    r42386 r42527  
    5858#include <signal.h>
    5959
     60#include "VBoxAutostart.h"
     61
    6062using namespace com;
    6163
    62 /**
    63  * Tokenizer instance data for the config data.
    64  */
    65 typedef struct CFGTOKENIZER
    66 {
    67     /** Config file handle. */
    68     PRTSTREAM hStrmConfig;
    69     /** String buffer for the current line we are operating in. */
    70     char      *pszLine;
    71     /** Size of the string buffer. */
    72     size_t     cbLine;
    73     /** Current position in the line. */
    74     char      *pszLineCurr;
    75     /** Current line in the config file. */
    76     unsigned   iLine;
    77 } CFGTOKENIZER, *PCFGTOKENIZER;
    78 
    79 /**
    80  * VM list entry.
    81  */
    82 typedef struct AUTOSTARTVM
    83 {
    84     /** ID of the VM to start. */
    85     Bstr  strId;
    86     /** Startup delay of the VM. */
    87     ULONG uStartupDelay;
    88 } AUTOSTARTVM;
    89 
    90 static ComPtr<IVirtualBoxClient> g_pVirtualBoxClient = NULL;
    91 static bool                      g_fVerbose    = false;
    92 static ComPtr<IVirtualBox>       g_pVirtualBox = NULL;
    93 static ComPtr<ISession>          g_pSession    = NULL;
     64#if defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) || defined(RT_OS_DARWIN)
     65# define VBOXAUTOSTART_DAEMONIZE
     66#endif
     67
     68ComPtr<IVirtualBoxClient> g_pVirtualBoxClient = NULL;
     69bool                      g_fVerbose    = false;
     70ComPtr<IVirtualBox>       g_pVirtualBox = NULL;
     71ComPtr<ISession>          g_pSession    = NULL;
    9472
    9573/** Logging parameters. */
     
    10583 */
    10684static const RTGETOPTDEF g_aOptions[] = {
    107 #if defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) || defined(RT_OS_DARWIN)
     85#ifdef VBOXAUTOSTART_DAEMONIZE
    10886    { "--background",           'b',                                       RTGETOPT_REQ_NOTHING },
    10987#endif
     
    122100
    123101
    124 static void serviceLog(const char *pszFormat, ...)
     102DECLHIDDEN(void) serviceLog(const char *pszFormat, ...)
    125103{
    126104    va_list args;
     
    133111
    134112    RTStrFree(psz);
    135 }
    136 
    137 #define serviceLogVerbose(a) if (g_fVerbose) { serviceLog a; }
    138 
    139 /**
    140  * Reads the next line from the config stream.
    141  *
    142  * @returns VBox status code.
    143  * @param   pCfgTokenizer    The config tokenizer.
    144  */
    145 static int autostartConfigTokenizerReadNextLine(PCFGTOKENIZER pCfgTokenizer)
    146 {
    147     int rc = VINF_SUCCESS;
    148 
    149     do
    150     {
    151         rc = RTStrmGetLine(pCfgTokenizer->hStrmConfig, pCfgTokenizer->pszLine,
    152                            pCfgTokenizer->cbLine);
    153         if (rc == VERR_BUFFER_OVERFLOW)
    154         {
    155             char *pszTmp;
    156 
    157             pCfgTokenizer->cbLine += 128;
    158             pszTmp = (char *)RTMemRealloc(pCfgTokenizer->pszLine, pCfgTokenizer->cbLine);
    159             if (pszTmp)
    160                 pCfgTokenizer->pszLine = pszTmp;
    161             else
    162                 rc = VERR_NO_MEMORY;
    163         }
    164     } while (rc == VERR_BUFFER_OVERFLOW);
    165 
    166     if (RT_SUCCESS(rc))
    167     {
    168         pCfgTokenizer->iLine++;
    169         pCfgTokenizer->pszLineCurr = pCfgTokenizer->pszLine;
    170     }
    171 
    172     return rc;
    173 }
    174 
    175 /**
    176  * Creates the config tokenizer from the given filename.
    177  *
    178  * @returns VBox status code.
    179  * @param   pszFilename    Config filename.
    180  * @param   ppCfgTokenizer Where to store the pointer to the config tokenizer on
    181  *                         success.
    182  */
    183 static int autostartConfigTokenizerCreate(const char *pszFilename, PCFGTOKENIZER *ppCfgTokenizer)
    184 {
    185     int rc = VINF_SUCCESS;
    186     PCFGTOKENIZER pCfgTokenizer = (PCFGTOKENIZER)RTMemAllocZ(sizeof(CFGTOKENIZER));
    187 
    188     if (pCfgTokenizer)
    189     {
    190         pCfgTokenizer->iLine = 1;
    191         pCfgTokenizer->cbLine = 128;
    192         pCfgTokenizer->pszLine = (char *)RTMemAllocZ(pCfgTokenizer->cbLine);
    193         if (pCfgTokenizer->pszLine)
    194         {
    195             rc = RTStrmOpen(pszFilename, "r", &pCfgTokenizer->hStrmConfig);
    196             if (RT_SUCCESS(rc))
    197                 rc = autostartConfigTokenizerReadNextLine(pCfgTokenizer);
    198         }
    199         else
    200             rc = VERR_NO_MEMORY;
    201     }
    202     else
    203         rc = VERR_NO_MEMORY;
    204 
    205     if (RT_SUCCESS(rc))
    206         *ppCfgTokenizer = pCfgTokenizer;
    207     else if (   RT_FAILURE(rc)
    208              && pCfgTokenizer)
    209     {
    210         if (pCfgTokenizer->pszLine)
    211             RTMemFree(pCfgTokenizer->pszLine);
    212         if (pCfgTokenizer->hStrmConfig)
    213             RTStrmClose(pCfgTokenizer->hStrmConfig);
    214         RTMemFree(pCfgTokenizer);
    215     }
    216 
    217     return rc;
    218 }
    219 
    220 /**
    221  * Destroys the given config tokenizer.
    222  *
    223  * @returns nothing.
    224  * @param   pCfgTokenizer    The config tokenizer to destroy.
    225  */
    226 static void autostartConfigTokenizerDestroy(PCFGTOKENIZER pCfgTokenizer)
    227 {
    228     if (pCfgTokenizer->pszLine)
    229         RTMemFree(pCfgTokenizer->pszLine);
    230     if (pCfgTokenizer->hStrmConfig)
    231         RTStrmClose(pCfgTokenizer->hStrmConfig);
    232     RTMemFree(pCfgTokenizer);
    233 }
    234 
    235 /**
    236  * Read the next token from the config file.
    237  *
    238  * @returns VBox status code.
    239  * @param   pCfgTokenizer    The config tokenizer data.
    240  * @param   ppszToken        Where to store the start to the next token on success.
    241  * @param   pcchToken        Where to store the number of characters of the next token
    242  *                           excluding the \0 terminator on success.
    243  */
    244 static int autostartConfigTokenizerReadNext(PCFGTOKENIZER pCfgTokenizer, const char **ppszToken,
    245                                             size_t *pcchToken)
    246 {
    247     if (!pCfgTokenizer->pszLineCurr)
    248         return VERR_EOF;
    249 
    250     int rc = VINF_SUCCESS;
    251 
    252     for (;;)
    253     {
    254         char *pszTok = pCfgTokenizer->pszLineCurr;
    255 
    256         /* Skip all spaces. */
    257         while (RT_C_IS_BLANK(*pszTok))
    258             pszTok++;
    259 
    260         /* Check if we have to read a new line. */
    261         if (   *pszTok == '\0'
    262             || *pszTok == '#')
    263         {
    264             rc = autostartConfigTokenizerReadNextLine(pCfgTokenizer);
    265             if (RT_FAILURE(rc))
    266                 break;
    267             /* start from the beginning. */
    268         }
    269         else if (   *pszTok == '='
    270                  || *pszTok == ',')
    271         {
    272             *ppszToken = pszTok;
    273             *pcchToken = 1;
    274             pCfgTokenizer->pszLineCurr = pszTok + 1;
    275             break;
    276         }
    277         else
    278         {
    279             /* Get the complete token. */
    280             size_t cchToken = 1;
    281             char *pszTmp = pszTok + 1;
    282 
    283             while (   RT_C_IS_ALNUM(*pszTmp)
    284                    || *pszTmp == '_')
    285             {
    286                 pszTmp++;
    287                 cchToken++;
    288             }
    289 
    290             *ppszToken = pszTok;
    291             *pcchToken = cchToken;
    292             pCfgTokenizer->pszLineCurr = pszTmp;
    293             break;
    294         }
    295     }
    296 
    297     return rc;
    298 }
    299 
    300 static int autostartConfigTokenizerCheckAndConsume(PCFGTOKENIZER pCfgTokenizer, const char *pszTokCheck)
    301 {
    302     int rc = VINF_SUCCESS;
    303     const char *pszToken = NULL;
    304     size_t cchToken = 0;
    305 
    306     rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken, &cchToken);
    307     if (RT_SUCCESS(rc))
    308     {
    309         if (RTStrNCmp(pszToken, pszTokCheck, cchToken))
    310         {
    311             RTMsgError("Unexpected token at line %d, expected '%s'",
    312                        pCfgTokenizer->iLine, pszTokCheck);
    313             rc = VERR_INVALID_PARAMETER;
    314         }
    315     }
    316     return rc;
    317 }
    318 
    319 /**
    320  * Returns the start of the next token without consuming it.
    321  *
    322  * @returns VBox status code.
    323  * @param   pCfgTokenizer    Tokenizer instance data.
    324  * @param   ppszTok          Where to store the start of the next token on success.
    325  */
    326 static int autostartConfigTokenizerPeek(PCFGTOKENIZER pCfgTokenizer, const char **ppszTok)
    327 {
    328     int rc = VINF_SUCCESS;
    329 
    330     for (;;)
    331     {
    332         char *pszTok = pCfgTokenizer->pszLineCurr;
    333 
    334         /* Skip all spaces. */
    335         while (RT_C_IS_BLANK(*pszTok))
    336             pszTok++;
    337 
    338         /* Check if we have to read a new line. */
    339         if (   *pszTok == '\0'
    340             || *pszTok == '#')
    341         {
    342             rc = autostartConfigTokenizerReadNextLine(pCfgTokenizer);
    343             if (RT_FAILURE(rc))
    344                 break;
    345             /* start from the beginning. */
    346         }
    347         else
    348         {
    349             *ppszTok = pszTok;
    350             break;
    351         }
    352     }
    353 
    354     return rc;
    355 }
    356 
    357 /**
    358  * Check whether the given token is a reserved token.
    359  *
    360  * @returns true if the token is reserved or false otherwise.
    361  * @param   pszToken    The token to check.
    362  * @param   cchToken    Size of the token in characters.
    363  */
    364 static bool autostartConfigTokenizerIsReservedToken(const char *pszToken, size_t cchToken)
    365 {
    366     if (   cchToken == 1
    367         && (   *pszToken == ','
    368             || *pszToken == '='))
    369         return true;
    370     else if (   cchToken > 1
    371              && (   !RTStrNCmp(pszToken, "default_policy", cchToken)
    372                  || !RTStrNCmp(pszToken, "exception_list", cchToken)))
    373         return true;
    374 
    375     return false;
    376 }
    377 
    378 /**
    379  * Parse the given configuration file and return the interesting config parameters.
    380  *
    381  * @returns VBox status code.
    382  * @param   pszFilename    The config file to parse.
    383  * @param   pfAllowed      Where to store the flag whether the user of this process
    384  *                         is allowed to start VMs automatically during system startup.
    385  * @param   puStartupDelay Where to store the startup delay for the user.
    386  */
    387 static int autostartParseConfig(const char *pszFilename, bool *pfAllowed, uint32_t *puStartupDelay)
    388 {
    389     int rc = VINF_SUCCESS;
    390     char *pszUserProcess = NULL;
    391     bool fDefaultAllow = false;
    392     bool fInExceptionList = false;
    393 
    394     AssertPtrReturn(pfAllowed, VERR_INVALID_POINTER);
    395     AssertPtrReturn(puStartupDelay, VERR_INVALID_POINTER);
    396 
    397     *pfAllowed = false;
    398     *puStartupDelay = 0;
    399 
    400     rc = RTProcQueryUsernameA(RTProcSelf(), &pszUserProcess);
    401     if (RT_SUCCESS(rc))
    402     {
    403         PCFGTOKENIZER pCfgTokenizer = NULL;
    404 
    405         rc = autostartConfigTokenizerCreate(pszFilename, &pCfgTokenizer);
    406         if (RT_SUCCESS(rc))
    407         {
    408             do
    409             {
    410                 size_t cchToken = 0;
    411                 const char *pszToken = NULL;
    412 
    413                 rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken,
    414                                                       &cchToken);
    415                 if (RT_SUCCESS(rc))
    416                 {
    417                     if (!RTStrNCmp(pszToken, "default_policy", strlen("default_policy")))
    418                     {
    419                         rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, "=");
    420                         if (RT_SUCCESS(rc))
    421                         {
    422                             rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken,
    423                                                                   &cchToken);
    424                             if (RT_SUCCESS(rc))
    425                             {
    426                                 if (!RTStrNCmp(pszToken, "allow", strlen("allow")))
    427                                     fDefaultAllow = true;
    428                                 else if (!RTStrNCmp(pszToken, "deny", strlen("deny")))
    429                                     fDefaultAllow = false;
    430                                 else
    431                                 {
    432                                     RTMsgError("Unexpected token at line %d, expected either 'allow' or 'deny'",
    433                                                pCfgTokenizer->iLine);
    434                                     rc = VERR_INVALID_PARAMETER;
    435                                     break;
    436                                 }
    437                             }
    438                         }
    439                     }
    440                     else if (!RTStrNCmp(pszToken, "exception_list", strlen("exception_list")))
    441                     {
    442                         rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, "=");
    443                         if (RT_SUCCESS(rc))
    444                         {
    445                             rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken,
    446                                                                   &cchToken);
    447 
    448                             while (RT_SUCCESS(rc))
    449                             {
    450                                 if (autostartConfigTokenizerIsReservedToken(pszToken, cchToken))
    451                                 {
    452                                     RTMsgError("Unexpected token at line %d, expected a username",
    453                                                pCfgTokenizer->iLine);
    454                                     rc = VERR_INVALID_PARAMETER;
    455                                     break;
    456                                 }
    457                                 else if (!RTStrNCmp(pszUserProcess, pszToken, strlen(pszUserProcess)))
    458                                     fInExceptionList = true;
    459 
    460                                 /* Skip , */
    461                                 rc = autostartConfigTokenizerPeek(pCfgTokenizer, &pszToken);
    462                                 if (   RT_SUCCESS(rc)
    463                                     && *pszToken == ',')
    464                                 {
    465                                     rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, ",");
    466                                     AssertRC(rc);
    467                                 }
    468                                 else if (RT_SUCCESS(rc))
    469                                     break;
    470 
    471                                 rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken,
    472                                                                       &cchToken);
    473                             }
    474 
    475                             if (rc == VERR_EOF)
    476                                 rc = VINF_SUCCESS;
    477                         }
    478                     }
    479                     else if (!autostartConfigTokenizerIsReservedToken(pszToken, cchToken))
    480                     {
    481                         /* Treat as 'username = <base delay in seconds>. */
    482                         rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, "=");
    483                         if (RT_SUCCESS(rc))
    484                         {
    485                             size_t cchDelay = 0;
    486                             const char *pszDelay = NULL;
    487 
    488                             rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszDelay,
    489                                                                   &cchDelay);
    490                             if (RT_SUCCESS(rc))
    491                             {
    492                                 uint32_t uDelay = 0;
    493 
    494                                 rc = RTStrToUInt32Ex(pszDelay, NULL, 10, &uDelay);
    495                                 if (rc == VWRN_TRAILING_SPACES)
    496                                     rc = VINF_SUCCESS;
    497 
    498                                 if (   RT_SUCCESS(rc)
    499                                     && !RTStrNCmp(pszUserProcess, pszToken, strlen(pszUserProcess)))
    500                                         *puStartupDelay = uDelay;
    501 
    502                                 if (RT_FAILURE(rc))
    503                                     RTMsgError("Unexpected token at line %d, expected a number",
    504                                                pCfgTokenizer->iLine);
    505                             }
    506                         }
    507                     }
    508                     else
    509                     {
    510                         RTMsgError("Unexpected token at line %d, expected a username",
    511                                    pCfgTokenizer->iLine);
    512                         rc = VERR_INVALID_PARAMETER;
    513                     }
    514                 }
    515                 else if (rc == VERR_EOF)
    516                 {
    517                     rc = VINF_SUCCESS;
    518                     break;
    519                 }
    520             } while (RT_SUCCESS(rc));
    521 
    522             if (   RT_SUCCESS(rc)
    523                 && (   (fDefaultAllow && !fInExceptionList)
    524                     || (!fDefaultAllow && fInExceptionList)))
    525                 *pfAllowed= true;
    526 
    527             autostartConfigTokenizerDestroy(pCfgTokenizer);
    528         }
    529 
    530         RTStrFree(pszUserProcess);
    531     }
    532 
    533     return rc;
    534 }
    535 
    536 static DECLCALLBACK(bool) autostartVMCmp(const AUTOSTARTVM &vm1, const AUTOSTARTVM &vm2)
    537 {
    538     return vm1.uStartupDelay <= vm2.uStartupDelay;
    539 }
    540 
    541 /**
    542  * Main routine for the autostart daemon.
    543  *
    544  * @returns exit status code.
    545  */
    546 static RTEXITCODE autostartMain(uint32_t uStartupDelay)
    547 {
    548     RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
    549     int vrc = VINF_SUCCESS;
    550     std::list<AUTOSTARTVM> listVM;
    551 
    552     if (uStartupDelay)
    553     {
    554         serviceLogVerbose(("Delay starting for %d seconds ...\n", uStartupDelay));
    555         vrc = RTThreadSleep(uStartupDelay * 1000);
    556     }
    557 
    558     if (vrc == VERR_INTERRUPTED)
    559         return RTEXITCODE_SUCCESS;
    560 
    561     /*
    562      * Build a list of all VMs we need to autostart first, apply the overrides
    563      * from the configuration and start the VMs afterwards.
    564      */
    565     com::SafeIfaceArray<IMachine> machines;
    566     HRESULT rc = g_pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(machines));
    567     if (SUCCEEDED(rc))
    568     {
    569         /*
    570          * Iterate through the collection
    571          */
    572         for (size_t i = 0; i < machines.size(); ++i)
    573         {
    574             if (machines[i])
    575             {
    576                 BOOL fAccessible;
    577                 CHECK_ERROR_BREAK(machines[i], COMGETTER(Accessible)(&fAccessible));
    578                 if (!fAccessible)
    579                     continue;
    580 
    581                 BOOL fAutostart;
    582                 CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostartEnabled)(&fAutostart));
    583                 if (fAutostart)
    584                 {
    585                     AUTOSTARTVM autostartVM;
    586 
    587                     CHECK_ERROR_BREAK(machines[i], COMGETTER(Id)(autostartVM.strId.asOutParam()));
    588                     CHECK_ERROR_BREAK(machines[i], COMGETTER(AutostartDelay)(&autostartVM.uStartupDelay));
    589 
    590                     listVM.push_back(autostartVM);
    591                 }
    592             }
    593         }
    594 
    595         if (   SUCCEEDED(rc)
    596             && listVM.size())
    597         {
    598             ULONG uDelayCurr = 0;
    599 
    600             /* Sort by startup delay and apply base override. */
    601             listVM.sort(autostartVMCmp);
    602 
    603             std::list<AUTOSTARTVM>::iterator it;
    604             for (it = listVM.begin(); it != listVM.end(); it++)
    605             {
    606                 ComPtr<IMachine> machine;
    607                 ComPtr<IProgress> progress;
    608 
    609                 if ((*it).uStartupDelay > uDelayCurr)
    610                 {
    611                     serviceLogVerbose(("Delay starting of the next VMs for %d seconds ...\n",
    612                                        (*it).uStartupDelay - uDelayCurr));
    613                     RTThreadSleep(((*it).uStartupDelay - uDelayCurr) * 1000);
    614                     uDelayCurr = (*it).uStartupDelay;
    615                 }
    616 
    617                 CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine((*it).strId.raw(),
    618                                                              machine.asOutParam()));
    619 
    620                 CHECK_ERROR_BREAK(machine, LaunchVMProcess(g_pSession, Bstr("headless").raw(),
    621                                                            Bstr("").raw(), progress.asOutParam()));
    622                 if (SUCCEEDED(rc) && !progress.isNull())
    623                 {
    624                     serviceLogVerbose(("Waiting for VM \"%ls\" to power on...\n", (*it).strId.raw()));
    625                     CHECK_ERROR(progress, WaitForCompletion(-1));
    626                     if (SUCCEEDED(rc))
    627                     {
    628                         BOOL completed = true;
    629                         CHECK_ERROR(progress, COMGETTER(Completed)(&completed));
    630                         if (SUCCEEDED(rc))
    631                         {
    632                             ASSERT(completed);
    633 
    634                             LONG iRc;
    635                             CHECK_ERROR(progress, COMGETTER(ResultCode)(&iRc));
    636                             if (SUCCEEDED(rc))
    637                             {
    638                                 if (FAILED(iRc))
    639                                 {
    640                                     ProgressErrorInfo info(progress);
    641                                     com::GluePrintErrorInfo(info);
    642                                 }
    643                                 else
    644                                     serviceLogVerbose(("VM \"%ls\" has been successfully started.\n", (*it).strId.raw()));
    645                             }
    646                         }
    647                     }
    648                 }
    649                 g_pSession->UnlockMachine();
    650             }
    651         }
    652     }
    653 
    654     return rcExit;
    655113}
    656114
     
    703161                break;
    704162
    705 #if defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) || defined(RT_OS_DARWIN)
     163#ifdef VBOXAUTOSTART_DAEMONIZE
    706164            case 'b':
    707165                pcszDescr = "Run in background (daemon mode).";
     
    807265                break;
    808266
    809 #if defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) || defined(RT_OS_DARWIN)
     267#ifdef VBOXAUTOSTART_DAEMONIZE
    810268            case 'b':
    811269                g_fDaemonize = true;
     
    901359        return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", szError, rc);
    902360
    903 #if defined(RT_OS_LINUX) || defined (RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) || defined(RT_OS_DARWIN)
     361#ifdef VBOXAUTOSTART_DAEMONIZE
    904362    if (g_fDaemonize)
    905363    {
     
    969427        return RTEXITCODE_FAILURE;
    970428
    971     RTEXITCODE rcExit = autostartMain(uStartupDelay);
     429    RTEXITCODE rcExit;
     430    if (fStart)
     431        rcExit = autostartStartMain(uStartupDelay);
     432    else
     433    {
     434        Assert(fStop);
     435        rcExit = autostartStopMain(uStartupDelay);
     436    }
    972437
    973438    EventQueue::getMainEventQueue()->processEventQueue(0);
Note: See TracChangeset for help on using the changeset viewer.

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