- Timestamp:
- Jul 11, 2012 7:43:11 PM (13 years ago)
- Location:
- trunk/src/VBox
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.cpp
r42001 r42118 50 50 #include <iprt/system.h> 51 51 #include <iprt/time.h> 52 #include <iprt/ctype.h> 52 53 53 54 … … 60 61 61 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 /** 62 80 * VM list entry. 63 81 */ 64 82 typedef struct AUTOSTARTVM 65 83 { 84 /** ID of the VM to start. */ 66 85 Bstr strId; 86 /** Startup delay of the VM. */ 67 87 ULONG uStartupDelay; 68 88 } AUTOSTARTVM; … … 117 137 #define serviceLogVerbose(a) if (g_fVerbose) { serviceLog a; } 118 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 119 536 static DECLCALLBACK(bool) autostartVMCmp(const AUTOSTARTVM &vm1, const AUTOSTARTVM &vm2) 120 537 { … … 127 544 * @returns exit status code. 128 545 */ 129 static RTEXITCODE autostartMain( void)546 static RTEXITCODE autostartMain(uint32_t uStartupDelay) 130 547 { 131 548 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 549 int vrc = VINF_SUCCESS; 132 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; 133 560 134 561 /* … … 169 596 && listVM.size()) 170 597 { 598 ULONG uDelayCurr = 0; 599 171 600 /* Sort by startup delay and apply base override. */ 172 601 listVM.sort(autostartVMCmp); … … 178 607 ComPtr<IProgress> progress; 179 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 180 617 CHECK_ERROR_BREAK(g_pVirtualBox, FindMachine((*it).strId.raw(), 181 618 machine.asOutParam())); … … 185 622 if (SUCCEEDED(rc) && !progress.isNull()) 186 623 { 187 RTPrintf("Waiting for VM \"%ls\" to power on...\n", (*it).strId.raw());624 serviceLogVerbose(("Waiting for VM \"%ls\" to power on...\n", (*it).strId.raw())); 188 625 CHECK_ERROR(progress, WaitForCompletion(-1)); 189 626 if (SUCCEEDED(rc)) … … 205 642 } 206 643 else 207 { 208 RTPrintf("VM \"%ls\" has been successfully started.\n", (*it).strId.raw()); 209 } 644 serviceLogVerbose(("VM \"%ls\" has been successfully started.\n", (*it).strId.raw())); 210 645 } 211 646 } … … 273 708 break; 274 709 #endif 275 case 'P':276 pcszDescr = "Name of the PID file which is created when the daemon was started.";277 break;278 710 279 711 case 'F': … … 427 859 } 428 860 861 if (!pszConfigFile) 862 { 863 displayHelp(argv[0]); 864 return RTMsgErrorExit(RTEXITCODE_FAILURE, "--config <config file> is missing"); 865 } 866 429 867 if (!fQuiet) 430 868 displayHeader(); 869 870 bool fAllowed = false; 871 uint32_t uStartupDelay = 0; 872 rc = autostartParseConfig(pszConfigFile, &fAllowed, &uStartupDelay); 873 if (RT_FAILURE(rc)) 874 return RTEXITCODE_FAILURE; 875 876 if (!fAllowed) 877 return RTMsgErrorExit(RTEXITCODE_FAILURE, "User is not allowed to autostart VMs"); 431 878 432 879 /* create release logger, to stdout */ … … 509 956 return RTEXITCODE_FAILURE; 510 957 511 RTEXITCODE rcExit = autostartMain( );958 RTEXITCODE rcExit = autostartMain(uStartupDelay); 512 959 513 960 EventQueue::getMainEventQueue()->processEventQueue(0); -
trunk/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp
r42069 r42118 54 54 if (fAddVM) 55 55 fOpen |= RTFILE_O_OPEN_CREATE; 56 else 57 fOpen |= RTFILE_O_OPEN; 56 58 57 59 rc = RTStrAPrintf(&pszFile, "%s/%s.%s",
Note:
See TracChangeset
for help on using the changeset viewer.