Changeset 40129 in vbox for trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp
- Timestamp:
- Feb 14, 2012 1:45:25 PM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Additions/common/VBoxService/VBoxService.cpp
r39843 r40129 36 36 #endif 37 37 38 #include <package-generated.h> 38 39 #include "product-generated.h" 40 39 41 #include <iprt/asm.h> 40 42 #include <iprt/buildconfig.h> … … 45 47 #include <iprt/message.h> 46 48 #include <iprt/path.h> 49 #include <iprt/process.h> 47 50 #include <iprt/semaphore.h> 48 51 #include <iprt/string.h> 49 52 #include <iprt/stream.h> 53 #include <iprt/system.h> 50 54 #include <iprt/thread.h> 51 55 … … 59 63 *******************************************************************************/ 60 64 /** The program name (derived from argv[0]). */ 61 char *g_pszProgName = (char *)"";65 char *g_pszProgName = (char *)""; 62 66 /** The current verbosity level. */ 63 int g_cVerbosity = 0; 67 int g_cVerbosity = 0; 68 /** Logging parameters. */ 69 /** @todo Make this configurable later. */ 70 static PRTLOGGER g_pLoggerRelease = NULL; 71 static uint32_t g_cHistory = 10; /* Enable log rotation, 10 files. */ 72 static uint32_t g_uHistoryFileTime = RT_SEC_1DAY; /* Max 1 day per file. */ 73 static uint64_t g_uHistoryFileSize = 100 * _1M; /* Max 100MB per file. */ 64 74 /** Critical section for (debug) logging. */ 65 75 #ifdef DEBUG 66 RTCRITSECT g_csLog;76 RTCRITSECT g_csLog; 67 77 #endif 68 78 /** The default service interval (the -i | --interval) option). */ 69 uint32_t g_DefaultInterval = 0;79 uint32_t g_DefaultInterval = 0; 70 80 #ifdef RT_OS_WINDOWS 71 81 /** Signal shutdown to the Windows service thread. */ 72 82 static bool volatile g_fWindowsServiceShutdown; 73 83 /** Event the Windows service thread waits for shutdown. */ 74 static RTSEMEVENT g_hEvtWindowsService;84 static RTSEMEVENT g_hEvtWindowsService; 75 85 #endif 76 86 … … 127 137 128 138 /** 139 * Release logger callback. 140 * 141 * @return IPRT status code. 142 * @param pLoggerRelease 143 * @param enmPhase 144 * @param pfnLog 145 */ 146 static 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 */ 218 static 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 244 static void VBoxServiceLogDestroy(void) 245 { 246 RTLogDestroy(g_pLoggerRelease); 247 } 248 249 250 /** 129 251 * Displays the program usage message. 130 252 * … … 134 256 { 135 257 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" 137 260 " [--disable-<service>] [--enable-<service>]\n" 138 261 " [--only-<service>] [-h|-?|--help]\n", g_pszProgName); … … 147 270 " -i | --interval The default interval.\n" 148 271 " -f | --foreground Don't daemonize the program. For debugging.\n" 272 " -l | --logfile <file> Enables logging to a file.\n" 149 273 " -v | --verbose Increment the verbosity level. For debugging.\n" 150 274 " -V | --version Show version information.\n" … … 174 298 175 299 /** 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 /**196 300 * Displays an error message. 197 301 * … … 202 306 RTEXITCODE VBoxServiceError(const char *pszFormat, ...) 203 307 { 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); 214 318 215 319 return RTEXITCODE_FAILURE; … … 220 324 * Displays a verbose message. 221 325 * 222 * @returns 1223 326 * @param iLevel Minimum log level required to display this message. 224 327 * @param pszFormat The message text. … … 233 336 if (RT_SUCCESS(rc)) 234 337 { 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); 249 349 #ifdef DEBUG 250 350 RTCritSectLeave(&g_csLog); … … 287 387 /** 288 388 * Gets a 32-bit value argument. 389 * @todo Get rid of this and VBoxServiceArgString() as soon as we have RTOpt handling. 289 390 * 290 391 * @returns 0 on success, non-zero exit code on error. … … 304 405 { 305 406 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]); 307 408 psz = argv[++*pi]; 308 409 } … … 311 412 int rc = RTStrToUInt32Ex(psz, &pszNext, 0, pu32); 312 413 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); 314 415 if (*pu32 < u32Min || *pu32 > u32Max) 315 return VBoxServiceSyntax("The timesync interval of %RU32 seconds is out of range [%RU32..%RU32].\n",316 416 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "The timesync interval of %RU32 seconds is out of range [%RU32..%RU32]\n", 417 *pu32, u32Min, u32Max); 317 418 return 0; 318 419 } 420 421 /** @todo Get rid of this and VBoxServiceArgUInt32() as soon as we have RTOpt handling. */ 422 int 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 319 441 320 442 … … 659 781 { 660 782 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", 662 784 g_pszProgName); 663 return VBoxServiceError("VbglR3Init failed with rc=%Rrc.\n", rc);785 return RTMsgErrorExit(RTEXITCODE_FAILURE, "VbglR3Init failed with rc=%Rrc\n", rc); 664 786 } 665 787 … … 674 796 #endif 675 797 798 char szLogFile[RTPATH_MAX + 128] = ""; 799 676 800 /* 677 801 * Parse the arguments. … … 685 809 const char *psz = argv[i]; 686 810 if (*psz != '-') 687 return VBoxServiceSyntax("Unknown argument '%s'\n", psz);811 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown argument '%s'\n", psz); 688 812 psz++; 689 813 … … 711 835 psz = "u"; 712 836 #endif 837 else if (MATCHES("logfile")) 838 psz = "l"; 713 839 else if (MATCHES("daemonized")) 714 840 { … … 732 858 if (cch > sizeof("only-") && !memcmp(psz, "only-", sizeof("only-") - 1)) 733 859 for (unsigned j = 0; j < RT_ELEMENTS(g_aServices); j++) 860 { 734 861 g_aServices[j].fEnabled = !RTStrICmp(psz + sizeof("only-") - 1, g_aServices[j].pDesc->pszName); 862 if (g_aServices[j].fEnabled) 863 fFound = true; 864 } 735 865 736 866 if (!fFound) … … 739 869 if (rcExit != RTEXITCODE_SUCCESS) 740 870 return rcExit; 741 742 871 for (unsigned j = 0; !fFound && j < RT_ELEMENTS(g_aServices); j++) 743 872 { 744 873 rc = g_aServices[j].pDesc->pfnOption(NULL, argc, argv, &i); 745 fFound = rc == 0;874 fFound = rc == VINF_SUCCESS; 746 875 if (fFound) 747 876 break; … … 751 880 } 752 881 if (!fFound) 753 return VBoxServiceSyntax("Unknown option '%s'\n", argv[i]);882 return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown option '%s'\n", argv[i]); 754 883 continue; 755 884 } … … 793 922 return VBoxServiceWinUninstall(); 794 923 #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 } 795 934 796 935 default: … … 811 950 } 812 951 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]); 814 953 break; 815 954 } … … 820 959 /* Check that at least one service is enabled. */ 821 960 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); 823 967 824 968 /* Call pre-init if we didn't do it already. */ … … 851 995 if (hMutexAppRunning == NULL) 852 996 { 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 853 1005 VBoxServiceError("CreateMutex failed with last error %u! Terminating", GetLastError()); 854 1006 return RTEXITCODE_FAILURE; 855 1007 } 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 862 1009 #else /* !RT_OS_WINDOWS */ 863 1010 /** @todo Add PID file creation here? */ … … 940 1087 //RTMemTrackerDumpAllToStdOut(); 941 1088 #endif 1089 1090 VBoxServiceLogDestroy(); 1091 942 1092 return rcExit; 943 1093 }
Note:
See TracChangeset
for help on using the changeset viewer.