Changeset 42732 in vbox
- Timestamp:
- Aug 9, 2012 10:32:48 PM (13 years ago)
- svn:sync-xref-src-repo-rev:
- 79941
- Location:
- trunk/src/VBox/Frontends/VBoxAutostart
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.cpp
r42527 r42732 331 331 displayHeader(); 332 332 333 bool fAllowed = false; 334 uint32_t uStartupDelay = 0; 335 rc = autostartParseConfig(pszConfigFile, &fAllowed, &uStartupDelay); 333 PCFGAST pCfgAst = NULL; 334 char *pszUser = NULL; 335 PCFGAST pCfgAstUser = NULL; 336 PCFGAST pCfgAstPolicy = NULL; 337 bool fAllow = false; 338 339 rc = autostartParseConfig(pszConfigFile, &pCfgAst); 336 340 if (RT_FAILURE(rc)) 337 341 return RTEXITCODE_FAILURE; 338 342 339 if (!fAllowed) 343 rc = RTProcQueryUsernameA(RTProcSelf(), &pszUser); 344 if (RT_FAILURE(rc)) 345 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to query username of the process"); 346 347 pCfgAstUser = autostartConfigAstGetByName(pCfgAst, pszUser); 348 pCfgAstPolicy = autostartConfigAstGetByName(pCfgAst, "default_policy"); 349 350 /* Check default policy. */ 351 if (pCfgAstPolicy) 352 { 353 if ( pCfgAstPolicy->enmType == CFGASTNODETYPE_KEYVALUE 354 && ( !RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "allow") 355 || !RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "deny"))) 356 { 357 if (!RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "allow")) 358 fAllow = true; 359 } 360 else 361 return RTMsgErrorExit(RTEXITCODE_FAILURE, "'default_policy' must be either 'allow' or 'deny'"); 362 } 363 364 if ( pCfgAstUser 365 && pCfgAstUser->enmType == CFGASTNODETYPE_COMPOUND) 366 { 367 pCfgAstPolicy = autostartConfigAstGetByName(pCfgAstUser, "allow"); 368 if (pCfgAstPolicy) 369 { 370 if ( pCfgAstPolicy->enmType == CFGASTNODETYPE_KEYVALUE 371 && ( !RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "true") 372 || !RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "false"))) 373 { 374 if (!RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "true")) 375 fAllow = true; 376 else 377 fAllow = false; 378 } 379 else 380 return RTMsgErrorExit(RTEXITCODE_FAILURE, "'allow' must be either 'true' or 'false'"); 381 } 382 } 383 else if (pCfgAstUser) 384 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Invalid config, user is not a compound node"); 385 386 if (!fAllow) 340 387 return RTMsgErrorExit(RTEXITCODE_FAILURE, "User is not allowed to autostart VMs"); 388 389 RTStrFree(pszUser); 341 390 342 391 /* Don't start if the VirtualBox settings directory does not exist. */ … … 429 478 RTEXITCODE rcExit; 430 479 if (fStart) 431 rcExit = autostartStartMain( uStartupDelay);480 rcExit = autostartStartMain(pCfgAstUser); 432 481 else 433 482 { 434 483 Assert(fStop); 435 rcExit = autostartStopMain(uStartupDelay); 436 } 437 484 rcExit = autostartStopMain(pCfgAstUser); 485 } 486 487 autostartConfigAstDestroy(pCfgAst); 438 488 EventQueue::getMainEventQueue()->processEventQueue(0); 439 489 -
trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.h
r42527 r42732 28 28 #include <VBox/com/VirtualBox.h> 29 29 30 /******************************************************************************* 31 * Constants And Macros, Structures and Typedefs * 32 *******************************************************************************/ 33 34 /** 35 * Config AST node types. 36 */ 37 typedef enum CFGASTNODETYPE 38 { 39 /** Invalid. */ 40 CFGASTNODETYPE_INVALID = 0, 41 /** Key/Value pair. */ 42 CFGASTNODETYPE_KEYVALUE, 43 /** Compound type. */ 44 CFGASTNODETYPE_COMPOUND, 45 /** List type. */ 46 CFGASTNODETYPE_LIST, 47 /** 32bit hack. */ 48 CFGASTNODETYPE_32BIT_HACK = 0x7fffffff 49 } CFGASTNODETYPE; 50 /** Pointer to a config AST node type. */ 51 typedef CFGASTNODETYPE *PCFGASTNODETYPE; 52 /** Pointer to a const config AST node type. */ 53 typedef const CFGASTNODETYPE *PCCFGASTNODETYPE; 54 55 /** 56 * Config AST. 57 */ 58 typedef struct CFGAST 59 { 60 /** AST node type. */ 61 CFGASTNODETYPE enmType; 62 /** Key or scope id. */ 63 char *pszKey; 64 /** Type dependent data. */ 65 union 66 { 67 /** Key value pair. */ 68 struct 69 { 70 /** Number of characters in the value - excluding terminator. */ 71 size_t cchValue; 72 /** Value string - variable in size. */ 73 char aszValue[1]; 74 } KeyValue; 75 /** Compound type. */ 76 struct 77 { 78 /** Number of AST node entries in the array. */ 79 unsigned cAstNodes; 80 /** AST node array - variable in size. */ 81 struct CFGAST *apAstNodes[1]; 82 } Compound; 83 /** List type. */ 84 struct 85 { 86 /** Number of entries in the list. */ 87 unsigned cListEntries; 88 /** Array of list entries - variable in size. */ 89 char *apszEntries[1]; 90 } List; 91 } u; 92 } CFGAST, *PCFGAST; 93 30 94 /** Flag whether we are in verbose logging mode. */ 31 95 extern bool g_fVerbose; … … 53 117 * @returns VBox status code. 54 118 * @param pszFilename The config file to parse. 55 * @param pfAllowed Where to store the flag whether the user of this process 56 * is allowed to start VMs automatically during system startup. 57 * @param puStartupDelay Where to store the startup delay for the user. 119 * @param ppCfgAst Where to store the pointer to the root AST node on success. 58 120 */ 59 DECLHIDDEN(int) autostartParseConfig(const char *pszFilename, bool *pfAllowed, uint32_t *puStartupDelay); 121 DECLHIDDEN(int) autostartParseConfig(const char *pszFilename, PCFGAST *ppCfgAst); 122 123 /** 124 * Destroys the config AST and frees all resources. 125 * 126 * @returns nothing. 127 * @param pCfgAst The config AST. 128 */ 129 DECLHIDDEN(void) autostartConfigAstDestroy(PCFGAST pCfgAst); 130 131 /** 132 * Return the config AST node with the given name or NULL if it doesn't exist. 133 * 134 * @returns Matching config AST node for the given name or NULL if not found. 135 * @param pCfgAst The config ASt to search. 136 * @param pszName The name to search for. 137 */ 138 DECLHIDDEN(PCFGAST) autostartConfigAstGetByName(PCFGAST pCfgAst, const char *pszName); 60 139 61 140 /** … … 63 142 * 64 143 * @returns exit status code. 65 * @param uStartupDelay Base startup for the user.144 * @param pCfgAst Config AST for the startup part of the autostart daemon. 66 145 */ 67 DECLHIDDEN(RTEXITCODE) autostartStartMain( uint32_t uStartupDelay);146 DECLHIDDEN(RTEXITCODE) autostartStartMain(PCFGAST pCfgAst); 68 147 69 148 /** … … 72 151 * 73 152 * @returns exit status code. 74 * @param uStartupDelay Base stop delay for the user.153 * @param pCfgAst Config AST for the shutdown part of the autostart daemon. 75 154 */ 76 DECLHIDDEN(RTEXITCODE) autostartStopMain( uint32_t uStopDelay);155 DECLHIDDEN(RTEXITCODE) autostartStopMain(PCFGAST pCfgAst); 77 156 78 157 #endif /* __VBoxAutostart_h__ */ -
trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartCfg.cpp
r42527 r42732 32 32 * Constants And Macros, Structures and Typedefs * 33 33 *******************************************************************************/ 34 35 /** 36 * Token type. 37 */ 38 typedef enum CFGTOKENTYPE 39 { 40 /** Invalid token type. */ 41 CFGTOKENTYPE_INVALID = 0, 42 /** Identifier. */ 43 CFGTOKENTYPE_ID, 44 /** Comma. */ 45 CFGTOKENTYPE_COMMA, 46 /** Equal sign. */ 47 CFGTOKENTYPE_EQUAL, 48 /** Open curly brackets. */ 49 CFGTOKENTYPE_CURLY_OPEN, 50 /** Closing curly brackets. */ 51 CFGTOKENTYPE_CURLY_CLOSING, 52 /** End of file. */ 53 CFGTOKENTYPE_EOF, 54 /** 32bit hack. */ 55 CFGTOKENTYPE_32BIT_HACK = 0x7fffffff 56 } CFGTOKENTYPE; 57 /** Pointer to a token type. */ 58 typedef CFGTOKENTYPE *PCFGTOKENTYPE; 59 /** Pointer to a const token type. */ 60 typedef const CFGTOKENTYPE *PCCFGTOKENTYPE; 61 62 /** 63 * A token. 64 */ 65 typedef struct CFGTOKEN 66 { 67 /** Type of the token. */ 68 CFGTOKENTYPE enmType; 69 /** Line number of the token. */ 70 unsigned iLine; 71 /** Starting character of the token in the stream. */ 72 unsigned cchStart; 73 /** Type dependen token data. */ 74 union 75 { 76 /** Data for the ID type. */ 77 struct 78 { 79 /** Size of the id in characters, excluding the \0 terminator. */ 80 size_t cchToken; 81 /** Token data, variable size (given by cchToken member). */ 82 char achToken[1]; 83 } Id; 84 } u; 85 } CFGTOKEN; 86 /** Pointer to a token. */ 87 typedef CFGTOKEN *PCFGTOKEN; 88 /** Pointer to a const token. */ 89 typedef const CFGTOKEN *PCCFGTOKEN; 34 90 35 91 /** … … 48 104 /** Current line in the config file. */ 49 105 unsigned iLine; 106 /** Current character of the line. */ 107 unsigned cchCurr; 108 /** Flag whether the end of the config stream is reached. */ 109 bool fEof; 110 /** Pointer to the next token in the stream (used to peek). */ 111 PCFGTOKEN pTokenNext; 50 112 } CFGTOKENIZER, *PCFGTOKENIZER; 51 113 … … 55 117 56 118 /** 119 * Free a config token. 120 * 121 * @returns nothing. 122 * @param pCfgTokenizer The config tokenizer. 123 * @param pToken The token to free. 124 */ 125 static void autostartConfigTokenFree(PCFGTOKENIZER pCfgTokenizer, PCFGTOKEN pToken) 126 { 127 NOREF(pCfgTokenizer); 128 RTMemFree(pToken); 129 } 130 131 /** 57 132 * Reads the next line from the config stream. 58 133 * … … 63 138 { 64 139 int rc = VINF_SUCCESS; 140 141 if (pCfgTokenizer->fEof) 142 return VERR_EOF; 65 143 66 144 do … … 81 159 } while (rc == VERR_BUFFER_OVERFLOW); 82 160 161 if ( RT_SUCCESS(rc) 162 || rc == VERR_EOF) 163 { 164 pCfgTokenizer->iLine++; 165 pCfgTokenizer->cchCurr = 1; 166 pCfgTokenizer->pszLineCurr = pCfgTokenizer->pszLine; 167 if (rc == VERR_EOF) 168 pCfgTokenizer->fEof = true; 169 } 170 171 return rc; 172 } 173 174 /** 175 * Get the next token from the config stream and create a token structure. 176 * 177 * @returns VBox status code. 178 * @param pCfgTokenizer The config tokenizer data. 179 * @param pCfgTokenUse Allocated token structure to use or NULL to allocate 180 * a new one. It will bee freed if an error is encountered. 181 * @param ppCfgToken Where to store the pointer to the next token on success. 182 */ 183 static int autostartConfigTokenizerCreateToken(PCFGTOKENIZER pCfgTokenizer, 184 PCFGTOKEN pCfgTokenUse, PCFGTOKEN *ppCfgToken) 185 { 186 const char *pszToken = NULL; 187 size_t cchToken = 1; 188 size_t cchAdvance = 0; 189 CFGTOKENTYPE enmType = CFGTOKENTYPE_INVALID; 190 int rc = VINF_SUCCESS; 191 192 for (;;) 193 { 194 pszToken = pCfgTokenizer->pszLineCurr; 195 196 /* Skip all spaces. */ 197 while (RT_C_IS_BLANK(*pszToken)) 198 { 199 pszToken++; 200 cchAdvance++; 201 } 202 203 /* Check if we have to read a new line. */ 204 if ( *pszToken == '\0' 205 || *pszToken == '#') 206 { 207 rc = autostartConfigTokenizerReadNextLine(pCfgTokenizer); 208 if (rc == VERR_EOF) 209 { 210 enmType = CFGTOKENTYPE_EOF; 211 rc = VINF_SUCCESS; 212 break; 213 } 214 else if (RT_FAILURE(rc)) 215 break; 216 /* start from the beginning. */ 217 cchAdvance = 0; 218 } 219 else if (*pszToken == '=') 220 { 221 enmType = CFGTOKENTYPE_EQUAL; 222 break; 223 } 224 else if (*pszToken == ',') 225 { 226 enmType = CFGTOKENTYPE_COMMA; 227 break; 228 } 229 else if (*pszToken == '{') 230 { 231 enmType = CFGTOKENTYPE_CURLY_OPEN; 232 break; 233 } 234 else if (*pszToken == '}') 235 { 236 enmType = CFGTOKENTYPE_CURLY_CLOSING; 237 break; 238 } 239 else 240 { 241 const char *pszTmp = pszToken; 242 cchToken = 0; 243 enmType = CFGTOKENTYPE_ID; 244 245 /* Get the complete token. */ 246 while ( RT_C_IS_ALNUM(*pszTmp) 247 || *pszTmp == '_' 248 || *pszTmp == '.') 249 { 250 pszTmp++; 251 cchToken++; 252 } 253 break; 254 } 255 } 256 257 Assert(RT_FAILURE(rc) || enmType != CFGTOKENTYPE_INVALID); 258 83 259 if (RT_SUCCESS(rc)) 84 260 { 85 pCfgTokenizer->iLine++; 86 pCfgTokenizer->pszLineCurr = pCfgTokenizer->pszLine; 261 /* Free the given token if it is an ID or the current one is an ID token. */ 262 if ( pCfgTokenUse 263 && ( pCfgTokenUse->enmType == CFGTOKENTYPE_ID 264 || enmType == CFGTOKENTYPE_ID)) 265 { 266 autostartConfigTokenFree(pCfgTokenizer, pCfgTokenUse); 267 pCfgTokenUse = NULL; 268 } 269 270 if (!pCfgTokenUse) 271 { 272 size_t cbToken = sizeof(CFGTOKEN); 273 if (enmType == CFGTOKENTYPE_ID) 274 cbToken += (cchToken + 1) * sizeof(char); 275 276 pCfgTokenUse = (PCFGTOKEN)RTMemAllocZ(cbToken); 277 if (!pCfgTokenUse) 278 rc = VERR_NO_MEMORY; 279 } 280 281 if (RT_SUCCESS(rc)) 282 { 283 /* Copy token data. */ 284 pCfgTokenUse->enmType = enmType; 285 pCfgTokenUse->cchStart = pCfgTokenizer->cchCurr; 286 pCfgTokenUse->iLine = pCfgTokenizer->iLine; 287 if (enmType == CFGTOKENTYPE_ID) 288 { 289 pCfgTokenUse->u.Id.cchToken = cchToken; 290 memcpy(pCfgTokenUse->u.Id.achToken, pszToken, cchToken); 291 } 292 } 293 else if (pCfgTokenUse) 294 autostartConfigTokenFree(pCfgTokenizer, pCfgTokenUse); 295 296 if (RT_SUCCESS(rc)) 297 { 298 /* Set new position in config stream. */ 299 pCfgTokenizer->pszLineCurr += cchToken + cchAdvance; 300 pCfgTokenizer->cchCurr += cchToken + cchAdvance; 301 *ppCfgToken = pCfgTokenUse; 302 } 87 303 } 88 304 89 305 return rc; 306 } 307 308 /** 309 * Destroys the given config tokenizer. 310 * 311 * @returns nothing. 312 * @param pCfgTokenizer The config tokenizer to destroy. 313 */ 314 static void autostartConfigTokenizerDestroy(PCFGTOKENIZER pCfgTokenizer) 315 { 316 if (pCfgTokenizer->pszLine) 317 RTMemFree(pCfgTokenizer->pszLine); 318 if (pCfgTokenizer->hStrmConfig) 319 RTStrmClose(pCfgTokenizer->hStrmConfig); 320 if (pCfgTokenizer->pTokenNext) 321 RTMemFree(pCfgTokenizer->pTokenNext); 322 RTMemFree(pCfgTokenizer); 90 323 } 91 324 … … 105 338 if (pCfgTokenizer) 106 339 { 107 pCfgTokenizer->iLine = 1;340 pCfgTokenizer->iLine = 0; 108 341 pCfgTokenizer->cbLine = 128; 109 342 pCfgTokenizer->pszLine = (char *)RTMemAllocZ(pCfgTokenizer->cbLine); … … 112 345 rc = RTStrmOpen(pszFilename, "r", &pCfgTokenizer->hStrmConfig); 113 346 if (RT_SUCCESS(rc)) 347 { 114 348 rc = autostartConfigTokenizerReadNextLine(pCfgTokenizer); 349 if (RT_SUCCESS(rc)) 350 rc = autostartConfigTokenizerCreateToken(pCfgTokenizer, NULL, 351 &pCfgTokenizer->pTokenNext); 352 } 115 353 } 116 354 else … … 124 362 else if ( RT_FAILURE(rc) 125 363 && pCfgTokenizer) 126 { 127 if (pCfgTokenizer->pszLine) 128 RTMemFree(pCfgTokenizer->pszLine); 129 if (pCfgTokenizer->hStrmConfig) 130 RTStrmClose(pCfgTokenizer->hStrmConfig); 131 RTMemFree(pCfgTokenizer); 132 } 364 autostartConfigTokenizerDestroy(pCfgTokenizer); 133 365 134 366 return rc; … … 136 368 137 369 /** 138 * Destroys the given config tokenizer. 139 * 140 * @returns nothing. 141 * @param pCfgTokenizer The config tokenizer to destroy. 142 */ 143 static void autostartConfigTokenizerDestroy(PCFGTOKENIZER pCfgTokenizer) 144 { 145 if (pCfgTokenizer->pszLine) 146 RTMemFree(pCfgTokenizer->pszLine); 147 if (pCfgTokenizer->hStrmConfig) 148 RTStrmClose(pCfgTokenizer->hStrmConfig); 149 RTMemFree(pCfgTokenizer); 150 } 151 152 /** 153 * Read the next token from the config file. 370 * Return the next token from the config stream. 154 371 * 155 372 * @returns VBox status code. 156 * @param pCfgTokenizer The config tokenizer data. 157 * @param ppszToken Where to store the start to the next token on success. 158 * @param pcchToken Where to store the number of characters of the next token 159 * excluding the \0 terminator on success. 160 */ 161 static int autostartConfigTokenizerReadNext(PCFGTOKENIZER pCfgTokenizer, const char **ppszToken, 162 size_t *pcchToken) 163 { 164 if (!pCfgTokenizer->pszLineCurr) 165 return VERR_EOF; 166 373 * @param pCfgTokenizer The config tokenizer. 374 * @param ppCfgToken Where to store the next token. 375 */ 376 static int autostartConfigTokenizerGetNextToken(PCFGTOKENIZER pCfgTokenizer, 377 PCFGTOKEN *ppCfgToken) 378 { 379 *ppCfgToken = pCfgTokenizer->pTokenNext; 380 return autostartConfigTokenizerCreateToken(pCfgTokenizer, NULL, &pCfgTokenizer->pTokenNext); 381 } 382 383 static const char *autostartConfigTokenToString(PCFGTOKEN pToken) 384 { 385 switch (pToken->enmType) 386 { 387 case CFGTOKENTYPE_COMMA: 388 return ","; 389 case CFGTOKENTYPE_EQUAL: 390 return "="; 391 case CFGTOKENTYPE_CURLY_OPEN: 392 return "{"; 393 case CFGTOKENTYPE_CURLY_CLOSING: 394 return "}"; 395 case CFGTOKENTYPE_EOF: 396 return "<EOF>"; 397 case CFGTOKENTYPE_ID: 398 return pToken->u.Id.achToken; 399 default: 400 AssertFailed(); 401 return "<Invalid>"; 402 } 403 404 AssertFailed(); 405 return NULL; 406 } 407 408 static size_t autostartConfigTokenGetLength(PCFGTOKEN pToken) 409 { 410 switch (pToken->enmType) 411 { 412 case CFGTOKENTYPE_COMMA: 413 case CFGTOKENTYPE_EQUAL: 414 case CFGTOKENTYPE_CURLY_OPEN: 415 case CFGTOKENTYPE_CURLY_CLOSING: 416 return 1; 417 case CFGTOKENTYPE_EOF: 418 return 0; 419 case CFGTOKENTYPE_ID: 420 return strlen(pToken->u.Id.achToken); 421 default: 422 AssertFailed(); 423 return 0; 424 } 425 426 AssertFailed(); 427 return 0; 428 } 429 430 static void autostartConfigTokenizerMsgUnexpectedToken(PCFGTOKEN pToken, const char *pszExpected) 431 { 432 RTMsgError("Unexpected token '%s' at %d:%d.%d, expected '%s'", 433 autostartConfigTokenToString(pToken), 434 pToken->iLine, pToken->cchStart, 435 pToken->cchStart + autostartConfigTokenGetLength(pToken) - 1, pszExpected); 436 } 437 438 /** 439 * Verfies a token and consumes it. 440 * 441 * @returns VBox status code. 442 * @param pCfgTokenizer The config tokenizer. 443 * @param pszTokenCheck The token to check for. 444 */ 445 static int autostartConfigTokenizerCheckAndConsume(PCFGTOKENIZER pCfgTokenizer, CFGTOKENTYPE enmType) 446 { 167 447 int rc = VINF_SUCCESS; 168 169 for (;;) 170 { 171 char *pszTok = pCfgTokenizer->pszLineCurr; 172 173 /* Skip all spaces. */ 174 while (RT_C_IS_BLANK(*pszTok)) 175 pszTok++; 176 177 /* Check if we have to read a new line. */ 178 if ( *pszTok == '\0' 179 || *pszTok == '#') 180 { 181 rc = autostartConfigTokenizerReadNextLine(pCfgTokenizer); 182 if (RT_FAILURE(rc)) 183 break; 184 /* start from the beginning. */ 185 } 186 else if ( *pszTok == '=' 187 || *pszTok == ',') 188 { 189 *ppszToken = pszTok; 190 *pcchToken = 1; 191 pCfgTokenizer->pszLineCurr = pszTok + 1; 192 break; 193 } 194 else 195 { 196 /* Get the complete token. */ 197 size_t cchToken = 1; 198 char *pszTmp = pszTok + 1; 199 200 while ( RT_C_IS_ALNUM(*pszTmp) 201 || *pszTmp == '_') 202 { 203 pszTmp++; 204 cchToken++; 205 } 206 207 *ppszToken = pszTok; 208 *pcchToken = cchToken; 209 pCfgTokenizer->pszLineCurr = pszTmp; 210 break; 211 } 212 } 213 448 PCFGTOKEN pCfgToken = NULL; 449 450 rc = autostartConfigTokenizerGetNextToken(pCfgTokenizer, &pCfgToken); 451 if (RT_SUCCESS(rc)) 452 { 453 if (pCfgToken->enmType != enmType) 454 { 455 autostartConfigTokenizerMsgUnexpectedToken(pCfgToken, "@todo"); 456 rc = VERR_INVALID_PARAMETER; 457 } 458 459 autostartConfigTokenFree(pCfgTokenizer, pCfgToken); 460 } 214 461 return rc; 215 462 } 216 463 217 static int autostartConfigTokenizerCheckAndConsume(PCFGTOKENIZER pCfgTokenizer, const char *pszTokCheck) 218 { 219 int rc = VINF_SUCCESS; 220 const char *pszToken = NULL; 221 size_t cchToken = 0; 222 223 rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken, &cchToken); 224 if (RT_SUCCESS(rc)) 225 { 226 if (RTStrNCmp(pszToken, pszTokCheck, cchToken)) 227 { 228 RTMsgError("Unexpected token at line %d, expected '%s'", 229 pCfgTokenizer->iLine, pszTokCheck); 230 rc = VERR_INVALID_PARAMETER; 231 } 232 } 233 return rc; 234 } 235 236 /** 237 * Returns the start of the next token without consuming it. 464 /** 465 * Consumes the next token in the stream. 238 466 * 239 467 * @returns VBox status code. 240 468 * @param pCfgTokenizer Tokenizer instance data. 241 * @param ppszTok Where to store the start of the next token on success. 242 */ 243 static int autostartConfigTokenizerPeek(PCFGTOKENIZER pCfgTokenizer, const char **ppszTok) 469 */ 470 static int autostartConfigTokenizerConsume(PCFGTOKENIZER pCfgTokenizer) 244 471 { 245 472 int rc = VINF_SUCCESS; 246 247 for (;;) 248 { 249 char *pszTok = pCfgTokenizer->pszLineCurr; 250 251 /* Skip all spaces. */ 252 while (RT_C_IS_BLANK(*pszTok)) 253 pszTok++; 254 255 /* Check if we have to read a new line. */ 256 if ( *pszTok == '\0' 257 || *pszTok == '#') 258 { 259 rc = autostartConfigTokenizerReadNextLine(pCfgTokenizer); 260 if (RT_FAILURE(rc)) 261 break; 262 /* start from the beginning. */ 263 } 264 else 265 { 266 *ppszTok = pszTok; 473 PCFGTOKEN pCfgToken = NULL; 474 475 rc = autostartConfigTokenizerGetNextToken(pCfgTokenizer, &pCfgToken); 476 if (RT_SUCCESS(rc)) 477 autostartConfigTokenFree(pCfgTokenizer, pCfgToken); 478 479 return rc; 480 } 481 482 /** 483 * Returns the start of the next token without consuming it. 484 * 485 * @returns The next token without consuming it. 486 * @param pCfgTokenizer Tokenizer instance data. 487 */ 488 DECLINLINE(PCFGTOKEN) autostartConfigTokenizerPeek(PCFGTOKENIZER pCfgTokenizer) 489 { 490 return pCfgTokenizer->pTokenNext; 491 } 492 493 /** 494 * Check whether the next token is equal to the given one. 495 * 496 * @returns true if the next token in the stream is equal to the given one 497 * false otherwise. 498 * @param pszToken The token to check for. 499 */ 500 DECLINLINE(bool) autostartConfigTokenizerPeekIsEqual(PCFGTOKENIZER pCfgTokenizer, CFGTOKENTYPE enmType) 501 { 502 PCFGTOKEN pToken = autostartConfigTokenizerPeek(pCfgTokenizer); 503 return pToken->enmType == enmType; 504 } 505 506 /** 507 * Parse a key value node and returns the AST. 508 * 509 * @returns VBox status code. 510 * @param pCfgTokenizer The tokenizer for the config stream. 511 * @param pszKey The key for the pair. 512 * @param ppCfgAst Where to store the resulting AST on success. 513 */ 514 static int autostartConfigParseValue(PCFGTOKENIZER pCfgTokenizer, const char *pszKey, 515 PCFGAST *ppCfgAst) 516 { 517 int rc = VINF_SUCCESS; 518 PCFGTOKEN pToken = NULL; 519 520 rc = autostartConfigTokenizerGetNextToken(pCfgTokenizer, &pToken); 521 if ( RT_SUCCESS(rc) 522 && pToken->enmType == CFGTOKENTYPE_ID) 523 { 524 PCFGAST pCfgAst = NULL; 525 526 pCfgAst = (PCFGAST)RTMemAllocZ(RT_OFFSETOF(CFGAST, u.KeyValue.aszValue[pToken->u.Id.cchToken + 1])); 527 if (!pCfgAst) 528 return VERR_NO_MEMORY; 529 530 pCfgAst->enmType = CFGASTNODETYPE_KEYVALUE; 531 pCfgAst->pszKey = RTStrDup(pszKey); 532 if (!pCfgAst->pszKey) 533 { 534 RTMemFree(pCfgAst); 535 return VERR_NO_MEMORY; 536 } 537 538 memcpy(pCfgAst->u.KeyValue.aszValue, pToken->u.Id.achToken, pToken->u.Id.cchToken); 539 pCfgAst->u.KeyValue.cchValue = pToken->u.Id.cchToken; 540 *ppCfgAst = pCfgAst; 541 } 542 else 543 { 544 autostartConfigTokenizerMsgUnexpectedToken(pToken, "non reserved token"); 545 rc = VERR_INVALID_PARAMETER; 546 } 547 548 return rc; 549 } 550 551 /** 552 * Parses a compound node constructing the AST and returning it on success. 553 * 554 * @returns VBox status code. 555 * @param pCfgTokenizer The tokenizer for the config stream. 556 * @param pszScopeId The scope ID of the compound node. 557 * @param ppCfgAst Where to store the resulting AST on success. 558 */ 559 static int autostartConfigParseCompoundNode(PCFGTOKENIZER pCfgTokenizer, const char *pszScopeId, 560 PCFGAST *ppCfgAst) 561 { 562 int rc = VINF_SUCCESS; 563 unsigned cAstNodesMax = 10; 564 unsigned idxAstNodeCur = 0; 565 PCFGAST pCfgAst = NULL; 566 567 pCfgAst = (PCFGAST)RTMemAllocZ(RT_OFFSETOF(CFGAST, u.Compound.apAstNodes[cAstNodesMax])); 568 if (!pCfgAst) 569 return VERR_NO_MEMORY; 570 571 pCfgAst->enmType = CFGASTNODETYPE_COMPOUND; 572 pCfgAst->pszKey = RTStrDup(pszScopeId); 573 if (!pCfgAst->pszKey) 574 { 575 RTMemFree(pCfgAst); 576 return VERR_NO_MEMORY; 577 } 578 579 do 580 { 581 PCFGTOKEN pToken = NULL; 582 PCFGAST pAstNode = NULL; 583 584 if ( autostartConfigTokenizerPeekIsEqual(pCfgTokenizer, CFGTOKENTYPE_CURLY_CLOSING) 585 || autostartConfigTokenizerPeekIsEqual(pCfgTokenizer, CFGTOKENTYPE_EOF)) 267 586 break; 268 } 269 } 587 588 rc = autostartConfigTokenizerGetNextToken(pCfgTokenizer, &pToken); 589 if ( RT_SUCCESS(rc) 590 && pToken->enmType == CFGTOKENTYPE_ID) 591 { 592 /* Next must be a = token in all cases at this place. */ 593 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, CFGTOKENTYPE_EQUAL); 594 if (RT_SUCCESS(rc)) 595 { 596 /* Check whether this is a compound node. */ 597 if (autostartConfigTokenizerPeekIsEqual(pCfgTokenizer, CFGTOKENTYPE_CURLY_OPEN)) 598 { 599 rc = autostartConfigTokenizerConsume(pCfgTokenizer); 600 if (RT_SUCCESS(rc)) 601 rc = autostartConfigParseCompoundNode(pCfgTokenizer, pToken->u.Id.achToken, 602 &pAstNode); 603 604 if (RT_SUCCESS(rc)) 605 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, CFGTOKENTYPE_CURLY_CLOSING); 606 } 607 else 608 rc = autostartConfigParseValue(pCfgTokenizer, pToken->u.Id.achToken, 609 &pAstNode); 610 } 611 } 612 else if (RT_SUCCESS(rc)) 613 { 614 autostartConfigTokenizerMsgUnexpectedToken(pToken, "non reserved token"); 615 rc = VERR_INVALID_PARAMETER; 616 } 617 618 /* Add to the current compound node. */ 619 if (RT_SUCCESS(rc)) 620 { 621 Assert(idxAstNodeCur < cAstNodesMax); 622 pCfgAst->u.Compound.apAstNodes[idxAstNodeCur] = pAstNode; 623 idxAstNodeCur++; 624 /** @todo: realloc if array is getting to small. */ 625 } 626 627 autostartConfigTokenFree(pCfgTokenizer, pToken); 628 629 } while (RT_SUCCESS(rc)); 630 631 if (RT_SUCCESS(rc)) 632 { 633 pCfgAst->u.Compound.cAstNodes = idxAstNodeCur; 634 *ppCfgAst = pCfgAst; 635 } 636 else 637 autostartConfigAstDestroy(pCfgAst); 270 638 271 639 return rc; 272 640 } 273 641 274 /** 275 * Check whether the given token is a reserved token. 276 * 277 * @returns true if the token is reserved or false otherwise. 278 * @param pszToken The token to check. 279 * @param cchToken Size of the token in characters. 280 */ 281 static bool autostartConfigTokenizerIsReservedToken(const char *pszToken, size_t cchToken) 282 { 283 if ( cchToken == 1 284 && ( *pszToken == ',' 285 || *pszToken == '=')) 286 return true; 287 else if ( cchToken > 1 288 && ( !RTStrNCmp(pszToken, "default_policy", cchToken) 289 || !RTStrNCmp(pszToken, "exception_list", cchToken))) 290 return true; 291 292 return false; 293 } 294 295 DECLHIDDEN(int) autostartParseConfig(const char *pszFilename, bool *pfAllowed, uint32_t *puStartupDelay) 296 { 642 DECLHIDDEN(int) autostartParseConfig(const char *pszFilename, PCFGAST *ppCfgAst) 643 { 644 PCFGTOKENIZER pCfgTokenizer = NULL; 297 645 int rc = VINF_SUCCESS; 298 char *pszUserProcess = NULL; 299 bool fDefaultAllow = false; 300 bool fInExceptionList = false; 301 302 AssertPtrReturn(pfAllowed, VERR_INVALID_POINTER); 303 AssertPtrReturn(puStartupDelay, VERR_INVALID_POINTER); 304 305 *pfAllowed = false; 306 *puStartupDelay = 0; 307 308 rc = RTProcQueryUsernameA(RTProcSelf(), &pszUserProcess); 646 PCFGAST pCfgAst = NULL; 647 648 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER); 649 AssertPtrReturn(ppCfgAst, VERR_INVALID_POINTER); 650 651 rc = autostartConfigTokenizerCreate(pszFilename, &pCfgTokenizer); 309 652 if (RT_SUCCESS(rc)) 310 653 { 311 PCFGTOKENIZER pCfgTokenizer = NULL; 312 313 rc = autostartConfigTokenizerCreate(pszFilename, &pCfgTokenizer); 654 rc = autostartConfigParseCompoundNode(pCfgTokenizer, "", &pCfgAst); 314 655 if (RT_SUCCESS(rc)) 315 { 316 do 317 { 318 size_t cchToken = 0; 319 const char *pszToken = NULL; 320 321 rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken, 322 &cchToken); 323 if (RT_SUCCESS(rc)) 324 { 325 if (!RTStrNCmp(pszToken, "default_policy", strlen("default_policy"))) 326 { 327 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, "="); 328 if (RT_SUCCESS(rc)) 329 { 330 rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken, 331 &cchToken); 332 if (RT_SUCCESS(rc)) 333 { 334 if (!RTStrNCmp(pszToken, "allow", strlen("allow"))) 335 fDefaultAllow = true; 336 else if (!RTStrNCmp(pszToken, "deny", strlen("deny"))) 337 fDefaultAllow = false; 338 else 339 { 340 RTMsgError("Unexpected token at line %d, expected either 'allow' or 'deny'", 341 pCfgTokenizer->iLine); 342 rc = VERR_INVALID_PARAMETER; 343 break; 344 } 345 } 346 } 347 } 348 else if (!RTStrNCmp(pszToken, "exception_list", strlen("exception_list"))) 349 { 350 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, "="); 351 if (RT_SUCCESS(rc)) 352 { 353 rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken, 354 &cchToken); 355 356 while (RT_SUCCESS(rc)) 357 { 358 if (autostartConfigTokenizerIsReservedToken(pszToken, cchToken)) 359 { 360 RTMsgError("Unexpected token at line %d, expected a username", 361 pCfgTokenizer->iLine); 362 rc = VERR_INVALID_PARAMETER; 363 break; 364 } 365 else if (!RTStrNCmp(pszUserProcess, pszToken, strlen(pszUserProcess))) 366 fInExceptionList = true; 367 368 /* Skip , */ 369 rc = autostartConfigTokenizerPeek(pCfgTokenizer, &pszToken); 370 if ( RT_SUCCESS(rc) 371 && *pszToken == ',') 372 { 373 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, ","); 374 AssertRC(rc); 375 } 376 else if (RT_SUCCESS(rc)) 377 break; 378 379 rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszToken, 380 &cchToken); 381 } 382 383 if (rc == VERR_EOF) 384 rc = VINF_SUCCESS; 385 } 386 } 387 else if (!autostartConfigTokenizerIsReservedToken(pszToken, cchToken)) 388 { 389 /* Treat as 'username = <base delay in seconds>. */ 390 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, "="); 391 if (RT_SUCCESS(rc)) 392 { 393 size_t cchDelay = 0; 394 const char *pszDelay = NULL; 395 396 rc = autostartConfigTokenizerReadNext(pCfgTokenizer, &pszDelay, 397 &cchDelay); 398 if (RT_SUCCESS(rc)) 399 { 400 uint32_t uDelay = 0; 401 402 rc = RTStrToUInt32Ex(pszDelay, NULL, 10, &uDelay); 403 if (rc == VWRN_TRAILING_SPACES) 404 rc = VINF_SUCCESS; 405 406 if ( RT_SUCCESS(rc) 407 && !RTStrNCmp(pszUserProcess, pszToken, strlen(pszUserProcess))) 408 *puStartupDelay = uDelay; 409 410 if (RT_FAILURE(rc)) 411 RTMsgError("Unexpected token at line %d, expected a number", 412 pCfgTokenizer->iLine); 413 } 414 } 415 } 416 else 417 { 418 RTMsgError("Unexpected token at line %d, expected a username", 419 pCfgTokenizer->iLine); 420 rc = VERR_INVALID_PARAMETER; 421 } 422 } 423 else if (rc == VERR_EOF) 424 { 425 rc = VINF_SUCCESS; 426 break; 427 } 428 } while (RT_SUCCESS(rc)); 429 430 if ( RT_SUCCESS(rc) 431 && ( (fDefaultAllow && !fInExceptionList) 432 || (!fDefaultAllow && fInExceptionList))) 433 *pfAllowed= true; 434 435 autostartConfigTokenizerDestroy(pCfgTokenizer); 436 } 437 438 RTStrFree(pszUserProcess); 439 } 656 rc = autostartConfigTokenizerCheckAndConsume(pCfgTokenizer, CFGTOKENTYPE_EOF); 657 } 658 659 if (pCfgTokenizer) 660 autostartConfigTokenizerDestroy(pCfgTokenizer); 661 662 if (RT_SUCCESS(rc)) 663 *ppCfgAst = pCfgAst; 440 664 441 665 return rc; 442 666 } 443 667 668 DECLHIDDEN(void) autostartConfigAstDestroy(PCFGAST pCfgAst) 669 { 670 AssertPtrReturnVoid(pCfgAst); 671 672 switch (pCfgAst->enmType) 673 { 674 case CFGASTNODETYPE_KEYVALUE: 675 { 676 RTMemFree(pCfgAst); 677 break; 678 } 679 case CFGASTNODETYPE_COMPOUND: 680 { 681 for (unsigned i = 0; i < pCfgAst->u.Compound.cAstNodes; i++) 682 autostartConfigAstDestroy(pCfgAst->u.Compound.apAstNodes[i]); 683 RTMemFree(pCfgAst); 684 break; 685 } 686 case CFGASTNODETYPE_LIST: 687 default: 688 AssertMsgFailed(("Invalid AST node type %d\n", pCfgAst->enmType)); 689 } 690 } 691 692 DECLHIDDEN(PCFGAST) autostartConfigAstGetByName(PCFGAST pCfgAst, const char *pszName) 693 { 694 if (!pCfgAst) 695 return NULL; 696 697 AssertReturn(pCfgAst->enmType == CFGASTNODETYPE_COMPOUND, NULL); 698 699 for (unsigned i = 0; i < pCfgAst->u.Compound.cAstNodes; i++) 700 { 701 PCFGAST pNode = pCfgAst->u.Compound.apAstNodes[i]; 702 703 if (!RTStrCmp(pNode->pszKey, pszName)) 704 return pNode; 705 } 706 707 return NULL; 708 } 709 -
trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStart.cpp
r42527 r42732 23 23 #include <VBox/com/errorprint.h> 24 24 25 #include <iprt/message.h> 25 26 #include <iprt/thread.h> 26 27 #include <iprt/stream.h> … … 51 52 } 52 53 53 DECLHIDDEN(RTEXITCODE) autostartStartMain( uint32_t uStartupDelay)54 DECLHIDDEN(RTEXITCODE) autostartStartMain(PCFGAST pCfgAst) 54 55 { 55 56 RTEXITCODE rcExit = RTEXITCODE_SUCCESS; 56 57 int vrc = VINF_SUCCESS; 57 58 std::list<AUTOSTARTVM> listVM; 59 uint32_t uStartupDelay = 0; 60 61 pCfgAst = autostartConfigAstGetByName(pCfgAst, "startup_delay"); 62 if (pCfgAst) 63 { 64 if (pCfgAst->enmType == CFGASTNODETYPE_KEYVALUE) 65 { 66 vrc = RTStrToUInt32Full(pCfgAst->u.KeyValue.aszValue, 10, &uStartupDelay); 67 if (RT_FAILURE(vrc)) 68 return RTMsgErrorExit(RTEXITCODE_FAILURE, "'startup_delay' must be an unsigned number"); 69 } 70 } 58 71 59 72 if (uStartupDelay) -
trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartStop.cpp
r42527 r42732 36 36 using namespace com; 37 37 38 DECLHIDDEN(RTEXITCODE) autostartStopMain( uint32_t uStartupDelay)38 DECLHIDDEN(RTEXITCODE) autostartStopMain(PCFGAST pCfgAst) 39 39 { 40 40 RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
Note:
See TracChangeset
for help on using the changeset viewer.