Changeset 102048 in vbox for trunk/src/VBox/Main/src-server
- Timestamp:
- Nov 9, 2023 7:47:10 PM (16 months ago)
- svn:sync-xref-src-repo-rev:
- 160155
- 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 34 34 #include <nsGenericFactory.h> 35 35 36 #include "prio.h"37 #include "prproces.h"38 39 36 #include "server.h" 40 37 … … 52 49 #include <iprt/stream.h> 53 50 #include <iprt/path.h> 51 #include <iprt/pipe.h> 52 #include <iprt/process.h> 54 53 #include <iprt/timer.h> 55 54 #include <iprt/env.h> … … 572 571 static nsresult vboxsvcSpawnDaemonByReExec(const char *pszPath, bool fAutoShutdown, const char *pszPidFile) 573 572 { 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; 639 637 } 640 638 … … 651 649 RTPrintf("\n"); 652 650 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"); 663 662 664 663 RTPrintf("\n"); … … 677 676 static const RTGETOPTDEF s_aOptions[] = 678 677 { 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 } 689 689 }; 690 690 … … 693 693 uint32_t uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file 694 694 uint64_t uHistoryFileSize = 100 * _1M; // max 100MB per file 695 uint32_t uStartupPipeFd = UINT32_MAX; 695 696 bool fDaemonize = false; 696 PRFileDesc *daemon_pipe_wr = nsnull;697 697 698 698 RTGETOPTSTATE GetOptState; … … 744 744 case 'I': 745 745 uHistoryFileTime = ValueUnion.u32; 746 break; 747 748 case 'P': 749 uStartupPipeFd = ValueUnion.u32; 746 750 break; 747 751 … … 798 802 RTStrPrintf(saBuildID, sizeof(saBuildID), "%s%s%s%s VirtualBox %s r%u %s%s%s%s", 799 803 "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");803 804 804 805 const nsModuleComponentInfo VirtualBoxInfo = { … … 903 904 } 904 905 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) 906 922 { 907 923 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 } 912 935 } 913 936 else -
trunk/src/VBox/Main/src-server/xpcom/server_module.cpp
r98103 r102048 27 27 28 28 #define LOG_GROUP LOG_GROUP_MAIN_VBOXSVC 29 #ifdef RT_OS_OS230 # include <prproces.h>31 #endif32 33 29 #include <nsMemory.h> 34 30 #include <nsString.h> … … 46 42 47 43 #include "prio.h" 48 #include "prproces.h"49 44 50 45 // official XPCOM headers don't define it yet … … 63 58 #include <iprt/param.h> 64 59 #include <iprt/path.h> 60 #include <iprt/pipe.h> 65 61 #include <iprt/process.h> 66 62 #include <iprt/env.h> … … 108 104 static nsresult vboxsvcSpawnDaemon(void) 109 105 { 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)) 153 116 { 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); 158 161 } 159 162 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; 170 164 } 171 165
Note:
See TracChangeset
for help on using the changeset viewer.