VirtualBox

Changeset 102048 in vbox for trunk/src/VBox/Main/src-server


Ignore:
Timestamp:
Nov 9, 2023 7:47:10 PM (16 months ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
160155
Message:

Main/XPCOM: Convert re-spawning VBoxSVC from NSPR to IPRT, bugref:10545

Location:
trunk/src/VBox/Main/src-server/xpcom
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/xpcom/server.cpp

    r98103 r102048  
    3434#include <nsGenericFactory.h>
    3535
    36 #include "prio.h"
    37 #include "prproces.h"
    38 
    3936#include "server.h"
    4037
     
    5249#include <iprt/stream.h>
    5350#include <iprt/path.h>
     51#include <iprt/pipe.h>
     52#include <iprt/process.h>
    5453#include <iprt/timer.h>
    5554#include <iprt/env.h>
     
    572571static nsresult vboxsvcSpawnDaemonByReExec(const char *pszPath, bool fAutoShutdown, const char *pszPidFile)
    573572{
    574     PRFileDesc *readable = nsnull, *writable = nsnull;
    575     PRProcessAttr *attr = nsnull;
    576     nsresult rv = NS_ERROR_FAILURE;
    577     PRFileDesc *devNull;
    578     unsigned args_index = 0;
    579     // The ugly casts are necessary because the PR_CreateProcessDetached has
    580     // a const array of writable strings as a parameter. It won't write. */
    581     char * args[1 + 1 + 2 + 1];
    582     args[args_index++] = (char *)pszPath;
    583     if (fAutoShutdown)
    584         args[args_index++] = (char *)"--auto-shutdown";
    585     if (pszPidFile)
    586     {
    587         args[args_index++] = (char *)"--pidfile";
    588         args[args_index++] = (char *)pszPidFile;
    589     }
    590     args[args_index++] = 0;
    591 
    592     // Use a pipe to determine when the daemon process is in the position
    593     // to actually process requests. The daemon will write "READY" to the pipe.
    594     if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
    595         goto end;
    596     PR_SetFDInheritable(writable, PR_TRUE);
    597 
    598     attr = PR_NewProcessAttr();
    599     if (!attr)
    600         goto end;
    601 
    602     if (PR_ProcessAttrSetInheritableFD(attr, writable, VBOXSVC_STARTUP_PIPE_NAME) != PR_SUCCESS)
    603         goto end;
    604 
    605     devNull = PR_Open("/dev/null", PR_RDWR, 0);
    606     if (!devNull)
    607         goto end;
    608 
    609     PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, devNull);
    610     PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, devNull);
    611     PR_ProcessAttrSetStdioRedirect(attr, PR_StandardError, devNull);
    612 
    613     if (PR_CreateProcessDetached(pszPath, (char * const *)args, nsnull, attr) != PR_SUCCESS)
    614         goto end;
    615 
    616     // Close /dev/null
    617     PR_Close(devNull);
    618     // Close the child end of the pipe to make it the only owner of the
    619     // file descriptor, so that unexpected closing can be detected.
    620     PR_Close(writable);
    621     writable = nsnull;
    622 
    623     char msg[10];
    624     memset(msg, '\0', sizeof(msg));
    625     if (   PR_Read(readable, msg, sizeof(msg)-1) != 5
    626         || strcmp(msg, "READY"))
    627         goto end;
    628 
    629     rv = NS_OK;
    630 
    631 end:
    632     if (readable)
    633         PR_Close(readable);
    634     if (writable)
    635         PR_Close(writable);
    636     if (attr)
    637         PR_DestroyProcessAttr(attr);
    638     return rv;
     573    /*
     574     * Setup an anonymous pipe that we can use to determine when the daemon
     575     * process has started up.  the daemon will write a char to the pipe, and
     576     * when we read it, we'll know to proceed with trying to connect to the
     577     * daemon.
     578     */
     579    RTPIPE hPipeWr = NIL_RTPIPE;
     580    RTPIPE hPipeRd = NIL_RTPIPE;
     581    int vrc = RTPipeCreate(&hPipeRd, &hPipeWr, RTPIPE_C_INHERIT_WRITE);
     582    if (RT_SUCCESS(vrc))
     583    {
     584        char szPipeInheritFd[32]; RT_ZERO(szPipeInheritFd);
     585
     586        unsigned cArgs = 0;
     587        const char *apszArgs[1 + 1 + 2 + 2 + 1];
     588        apszArgs[cArgs++] = pszPath;
     589        if (fAutoShutdown)
     590            apszArgs[cArgs++] = "--auto-shutdown";
     591        if (pszPidFile)
     592        {
     593            apszArgs[cArgs++] = "--pidfile";
     594            apszArgs[cArgs++] = pszPidFile;
     595        }
     596        apszArgs[cArgs++] = "--inherit-startup-pipe";
     597        apszArgs[cArgs++] = &szPipeInheritFd[0];
     598        apszArgs[cArgs++] = NULL;
     599
     600        ssize_t cch = RTStrFormatU32(&szPipeInheritFd[0], sizeof(szPipeInheritFd),
     601                                     (uint32_t)RTPipeToNative(hPipeWr), 10 /*uiBase*/,
     602                                     0 /*cchWidth*/, 0 /*cchPrecision*/, 0 /*fFlags*/);
     603        Assert(cch > 0);
     604
     605        RTHANDLE hStdNil;
     606        hStdNil.enmType = RTHANDLETYPE_FILE;
     607        hStdNil.u.hFile = NIL_RTFILE;
     608
     609        vrc = RTProcCreateEx(pszPath, apszArgs, RTENV_DEFAULT,
     610                             RTPROC_FLAGS_DETACHED, &hStdNil, &hStdNil, &hStdNil,
     611                             NULL /* pszAsUser */, NULL /* pszPassword */, NULL /* pExtraData */,
     612                             NULL /* phProcess */);
     613        if (RT_SUCCESS(vrc))
     614        {
     615            vrc = RTPipeClose(hPipeWr); AssertRC(vrc); RT_NOREF(vrc);
     616            hPipeWr = NIL_RTPIPE;
     617
     618            size_t cbRead = 0;
     619            char msg[10];
     620            memset(msg, '\0', sizeof(msg));
     621            vrc = RTPipeReadBlocking(hPipeRd, &msg[0], sizeof(msg) - 1, &cbRead);
     622            if (   RT_SUCCESS(vrc)
     623                && cbRead == 5
     624                && !strcmp(msg, "READY"))
     625            {
     626                RTPipeClose(hPipeRd);
     627                return NS_OK;
     628            }
     629        }
     630
     631        if (hPipeWr != NIL_RTPIPE)
     632            RTPipeClose(hPipeWr);
     633        RTPipeClose(hPipeRd);
     634    }
     635
     636    return NS_ERROR_FAILURE;
    639637}
    640638
     
    651649    RTPrintf("\n");
    652650    RTPrintf("Options:\n");
    653     RTPrintf("  -a, --automate            Start XPCOM on demand and daemonize.\n");
    654     RTPrintf("  -A, --auto-shutdown       Shuts down service if no longer in use.\n");
    655     RTPrintf("  -d, --daemonize           Starts service in background.\n");
    656     RTPrintf("  -D, --shutdown-delay <ms> Sets shutdown delay in ms.\n");
    657     RTPrintf("  -h, --help                Displays this help.\n");
    658     RTPrintf("  -p, --pidfile <path>      Uses a specific pidfile.\n");
    659     RTPrintf("  -F, --logfile <path>      Uses a specific logfile.\n");
    660     RTPrintf("  -R, --logrotate <count>   Number of old log files to keep.\n");
    661     RTPrintf("  -S, --logsize <bytes>     Maximum size of a log file before rotating.\n");
    662     RTPrintf("  -I, --loginterval <s>     Maximum amount of time to put in a log file.\n");
     651    RTPrintf("  -a, --automate                      Start XPCOM on demand and daemonize.\n");
     652    RTPrintf("  -A, --auto-shutdown                 Shuts down service if no longer in use.\n");
     653    RTPrintf("  -d, --daemonize                     Starts service in background.\n");
     654    RTPrintf("  -D, --shutdown-delay <ms>           Sets shutdown delay in ms.\n");
     655    RTPrintf("  -h, --help                          Displays this help.\n");
     656    RTPrintf("  -p, --pidfile <path>                Uses a specific pidfile.\n");
     657    RTPrintf("  -F, --logfile <path>                Uses a specific logfile.\n");
     658    RTPrintf("  -R, --logrotate <count>             Number of old log files to keep.\n");
     659    RTPrintf("  -S, --logsize <bytes>               Maximum size of a log file before rotating.\n");
     660    RTPrintf("  -I, --loginterval <s>               Maximum amount of time to put in a log file.\n");
     661    RTPrintf("  -P, --inherit-startup-pipe <fd>     The startup pipe file descriptor number when re-starting the daemon\n");
    663662
    664663    RTPrintf("\n");
     
    677676    static const RTGETOPTDEF s_aOptions[] =
    678677    {
    679         { "--automate",         'a', RTGETOPT_REQ_NOTHING },
    680         { "--auto-shutdown",    'A', RTGETOPT_REQ_NOTHING },
    681         { "--daemonize",        'd', RTGETOPT_REQ_NOTHING },
    682         { "--help",             'h', RTGETOPT_REQ_NOTHING },
    683         { "--shutdown-delay",   'D', RTGETOPT_REQ_UINT32 },
    684         { "--pidfile",          'p', RTGETOPT_REQ_STRING },
    685         { "--logfile",          'F', RTGETOPT_REQ_STRING },
    686         { "--logrotate",        'R', RTGETOPT_REQ_UINT32 },
    687         { "--logsize",          'S', RTGETOPT_REQ_UINT64 },
    688         { "--loginterval",      'I', RTGETOPT_REQ_UINT32 }
     678        { "--automate",             'a', RTGETOPT_REQ_NOTHING },
     679        { "--auto-shutdown",        'A', RTGETOPT_REQ_NOTHING },
     680        { "--daemonize",            'd', RTGETOPT_REQ_NOTHING },
     681        { "--help",                 'h', RTGETOPT_REQ_NOTHING },
     682        { "--shutdown-delay",       'D', RTGETOPT_REQ_UINT32 },
     683        { "--pidfile",              'p', RTGETOPT_REQ_STRING },
     684        { "--logfile",              'F', RTGETOPT_REQ_STRING },
     685        { "--logrotate",            'R', RTGETOPT_REQ_UINT32 },
     686        { "--logsize",              'S', RTGETOPT_REQ_UINT64 },
     687        { "--loginterval",          'I', RTGETOPT_REQ_UINT32 },
     688        { "--inherit-startup-pipe", 'P', RTGETOPT_REQ_UINT32 }
    689689    };
    690690
     
    693693    uint32_t        uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file
    694694    uint64_t        uHistoryFileSize = 100 * _1M;   // max 100MB per file
     695    uint32_t        uStartupPipeFd = UINT32_MAX;
    695696    bool            fDaemonize = false;
    696     PRFileDesc      *daemon_pipe_wr = nsnull;
    697697
    698698    RTGETOPTSTATE   GetOptState;
     
    744744            case 'I':
    745745                uHistoryFileTime = ValueUnion.u32;
     746                break;
     747
     748            case 'P':
     749                uStartupPipeFd = ValueUnion.u32;
    746750                break;
    747751
     
    798802    RTStrPrintf(saBuildID, sizeof(saBuildID), "%s%s%s%s VirtualBox %s r%u %s%s%s%s",
    799803                "BU", "IL", "DI", "D", RTBldCfgVersion(), RTBldCfgRevision(), "BU", "IL", "DI", "D");
    800 
    801     daemon_pipe_wr = PR_GetInheritedFD(VBOXSVC_STARTUP_PIPE_NAME);
    802     RTEnvUnset("NSPR_INHERIT_FDS");
    803804
    804805    const nsModuleComponentInfo VirtualBoxInfo = {
     
    903904        }
    904905
    905         if (daemon_pipe_wr != nsnull)
     906        if (uStartupPipeFd == UINT32_MAX)
     907        {
     908            /* Check the environment variable. */
     909            const char *pszStartupPipe = RTEnvGet("VBOX_STARTUP_PIPE_FD");
     910            if (pszStartupPipe)
     911            {
     912                /* Convert it to a number. */
     913                vrc = RTStrToUInt32Full(pszStartupPipe, 0, &uStartupPipeFd);
     914                if (RT_FAILURE(vrc))
     915                {
     916                    RTMsgError("Failed to parse VBOX_STARTUP_PIPE_FD=%s! (rc=%Rrc)", pszStartupPipe, vrc);
     917                    break;
     918                }
     919            }
     920        }
     921        if (uStartupPipeFd != UINT32_MAX)
    906922        {
    907923            RTPrintf("\nStarting event loop....\n[send TERM signal to quit]\n");
    908             /* now we're ready, signal the parent process */
    909             PR_Write(daemon_pipe_wr, RT_STR_TUPLE("READY"));
    910             /* close writing end of the pipe, its job is done */
    911             PR_Close(daemon_pipe_wr);
     924
     925            RTPIPE hPipe = NIL_RTPIPE;
     926            vrc = RTPipeFromNative(&hPipe, (RTHCINTPTR)uStartupPipeFd, RTPIPE_N_WRITE);
     927            if (RT_SUCCESS(vrc))
     928            {
     929                vrc = RTPipeWriteBlocking(hPipe, RT_STR_TUPLE("READY"), NULL /*pcbWritten*/);
     930                AssertRC(vrc); RT_NOREF(vrc);
     931
     932                vrc = RTPipeClose(hPipe);
     933                AssertRC(vrc); RT_NOREF(vrc);
     934            }
    912935        }
    913936        else
  • trunk/src/VBox/Main/src-server/xpcom/server_module.cpp

    r98103 r102048  
    2727
    2828#define LOG_GROUP LOG_GROUP_MAIN_VBOXSVC
    29 #ifdef RT_OS_OS2
    30 # include <prproces.h>
    31 #endif
    32 
    3329#include <nsMemory.h>
    3430#include <nsString.h>
     
    4642
    4743#include "prio.h"
    48 #include "prproces.h"
    4944
    5045// official XPCOM headers don't define it yet
     
    6358#include <iprt/param.h>
    6459#include <iprt/path.h>
     60#include <iprt/pipe.h>
    6561#include <iprt/process.h>
    6662#include <iprt/env.h>
     
    108104static nsresult vboxsvcSpawnDaemon(void)
    109105{
    110     PRFileDesc *readable = nsnull, *writable = nsnull;
    111     PRProcessAttr *attr = nsnull;
    112     nsresult rv = NS_ERROR_FAILURE;
    113     PRFileDesc *devNull;
    114     // The ugly casts are necessary because the PR_CreateProcessDetached has
    115     // a const array of writable strings as a parameter. It won't write. */
    116     char * const args[] = { (char *)VBoxSVCPath, (char *)"--auto-shutdown", 0 };
    117 
    118     // Use a pipe to determine when the daemon process is in the position
    119     // to actually process requests. The daemon will write "READY" to the pipe.
    120     if (PR_CreatePipe(&readable, &writable) != PR_SUCCESS)
    121         goto end;
    122     PR_SetFDInheritable(writable, PR_TRUE);
    123 
    124     attr = PR_NewProcessAttr();
    125     if (!attr)
    126         goto end;
    127 
    128     if (PR_ProcessAttrSetInheritableFD(attr, writable, VBOXSVC_STARTUP_PIPE_NAME) != PR_SUCCESS)
    129         goto end;
    130 
    131     devNull = PR_Open("/dev/null", PR_RDWR, 0);
    132     if (!devNull)
    133         goto end;
    134 
    135     PR_ProcessAttrSetStdioRedirect(attr, PR_StandardInput, devNull);
    136     PR_ProcessAttrSetStdioRedirect(attr, PR_StandardOutput, devNull);
    137     PR_ProcessAttrSetStdioRedirect(attr, PR_StandardError, devNull);
    138 
    139     if (PR_CreateProcessDetached(VBoxSVCPath, args, nsnull, attr) != PR_SUCCESS)
    140         goto end;
    141 
    142     // Close /dev/null
    143     PR_Close(devNull);
    144     // Close the child end of the pipe to make it the only owner of the
    145     // file descriptor, so that unexpected closing can be detected.
    146     PR_Close(writable);
    147     writable = nsnull;
    148 
    149     char msg[10];
    150     RT_ZERO(msg);
    151     if (   PR_Read(readable, msg, sizeof(msg)-1) != 5
    152         || strcmp(msg, "READY"))
     106    /*
     107     * Setup an anonymous pipe that we can use to determine when the daemon
     108     * process has started up.  the daemon will write a char to the pipe, and
     109     * when we read it, we'll know to proceed with trying to connect to the
     110     * daemon.
     111     */
     112    RTPIPE hPipeWr = NIL_RTPIPE;
     113    RTPIPE hPipeRd = NIL_RTPIPE;
     114    int vrc = RTPipeCreate(&hPipeRd, &hPipeWr, RTPIPE_C_INHERIT_WRITE);
     115    if (RT_SUCCESS(vrc))
    153116    {
    154         /* If several clients start VBoxSVC simultaneously only one can
    155          * succeed. So treat this as success as well. */
    156         rv = NS_OK;
    157         goto end;
     117        char szPipeInheritFd[32]; RT_ZERO(szPipeInheritFd);
     118        const char *apszArgs[] =
     119        {
     120            VBoxSVCPath,
     121            "--auto-shutdown",
     122            "--inherit-startup-pipe",
     123            &szPipeInheritFd[0],
     124            NULL
     125        };
     126
     127        ssize_t cch = RTStrFormatU32(&szPipeInheritFd[0], sizeof(szPipeInheritFd),
     128                                     (uint32_t)RTPipeToNative(hPipeWr), 10 /*uiBase*/,
     129                                     0 /*cchWidth*/, 0 /*cchPrecision*/, 0 /*fFlags*/);
     130        Assert(cch > 0);
     131
     132        RTHANDLE hStdNil;
     133        hStdNil.enmType = RTHANDLETYPE_FILE;
     134        hStdNil.u.hFile = NIL_RTFILE;
     135
     136        vrc = RTProcCreateEx(VBoxSVCPath, apszArgs, RTENV_DEFAULT,
     137                             RTPROC_FLAGS_DETACHED, &hStdNil, &hStdNil, &hStdNil,
     138                             NULL /* pszAsUser */, NULL /* pszPassword */, NULL /* pExtraData */,
     139                             NULL /* phProcess */);
     140        if (RT_SUCCESS(vrc))
     141        {
     142            vrc = RTPipeClose(hPipeWr); AssertRC(vrc); RT_NOREF(vrc);
     143            hPipeWr = NIL_RTPIPE;
     144
     145            size_t cbRead = 0;
     146            char msg[10];
     147            memset(msg, '\0', sizeof(msg));
     148            vrc = RTPipeReadBlocking(hPipeRd, &msg[0], sizeof(msg) - 1, &cbRead);
     149            if (   RT_SUCCESS(vrc)
     150                && cbRead == 5
     151                && !strcmp(msg, "READY"))
     152            {
     153                RTPipeClose(hPipeRd);
     154                return NS_OK;
     155            }
     156        }
     157
     158        if (hPipeWr != NIL_RTPIPE)
     159            RTPipeClose(hPipeWr);
     160        RTPipeClose(hPipeRd);
    158161    }
    159162
    160     rv = NS_OK;
    161 
    162 end:
    163     if (readable)
    164         PR_Close(readable);
    165     if (writable)
    166         PR_Close(writable);
    167     if (attr)
    168         PR_DestroyProcessAttr(attr);
    169     return rv;
     163    return NS_ERROR_FAILURE;
    170164}
    171165
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