Changeset 107985 in vbox for trunk/src/VBox/GuestHost/installation/VBoxWinDrvInst.cpp
- Timestamp:
- Jan 30, 2025 10:01:07 AM (3 months ago)
- svn:sync-xref-src-repo-rev:
- 167248
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/GuestHost/installation/VBoxWinDrvInst.cpp
r107973 r107985 51 51 #include <iprt/string.h> 52 52 #include <iprt/system.h> 53 #include <iprt/thread.h> /* For RTThreadSleep(). */ 53 54 #include <iprt/utf16.h> 54 55 … … 2284 2285 } 2285 2286 2287 /** 2288 * Controls a Windows service, internal version. 2289 * 2290 * @returns VBox status code. 2291 * @param hDrvInst Windows driver installer handle to use. 2292 * @param pszService Name of service to control. 2293 * @param enmFn Service control function to use. 2294 * VBOXWINDRVSVCFN_RESTART is not implemented and must be composed of 2295 * VBOXWINDRVSVCFN_START + VBOXWINDRVSVCFN_STOP by the caller. 2296 * @param fFlags Service control flags (of type VBOXWINDRVSVCFN_F_XXX) to use. 2297 * @param msTimeout Timeout (in ms) to use. Only being used if VBOXWINDRVSVCFN_F_WAIT is specified in \a fFlags. 2298 */ 2299 static int vbooxWinDrvInstControlServiceEx(PVBOXWINDRVINSTINTERNAL pCtx, 2300 const char *pszService, VBOXWINDRVSVCFN enmFn, uint32_t fFlags, RTMSINTERVAL msTimeout) 2301 { 2302 AssertPtrReturn(pszService, VERR_INVALID_POINTER); 2303 AssertReturn(!(fFlags & ~VBOXWINDRVSVCFN_F_VALID_MASK), VERR_INVALID_PARAMETER); 2304 AssertReturn(enmFn > VBOXWINDRVSVCFN_INVALID && enmFn < VBOXWINDRVSVCFN_END, VERR_INVALID_PARAMETER); 2305 AssertReturn(msTimeout == RT_INDEFINITE_WAIT || msTimeout, VERR_INVALID_PARAMETER); 2306 2307 PRTUTF16 pwszService; 2308 int rc = RTStrToUtf16(pszService, &pwszService); 2309 if (RT_FAILURE(rc)) 2310 return rc; 2311 2312 SC_HANDLE hSvc = NULL; 2313 SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); 2314 if (hSCM != NULL) 2315 { 2316 hSvc = OpenServiceW(hSCM, pwszService, SERVICE_ALL_ACCESS | SERVICE_QUERY_STATUS); 2317 if (hSvc == NULL) 2318 { 2319 rc = RTErrConvertFromWin32(GetLastError()); 2320 if (rc == VERR_NOT_FOUND) 2321 vboxWinDrvInstLogError(pCtx, "Service '%s' not found", pszService); 2322 else 2323 rc = vboxWinDrvInstLogLastError(pCtx, "Opening service '%s' failed", pszService); 2324 } 2325 } 2326 else 2327 rc = vboxWinDrvInstLogLastError(pCtx, "Opening Service Control Manager (SCM) failed"); 2328 2329 if (RT_FAILURE(rc)) 2330 { 2331 RTUtf16Free(pwszService); 2332 if (hSvc) 2333 CloseServiceHandle(hSvc); 2334 if (hSCM) 2335 CloseServiceHandle(hSCM); 2336 return rc; 2337 } 2338 2339 SERVICE_STATUS_PROCESS enmSvcSts; 2340 2341 switch (enmFn) 2342 { 2343 case VBOXWINDRVSVCFN_START: 2344 { 2345 if (!StartService(hSvc, 0, NULL)) 2346 { 2347 if (GetLastError() == ERROR_SERVICE_ALREADY_RUNNING) 2348 break; 2349 2350 /** @todo Also handle disabled services here? */ 2351 2352 rc = vboxWinDrvInstLogLastError(pCtx, "Starting service '%s' failed", pszService); 2353 } 2354 else 2355 vboxWinDrvInstLogInfo(pCtx, "Starting service '%s' ...", pszService); 2356 break; 2357 } 2358 2359 case VBOXWINDRVSVCFN_STOP: 2360 { 2361 if (!ControlService(hSvc, SERVICE_CONTROL_STOP, (LPSERVICE_STATUS)&enmSvcSts)) 2362 { 2363 DWORD const dwErr = GetLastError(); 2364 2365 /* A not active or disabled service is not an error, so just skip. */ 2366 if ( dwErr == ERROR_SERVICE_DISABLED 2367 || dwErr == ERROR_SERVICE_NOT_ACTIVE) 2368 break; 2369 2370 rc = vboxWinDrvInstLogLastError(pCtx, "Stopping service '%s' failed", pszService); 2371 } 2372 else 2373 vboxWinDrvInstLogInfo(pCtx, "Stopping service '%s' ...", pszService); 2374 break; 2375 } 2376 2377 default: 2378 AssertFailedStmt(rc = VERR_NOT_SUPPORTED); 2379 break; 2380 } 2381 2382 if ( RT_SUCCESS(rc) 2383 && (fFlags & VBOXWINDRVSVCFN_F_WAIT)) 2384 { 2385 uint64_t const msStartTS = RTTimeMilliTS(); 2386 2387 rc = VERR_NO_CHANGE; /* No change yet. */ 2388 2389 vboxWinDrvInstLogInfo(pCtx, "Waiting for status change of service '%s' ...", pszService); 2390 for (;;) 2391 { 2392 DWORD dwBytes; 2393 if (!QueryServiceStatusEx(hSvc, 2394 SC_STATUS_PROCESS_INFO, 2395 (LPBYTE)&enmSvcSts, 2396 sizeof(SERVICE_STATUS_PROCESS), 2397 &dwBytes)) 2398 { 2399 rc = vboxWinDrvInstLogLastError(pCtx, "Failed to query service status"); 2400 break; 2401 } 2402 2403 if ((RTTimeMilliTS() - msStartTS) % RT_MS_1SEC == 0) /* Don't spam. */ 2404 vboxWinDrvInstLogVerbose(pCtx, 3, "Service '%s' status is %#x: %u", 2405 pszService, enmSvcSts.dwCurrentState, (RTTimeMilliTS() - msStartTS) % 100 == 0); 2406 2407 switch (enmSvcSts.dwCurrentState) 2408 { 2409 case SERVICE_STOP_PENDING: 2410 case SERVICE_START_PENDING: 2411 RTThreadSleep(100); /* Wait a bit before retrying. */ 2412 break; 2413 2414 case SERVICE_RUNNING: 2415 { 2416 if (enmFn == VBOXWINDRVSVCFN_START) 2417 rc = VINF_SUCCESS; 2418 break; 2419 } 2420 2421 case SERVICE_STOPPED: 2422 { 2423 if (enmFn == VBOXWINDRVSVCFN_START) 2424 { 2425 vboxWinDrvInstLogError(pCtx, "Service '%s' stopped unexpectedly", pszService); 2426 rc = VERR_INVALID_STATE; 2427 } 2428 else 2429 rc = VINF_SUCCESS; 2430 break; 2431 } 2432 2433 default: 2434 { 2435 vboxWinDrvInstLogError(pCtx, "Service '%s' reported an unexpected state (%#x)", 2436 pszService, enmSvcSts.dwCurrentState); 2437 rc = VERR_INVALID_STATE; 2438 } 2439 } 2440 2441 if ( RT_FAILURE(rc) 2442 && rc != VERR_NO_CHANGE) 2443 break; 2444 2445 if (RT_SUCCESS(rc)) 2446 break; 2447 2448 if (RTTimeMilliTS() - msStartTS >= msTimeout) 2449 { 2450 vboxWinDrvInstLogError(pCtx, "Waiting for service '%s' timed out (%ums)", pszService, msTimeout); 2451 rc = VERR_TIMEOUT; 2452 break; 2453 } 2454 } 2455 2456 if (RT_SUCCESS(rc)) 2457 vboxWinDrvInstLogInfo(pCtx, "Service '%s' successfully %s", 2458 pszService, enmFn == VBOXWINDRVSVCFN_START ? "started" : "stopped"); 2459 } 2460 else 2461 vboxWinDrvInstLogVerbose(pCtx, 1, "Service '%s' was %s asynchronously", 2462 pszService, enmFn == VBOXWINDRVSVCFN_START ? "started" : "stopped"); 2463 2464 RTUtf16Free(pwszService); 2465 CloseServiceHandle(hSvc); 2466 CloseServiceHandle(hSCM); 2467 return rc; 2468 } 2469 2470 /** 2471 * Controls a Windows service, extended version. 2472 * 2473 * @returns VBox status code. 2474 * @param hDrvInst Windows driver installer handle to use. 2475 * @param pszService Name of service to control. 2476 * @param enmFn Service control function to use. 2477 * @param fFlags Service control flags (of type VBOXWINDRVSVCFN_F_XXX) to use. 2478 * @param msTimeout Timeout (in ms) to use. Only being used if VBOXWINDRVSVCFN_F_WAIT is specified in \a fFlags. 2479 */ 2480 int VBooxWinDrvInstControlServiceEx(VBOXWINDRVINST hDrvInst, 2481 const char *pszService, VBOXWINDRVSVCFN enmFn, uint32_t fFlags, RTMSINTERVAL msTimeout) 2482 { 2483 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst; 2484 VBOXWINDRVINST_VALID_RETURN(pCtx); 2485 2486 #define CONTROL_SERVICE(a_Fn) \ 2487 vbooxWinDrvInstControlServiceEx(pCtx, pszService, a_Fn, fFlags, msTimeout); 2488 2489 int rc; 2490 if (enmFn == VBOXWINDRVSVCFN_RESTART) 2491 { 2492 rc = CONTROL_SERVICE(VBOXWINDRVSVCFN_STOP); 2493 if (RT_SUCCESS(rc)) 2494 rc = CONTROL_SERVICE(VBOXWINDRVSVCFN_START); 2495 } 2496 else 2497 rc = CONTROL_SERVICE(enmFn); 2498 2499 #undef CONTROL_SERVICE 2500 return rc; 2501 } 2502 2503 /** 2504 * Controls a Windows service. 2505 * 2506 * @returns VBox status code. 2507 * @param hDrvInst Windows driver installer handle to use. 2508 * @param pszService Name of service to control. 2509 * @param enmFn Service control function to use. 2510 * 2511 * @note Function waits 30s for the service to reach the desired control function. 2512 * Use VBooxWinDrvInstControlServiceEx() for more flexibility. 2513 */ 2514 int VBoxWinDrvInstControlService(VBOXWINDRVINST hDrvInst, const char *pszService, VBOXWINDRVSVCFN enmFn) 2515 { 2516 PVBOXWINDRVINSTINTERNAL pCtx = hDrvInst; 2517 VBOXWINDRVINST_VALID_RETURN(pCtx); 2518 2519 return VBooxWinDrvInstControlServiceEx(pCtx, pszService, enmFn, VBOXWINDRVSVCFN_F_WAIT, RT_MS_30SEC); 2520 } 2521 2286 2522 #ifdef TESTCASE 2287 2523 /**
Note:
See TracChangeset
for help on using the changeset viewer.