Initial reintegration of legacy update process that used update-script
This commit is contained in:
		| @@ -7,6 +7,7 @@ include $(CLEAR_VARS) | ||||
| commands_recovery_local_path := $(LOCAL_PATH) | ||||
|  | ||||
| LOCAL_SRC_FILES := \ | ||||
| 	legacy.c \ | ||||
| 	recovery.c \ | ||||
| 	bootloader.c \ | ||||
| 	firmware.c \ | ||||
| @@ -40,9 +41,11 @@ endif | ||||
| LOCAL_STATIC_LIBRARIES += libminzip libunz libmtdutils libmincrypt | ||||
| LOCAL_STATIC_LIBRARIES += libminui libpixelflinger_static libpng libcutils | ||||
| LOCAL_STATIC_LIBRARIES += libstdc++ libc | ||||
| LOCAL_STATIC_LIBRARIES += libamend | ||||
|  | ||||
| include $(BUILD_EXECUTABLE) | ||||
|  | ||||
| include $(commands_recovery_local_path)/amend/Android.mk | ||||
| include $(commands_recovery_local_path)/minui/Android.mk | ||||
| include $(commands_recovery_local_path)/minzip/Android.mk | ||||
| include $(commands_recovery_local_path)/mtdutils/Android.mk | ||||
|   | ||||
							
								
								
									
										53
									
								
								amend/Android.mk
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								amend/Android.mk
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,53 @@ | ||||
| # Copyright 2007 The Android Open Source Project | ||||
| # | ||||
|  | ||||
| LOCAL_PATH := $(call my-dir) | ||||
|  | ||||
| amend_src_files := \ | ||||
| 	amend.c \ | ||||
| 	lexer.l \ | ||||
| 	parser_y.y \ | ||||
| 	ast.c \ | ||||
| 	symtab.c \ | ||||
| 	commands.c \ | ||||
| 	permissions.c \ | ||||
| 	execute.c | ||||
|  | ||||
| amend_test_files := \ | ||||
| 	test_symtab.c \ | ||||
| 	test_commands.c \ | ||||
| 	test_permissions.c | ||||
|  | ||||
| # "-x c" forces the lex/yacc files to be compiled as c; | ||||
| # the build system otherwise forces them to be c++. | ||||
| amend_cflags := -Wall -x c | ||||
|  | ||||
| # | ||||
| # Build the host-side command line tool | ||||
| # | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| LOCAL_SRC_FILES := \ | ||||
| 		$(amend_src_files) \ | ||||
| 		$(amend_test_files) \ | ||||
| 		register.c \ | ||||
| 		main.c | ||||
|  | ||||
| LOCAL_CFLAGS := $(amend_cflags) -g -O0 | ||||
| LOCAL_MODULE := amend | ||||
| LOCAL_YACCFLAGS := -v | ||||
|  | ||||
| include $(BUILD_HOST_EXECUTABLE) | ||||
|  | ||||
| # | ||||
| # Build the device-side library | ||||
| # | ||||
| include $(CLEAR_VARS) | ||||
|  | ||||
| LOCAL_SRC_FILES := $(amend_src_files) | ||||
| LOCAL_SRC_FILES += $(amend_test_files) | ||||
|  | ||||
| LOCAL_CFLAGS := $(amend_cflags) | ||||
| LOCAL_MODULE := libamend | ||||
|  | ||||
| include $(BUILD_STATIC_LIBRARY) | ||||
							
								
								
									
										32
									
								
								amend/amend.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								amend/amend.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include "amend.h" | ||||
| #include "lexer.h" | ||||
|  | ||||
| extern const AmCommandList *gCommands; | ||||
|  | ||||
| const AmCommandList * | ||||
| parseAmendScript(const char *buf, size_t bufLen) | ||||
| { | ||||
|     setLexerInputBuffer(buf, bufLen); | ||||
|     int ret = yyparse(); | ||||
|     if (ret != 0) { | ||||
|         return NULL; | ||||
|     } | ||||
|     return gCommands; | ||||
| } | ||||
							
								
								
									
										25
									
								
								amend/amend.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								amend/amend.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef AMEND_H_ | ||||
| #define AMEND_H_ | ||||
|  | ||||
| #include "ast.h" | ||||
| #include "execute.h" | ||||
|  | ||||
| const AmCommandList *parseAmendScript(const char *buf, size_t bufLen); | ||||
|  | ||||
| #endif  // AMEND_H_ | ||||
							
								
								
									
										198
									
								
								amend/ast.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								amend/ast.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,198 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include "ast.h" | ||||
|  | ||||
| static const char gSpaces[] = | ||||
|     "                                                                " | ||||
|     "                                                                " | ||||
|     "                                                                " | ||||
|     "                                                                " | ||||
|     "                                                                " | ||||
|     "                                                                " | ||||
|     "                                                                "; | ||||
| const int gSpacesMax = sizeof(gSpaces) - 1; | ||||
|  | ||||
| static const char * | ||||
| pad(int level) | ||||
| { | ||||
|     level *= 4; | ||||
|     if (level > gSpacesMax) { | ||||
|         level = gSpacesMax; | ||||
|     } | ||||
|     return gSpaces + gSpacesMax - level; | ||||
| } | ||||
|  | ||||
| void dumpBooleanValue(int level, const AmBooleanValue *booleanValue); | ||||
| void dumpStringValue(int level, const AmStringValue *stringValue); | ||||
|  | ||||
| void | ||||
| dumpBooleanExpression(int level, const AmBooleanExpression *booleanExpression) | ||||
| { | ||||
|     const char *op; | ||||
|     bool unary = false; | ||||
|  | ||||
|     switch (booleanExpression->op) { | ||||
|     case AM_BOP_NOT: | ||||
|         op = "NOT"; | ||||
|         unary = true; | ||||
|         break; | ||||
|     case AM_BOP_EQ: | ||||
|         op = "EQ"; | ||||
|         break; | ||||
|     case AM_BOP_NE: | ||||
|         op = "NE"; | ||||
|         break; | ||||
|     case AM_BOP_AND: | ||||
|         op = "AND"; | ||||
|         break; | ||||
|     case AM_BOP_OR: | ||||
|         op = "OR"; | ||||
|         break; | ||||
|     default: | ||||
|         op = "??"; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     printf("%sBOOLEAN %s {\n", pad(level), op); | ||||
|     dumpBooleanValue(level + 1, booleanExpression->arg1); | ||||
|     if (!unary) { | ||||
|         dumpBooleanValue(level + 1, booleanExpression->arg2); | ||||
|     } | ||||
|     printf("%s}\n", pad(level)); | ||||
| } | ||||
|  | ||||
| void | ||||
| dumpFunctionArguments(int level, const AmFunctionArguments *functionArguments) | ||||
| { | ||||
|     int i; | ||||
|     for (i = 0; i < functionArguments->argc; i++) { | ||||
|         dumpStringValue(level, &functionArguments->argv[i]); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| dumpFunctionCall(int level, const AmFunctionCall *functionCall) | ||||
| { | ||||
|     printf("%sFUNCTION %s (\n", pad(level), functionCall->name); | ||||
|     dumpFunctionArguments(level + 1, functionCall->args); | ||||
|     printf("%s)\n", pad(level)); | ||||
| } | ||||
|  | ||||
| void | ||||
| dumpStringValue(int level, const AmStringValue *stringValue) | ||||
| { | ||||
|     switch (stringValue->type) { | ||||
|     case AM_SVAL_LITERAL: | ||||
|         printf("%s\"%s\"\n", pad(level), stringValue->u.literal); | ||||
|         break; | ||||
|     case AM_SVAL_FUNCTION: | ||||
|         dumpFunctionCall(level, stringValue->u.function); | ||||
|         break; | ||||
|     default: | ||||
|         printf("%s<UNKNOWN SVAL TYPE %d>\n", pad(level), stringValue->type); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| dumpStringComparisonExpression(int level, | ||||
|         const AmStringComparisonExpression *stringComparisonExpression) | ||||
| { | ||||
|     const char *op; | ||||
|  | ||||
|     switch (stringComparisonExpression->op) { | ||||
|     case AM_SOP_LT: | ||||
|         op = "LT"; | ||||
|         break; | ||||
|     case AM_SOP_LE: | ||||
|         op = "LE"; | ||||
|         break; | ||||
|     case AM_SOP_GT: | ||||
|         op = "GT"; | ||||
|         break; | ||||
|     case AM_SOP_GE: | ||||
|         op = "GE"; | ||||
|         break; | ||||
|     case AM_SOP_EQ: | ||||
|         op = "EQ"; | ||||
|         break; | ||||
|     case AM_SOP_NE: | ||||
|         op = "NE"; | ||||
|         break; | ||||
|     default: | ||||
|         op = "??"; | ||||
|         break; | ||||
|     } | ||||
|     printf("%sSTRING %s {\n", pad(level), op); | ||||
|     dumpStringValue(level + 1, stringComparisonExpression->arg1); | ||||
|     dumpStringValue(level + 1, stringComparisonExpression->arg2); | ||||
|     printf("%s}\n", pad(level)); | ||||
| } | ||||
|  | ||||
| void | ||||
| dumpBooleanValue(int level, const AmBooleanValue *booleanValue) | ||||
| { | ||||
|     switch (booleanValue->type) { | ||||
|     case AM_BVAL_EXPRESSION: | ||||
|         dumpBooleanExpression(level, &booleanValue->u.expression); | ||||
|         break; | ||||
|     case AM_BVAL_STRING_COMPARISON: | ||||
|         dumpStringComparisonExpression(level, | ||||
|                 &booleanValue->u.stringComparison); | ||||
|         break; | ||||
|     default: | ||||
|         printf("%s<UNKNOWN BVAL TYPE %d>\n", pad(1), booleanValue->type); | ||||
|         break; | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| dumpWordList(const AmWordList *wordList) | ||||
| { | ||||
|     int i; | ||||
|     for (i = 0; i < wordList->argc; i++) { | ||||
|         printf("%s\"%s\"\n", pad(1), wordList->argv[i]); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| dumpCommandArguments(const AmCommandArguments *commandArguments) | ||||
| { | ||||
|     if (commandArguments->booleanArgs) { | ||||
|         dumpBooleanValue(1, commandArguments->u.b); | ||||
|     } else { | ||||
|         dumpWordList(commandArguments->u.w); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void | ||||
| dumpCommand(const AmCommand *command) | ||||
| { | ||||
|     printf("command \"%s\" {\n", command->name); | ||||
|     dumpCommandArguments(command->args); | ||||
|     printf("}\n"); | ||||
| } | ||||
|  | ||||
| void | ||||
| dumpCommandList(const AmCommandList *commandList) | ||||
| { | ||||
|     int i; | ||||
|     for (i = 0; i < commandList->commandCount; i++) { | ||||
|         dumpCommand(commandList->commands[i]); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										165
									
								
								amend/ast.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								amend/ast.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef AMEND_AST_H_ | ||||
| #define AMEND_AST_H_ | ||||
|  | ||||
| #include "commands.h" | ||||
|  | ||||
| typedef struct AmStringValue AmStringValue; | ||||
|  | ||||
| typedef struct { | ||||
|     int argc; | ||||
|     AmStringValue *argv; | ||||
| } AmFunctionArguments; | ||||
|  | ||||
| /* An internal structure used only by the parser; | ||||
|  * will not appear in the output AST. | ||||
| xxx try to move this into parser.h | ||||
|  */ | ||||
| typedef struct AmFunctionArgumentBuilder AmFunctionArgumentBuilder; | ||||
| struct AmFunctionArgumentBuilder { | ||||
|     AmFunctionArgumentBuilder *next; | ||||
|     AmStringValue *arg; | ||||
|     int argCount; | ||||
| }; | ||||
|  | ||||
| typedef struct AmWordListBuilder AmWordListBuilder; | ||||
| struct AmWordListBuilder { | ||||
|     AmWordListBuilder *next; | ||||
|     const char *word; | ||||
|     int wordCount; | ||||
| }; | ||||
|  | ||||
| typedef struct { | ||||
|     const char *name; | ||||
|     Function *fn; | ||||
|     AmFunctionArguments *args; | ||||
| } AmFunctionCall; | ||||
|  | ||||
|  | ||||
| /* <string-value> ::= | ||||
|  *      <literal-string> | | ||||
|  *      <function-call> | ||||
|  */ | ||||
| struct AmStringValue { | ||||
|     unsigned int line; | ||||
|  | ||||
|     enum { | ||||
|         AM_SVAL_LITERAL, | ||||
|         AM_SVAL_FUNCTION, | ||||
|     } type; | ||||
|     union { | ||||
|         const char *literal; | ||||
| //xxx inline instead of using pointers | ||||
|         AmFunctionCall *function; | ||||
|     } u; | ||||
| }; | ||||
|  | ||||
|  | ||||
| /* <string-comparison-expression> ::= | ||||
|  *      <string-value> <string-comparison-operator> <string-value> | ||||
|  */ | ||||
| typedef struct { | ||||
|     unsigned int line; | ||||
|  | ||||
|     enum { | ||||
|         AM_SOP_LT, | ||||
|         AM_SOP_LE, | ||||
|         AM_SOP_GT, | ||||
|         AM_SOP_GE, | ||||
|         AM_SOP_EQ, | ||||
|         AM_SOP_NE, | ||||
|     } op; | ||||
|     AmStringValue *arg1; | ||||
|     AmStringValue *arg2; | ||||
| } AmStringComparisonExpression; | ||||
|  | ||||
|  | ||||
| /* <boolean-expression> ::= | ||||
|  *      ! <boolean-value> | | ||||
|  *      <boolean-value> <binary-boolean-operator> <boolean-value> | ||||
|  */ | ||||
| typedef struct AmBooleanValue AmBooleanValue; | ||||
| typedef struct { | ||||
|     unsigned int line; | ||||
|  | ||||
|     enum { | ||||
|         AM_BOP_NOT, | ||||
|  | ||||
|         AM_BOP_EQ, | ||||
|         AM_BOP_NE, | ||||
|  | ||||
|         AM_BOP_AND, | ||||
|  | ||||
|         AM_BOP_OR, | ||||
|     } op; | ||||
|     AmBooleanValue *arg1; | ||||
|     AmBooleanValue *arg2; | ||||
| } AmBooleanExpression; | ||||
|  | ||||
|  | ||||
| /* <boolean-value> ::= | ||||
|  *      <boolean-expression> | | ||||
|  *      <string-comparison-expression> | ||||
|  */ | ||||
| struct AmBooleanValue { | ||||
|     unsigned int line; | ||||
|  | ||||
|     enum { | ||||
|         AM_BVAL_EXPRESSION, | ||||
|         AM_BVAL_STRING_COMPARISON, | ||||
|     } type; | ||||
|     union { | ||||
|         AmBooleanExpression expression; | ||||
|         AmStringComparisonExpression stringComparison; | ||||
|     } u; | ||||
| }; | ||||
|  | ||||
|  | ||||
| typedef struct { | ||||
|     unsigned int line; | ||||
|  | ||||
|     int argc; | ||||
|     const char **argv; | ||||
| } AmWordList; | ||||
|  | ||||
|  | ||||
| typedef struct { | ||||
|     bool booleanArgs; | ||||
|     union { | ||||
|         AmWordList *w; | ||||
|         AmBooleanValue *b; | ||||
|     } u; | ||||
| } AmCommandArguments; | ||||
|  | ||||
| typedef struct { | ||||
|     unsigned int line; | ||||
|  | ||||
|     const char *name; | ||||
|     Command *cmd; | ||||
|     AmCommandArguments *args; | ||||
| } AmCommand; | ||||
|  | ||||
| typedef struct { | ||||
|     AmCommand **commands; | ||||
|     int commandCount; | ||||
|     int arraySize; | ||||
| } AmCommandList; | ||||
|  | ||||
| void dumpCommandList(const AmCommandList *commandList); | ||||
|  | ||||
| #endif  // AMEND_AST_H_ | ||||
							
								
								
									
										273
									
								
								amend/commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										273
									
								
								amend/commands.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,273 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #include "symtab.h" | ||||
| #include "commands.h" | ||||
|  | ||||
| #if 1 | ||||
| #define TRACE(...)  printf(__VA_ARGS__) | ||||
| #else | ||||
| #define TRACE(...)  /**/ | ||||
| #endif | ||||
|  | ||||
| typedef enum { | ||||
|     CMD_TYPE_UNKNOWN = -1, | ||||
|     CMD_TYPE_COMMAND = 0, | ||||
|     CMD_TYPE_FUNCTION | ||||
| } CommandType; | ||||
|  | ||||
| typedef struct { | ||||
|     const char *name; | ||||
|     void *cookie; | ||||
|     CommandType type; | ||||
|     CommandArgumentType argType; | ||||
|     CommandHook hook; | ||||
| } CommandEntry; | ||||
|  | ||||
| static struct { | ||||
|     SymbolTable *symbolTable; | ||||
|     bool commandStateInitialized; | ||||
| } gCommandState; | ||||
|  | ||||
| int | ||||
| commandInit() | ||||
| { | ||||
|     if (gCommandState.commandStateInitialized) { | ||||
|         return -1; | ||||
|     } | ||||
|     gCommandState.symbolTable = createSymbolTable(); | ||||
|     if (gCommandState.symbolTable == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     gCommandState.commandStateInitialized = true; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| commandCleanup() | ||||
| { | ||||
|     if (gCommandState.commandStateInitialized) { | ||||
|         gCommandState.commandStateInitialized = false; | ||||
|         deleteSymbolTable(gCommandState.symbolTable); | ||||
|         gCommandState.symbolTable = NULL; | ||||
| //xxx need to free the entries and names in the symbol table | ||||
|     } | ||||
| } | ||||
|  | ||||
| static int | ||||
| registerCommandInternal(const char *name, CommandType type, | ||||
|         CommandArgumentType argType, CommandHook hook, void *cookie) | ||||
| { | ||||
|     CommandEntry *entry; | ||||
|  | ||||
|     if (!gCommandState.commandStateInitialized) { | ||||
|         return -1; | ||||
|     } | ||||
|     if (name == NULL || hook == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     if (type != CMD_TYPE_COMMAND && type != CMD_TYPE_FUNCTION) { | ||||
|         return -1; | ||||
|     } | ||||
|     if (argType != CMD_ARGS_BOOLEAN && argType != CMD_ARGS_WORDS) { | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     entry = (CommandEntry *)malloc(sizeof(CommandEntry)); | ||||
|     if (entry != NULL) { | ||||
|         entry->name = strdup(name); | ||||
|         if (entry->name != NULL) { | ||||
|             int ret; | ||||
|  | ||||
|             entry->cookie = cookie; | ||||
|             entry->type = type; | ||||
|             entry->argType = argType; | ||||
|             entry->hook = hook; | ||||
|             ret = addToSymbolTable(gCommandState.symbolTable, | ||||
|                         entry->name, entry->type, entry); | ||||
|             if (ret == 0) { | ||||
|                 return 0; | ||||
|             } | ||||
|         } | ||||
|         free(entry); | ||||
|     } | ||||
|  | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| registerCommand(const char *name, | ||||
|         CommandArgumentType argType, CommandHook hook, void *cookie) | ||||
| { | ||||
|     return registerCommandInternal(name, | ||||
|             CMD_TYPE_COMMAND, argType, hook, cookie); | ||||
| } | ||||
|  | ||||
| int | ||||
| registerFunction(const char *name, FunctionHook hook, void *cookie) | ||||
| { | ||||
|     return registerCommandInternal(name, | ||||
|             CMD_TYPE_FUNCTION, CMD_ARGS_WORDS, (CommandHook)hook, cookie); | ||||
| } | ||||
|  | ||||
| Command * | ||||
| findCommand(const char *name) | ||||
| { | ||||
|     return (Command *)findInSymbolTable(gCommandState.symbolTable, | ||||
|             name, CMD_TYPE_COMMAND); | ||||
| } | ||||
|  | ||||
| Function * | ||||
| findFunction(const char *name) | ||||
| { | ||||
|     return (Function *)findInSymbolTable(gCommandState.symbolTable, | ||||
|             name, CMD_TYPE_FUNCTION); | ||||
| } | ||||
|  | ||||
| CommandArgumentType | ||||
| getCommandArgumentType(Command *cmd) | ||||
| { | ||||
|     CommandEntry *entry = (CommandEntry *)cmd; | ||||
|  | ||||
|     if (entry != NULL) { | ||||
|         return entry->argType; | ||||
|     } | ||||
|     return CMD_ARGS_UNKNOWN; | ||||
| } | ||||
|  | ||||
| static int | ||||
| callCommandInternal(CommandEntry *entry, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     if (entry != NULL && entry->argType == CMD_ARGS_WORDS && | ||||
|             (argc == 0 || (argc > 0 && argv != NULL))) | ||||
|     { | ||||
|         if (permissions == NULL) { | ||||
|             int i; | ||||
|             for (i = 0; i < argc; i++) { | ||||
|                 if (argv[i] == NULL) { | ||||
|                     goto bail; | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|         TRACE("calling command %s\n", entry->name); | ||||
|         return entry->hook(entry->name, entry->cookie, argc, argv, permissions); | ||||
| //xxx if permissions, make sure the entry has added at least one element. | ||||
|     } | ||||
| bail: | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| static int | ||||
| callBooleanCommandInternal(CommandEntry *entry, bool arg, | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     if (entry != NULL && entry->argType == CMD_ARGS_BOOLEAN) { | ||||
|         TRACE("calling boolean command %s\n", entry->name); | ||||
|         return entry->hook(entry->name, entry->cookie, arg ? 1 : 0, NULL, | ||||
|                 permissions); | ||||
| //xxx if permissions, make sure the entry has added at least one element. | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| callCommand(Command *cmd, int argc, const char *argv[]) | ||||
| { | ||||
|     return callCommandInternal((CommandEntry *)cmd, argc, argv, NULL); | ||||
| } | ||||
|  | ||||
| int | ||||
| callBooleanCommand(Command *cmd, bool arg) | ||||
| { | ||||
|     return callBooleanCommandInternal((CommandEntry *)cmd, arg, NULL); | ||||
| } | ||||
|  | ||||
| int | ||||
| getCommandPermissions(Command *cmd, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     if (permissions != NULL) { | ||||
|         return callCommandInternal((CommandEntry *)cmd, argc, argv, | ||||
|                 permissions); | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| getBooleanCommandPermissions(Command *cmd, bool arg, | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     if (permissions != NULL) { | ||||
|         return callBooleanCommandInternal((CommandEntry *)cmd, arg, | ||||
|                 permissions); | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| callFunctionInternal(CommandEntry *entry, int argc, const char *argv[], | ||||
|         char **result, size_t *resultLen, PermissionRequestList *permissions) | ||||
| { | ||||
|     if (entry != NULL && entry->argType == CMD_ARGS_WORDS && | ||||
|             (argc == 0 || (argc > 0 && argv != NULL))) | ||||
|     { | ||||
|         if ((permissions == NULL && result != NULL) || | ||||
|                 (permissions != NULL && result == NULL)) | ||||
|         { | ||||
|             if (permissions == NULL) { | ||||
|                 /* This is the actual invocation of the function, | ||||
|                  * which means that none of the arguments are allowed | ||||
|                  * to be NULL. | ||||
|                  */ | ||||
|                 int i; | ||||
|                 for (i = 0; i < argc; i++) { | ||||
|                     if (argv[i] == NULL) { | ||||
|                         goto bail; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             TRACE("calling function %s\n", entry->name); | ||||
|             return ((FunctionHook)entry->hook)(entry->name, entry->cookie, | ||||
|                     argc, argv, result, resultLen, permissions); | ||||
| //xxx if permissions, make sure the entry has added at least one element. | ||||
|         } | ||||
|     } | ||||
| bail: | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| callFunction(Function *fn, int argc, const char *argv[], | ||||
|         char **result, size_t *resultLen) | ||||
| { | ||||
|     return callFunctionInternal((CommandEntry *)fn, argc, argv, | ||||
|             result, resultLen, NULL); | ||||
| } | ||||
|  | ||||
| int | ||||
| getFunctionPermissions(Function *fn, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     if (permissions != NULL) { | ||||
|         return callFunctionInternal((CommandEntry *)fn, argc, argv, | ||||
|                 NULL, NULL, permissions); | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
							
								
								
									
										96
									
								
								amend/commands.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								amend/commands.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,96 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef AMEND_COMMANDS_H_ | ||||
| #define AMEND_COMMANDS_H_ | ||||
|  | ||||
| #include "permissions.h" | ||||
|  | ||||
| /* Invoke or dry-run a command.  If "permissions" is non-NULL, | ||||
|  * the hook should fill it out with the list of files and operations that | ||||
|  * it would need to complete its operation.  If "permissions" is NULL, | ||||
|  * the hook should do the actual work specified by its arguments. | ||||
|  * | ||||
|  * When a command is called with non-NULL "permissions", some arguments | ||||
|  * may be NULL.  A NULL argument indicates that the argument is actually | ||||
|  * the output of another function, so is not known at permissions time. | ||||
|  * The permissions of leaf-node functions (those that have only literal | ||||
|  * strings as arguments) will get appended to the permissions of the | ||||
|  * functions that call them.  However, to be completely safe, functions | ||||
|  * that receive a NULL argument should request the broadest-possible | ||||
|  * permissions for the range of the input argument. | ||||
|  * | ||||
|  * When a boolean command is called, "argc" is the boolean value and | ||||
|  * "argv" is NULL. | ||||
|  */ | ||||
| typedef int (*CommandHook)(const char *name, void *cookie, | ||||
|                                 int argc, const char *argv[], | ||||
|                                 PermissionRequestList *permissions); | ||||
|  | ||||
| int commandInit(void); | ||||
| void commandCleanup(void); | ||||
|  | ||||
| /* | ||||
|  * Command management | ||||
|  */ | ||||
|  | ||||
| struct Command; | ||||
| typedef struct Command Command; | ||||
|  | ||||
| typedef enum { | ||||
|     CMD_ARGS_UNKNOWN = -1, | ||||
|     CMD_ARGS_BOOLEAN = 0, | ||||
|     CMD_ARGS_WORDS | ||||
| } CommandArgumentType; | ||||
|  | ||||
| int registerCommand(const char *name, | ||||
|         CommandArgumentType argType, CommandHook hook, void *cookie); | ||||
|  | ||||
| Command *findCommand(const char *name); | ||||
|  | ||||
| CommandArgumentType getCommandArgumentType(Command *cmd); | ||||
|  | ||||
| int callCommand(Command *cmd, int argc, const char *argv[]); | ||||
| int callBooleanCommand(Command *cmd, bool arg); | ||||
|  | ||||
| int getCommandPermissions(Command *cmd, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions); | ||||
| int getBooleanCommandPermissions(Command *cmd, bool arg, | ||||
|         PermissionRequestList *permissions); | ||||
|  | ||||
| /* | ||||
|  * Function management | ||||
|  */ | ||||
|  | ||||
| typedef int (*FunctionHook)(const char *name, void *cookie, | ||||
|                                 int argc, const char *argv[], | ||||
|                                 char **result, size_t *resultLen, | ||||
|                                 PermissionRequestList *permissions); | ||||
|  | ||||
| struct Function; | ||||
| typedef struct Function Function; | ||||
|  | ||||
| int registerFunction(const char *name, FunctionHook hook, void *cookie); | ||||
|  | ||||
| Function *findFunction(const char *name); | ||||
|  | ||||
| int callFunction(Function *fn, int argc, const char *argv[], | ||||
|         char **result, size_t *resultLen); | ||||
|  | ||||
| int getFunctionPermissions(Function *fn, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions); | ||||
|  | ||||
| #endif  // AMEND_COMMANDS_H_ | ||||
							
								
								
									
										315
									
								
								amend/execute.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								amend/execute.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,315 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #undef NDEBUG | ||||
| #include <assert.h> | ||||
| #include "ast.h" | ||||
| #include "execute.h" | ||||
|  | ||||
| typedef struct { | ||||
|     int c; | ||||
|     const char **v; | ||||
| } StringList; | ||||
|  | ||||
| static int execBooleanValue(ExecContext *ctx, | ||||
|         const AmBooleanValue *booleanValue, bool *result); | ||||
| static int execStringValue(ExecContext *ctx, const AmStringValue *stringValue, | ||||
|         const char **result); | ||||
|  | ||||
| static int | ||||
| execBooleanExpression(ExecContext *ctx, | ||||
|         const AmBooleanExpression *booleanExpression, bool *result) | ||||
| { | ||||
|     int ret; | ||||
|     bool arg1, arg2; | ||||
|     bool unary; | ||||
|  | ||||
|     assert(ctx != NULL); | ||||
|     assert(booleanExpression != NULL); | ||||
|     assert(result != NULL); | ||||
|     if (ctx == NULL || booleanExpression == NULL || result == NULL) { | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     if (booleanExpression->op == AM_BOP_NOT) { | ||||
|         unary = true; | ||||
|     } else { | ||||
|         unary = false; | ||||
|     } | ||||
|  | ||||
|     ret = execBooleanValue(ctx, booleanExpression->arg1, &arg1); | ||||
|     if (ret != 0) return ret; | ||||
|  | ||||
|     if (!unary) { | ||||
|         ret = execBooleanValue(ctx, booleanExpression->arg2, &arg2); | ||||
|         if (ret != 0) return ret; | ||||
|     } else { | ||||
|         arg2 = false; | ||||
|     } | ||||
|  | ||||
|     switch (booleanExpression->op) { | ||||
|     case AM_BOP_NOT: | ||||
|         *result = !arg1; | ||||
|         break; | ||||
|     case AM_BOP_EQ: | ||||
|         *result = (arg1 == arg2); | ||||
|         break; | ||||
|     case AM_BOP_NE: | ||||
|         *result = (arg1 != arg2); | ||||
|         break; | ||||
|     case AM_BOP_AND: | ||||
|         *result = (arg1 && arg2); | ||||
|         break; | ||||
|     case AM_BOP_OR: | ||||
|         *result = (arg1 || arg2); | ||||
|         break; | ||||
|     default: | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| execFunctionArguments(ExecContext *ctx, | ||||
|         const AmFunctionArguments *functionArguments, StringList *result) | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     assert(ctx != NULL); | ||||
|     assert(functionArguments != NULL); | ||||
|     assert(result != NULL); | ||||
|     if (ctx == NULL || functionArguments == NULL || result == NULL) { | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     result->c = functionArguments->argc; | ||||
|     result->v = (const char **)malloc(result->c * sizeof(const char *)); | ||||
|     if (result->v == NULL) { | ||||
|         result->c = 0; | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     int i; | ||||
|     for (i = 0; i < functionArguments->argc; i++) { | ||||
|         ret = execStringValue(ctx, &functionArguments->argv[i], &result->v[i]); | ||||
|         if (ret != 0) { | ||||
|             result->c = 0; | ||||
|             free(result->v); | ||||
|             //TODO: free the individual args, if we're responsible for them. | ||||
|             result->v = NULL; | ||||
|             return ret; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| execFunctionCall(ExecContext *ctx, const AmFunctionCall *functionCall, | ||||
|         const char **result) | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     assert(ctx != NULL); | ||||
|     assert(functionCall != NULL); | ||||
|     assert(result != NULL); | ||||
|     if (ctx == NULL || functionCall == NULL || result == NULL) { | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     StringList args; | ||||
|     ret = execFunctionArguments(ctx, functionCall->args, &args); | ||||
|     if (ret != 0) { | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     ret = callFunction(functionCall->fn, args.c, args.v, (char **)result, NULL); | ||||
|     if (ret != 0) { | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     //TODO: clean up args | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| execStringValue(ExecContext *ctx, const AmStringValue *stringValue, | ||||
|         const char **result) | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     assert(ctx != NULL); | ||||
|     assert(stringValue != NULL); | ||||
|     assert(result != NULL); | ||||
|     if (ctx == NULL || stringValue == NULL || result == NULL) { | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     switch (stringValue->type) { | ||||
|     case AM_SVAL_LITERAL: | ||||
|         *result = strdup(stringValue->u.literal); | ||||
|         break; | ||||
|     case AM_SVAL_FUNCTION: | ||||
|         ret = execFunctionCall(ctx, stringValue->u.function, result); | ||||
|         if (ret != 0) { | ||||
|             return ret; | ||||
|         } | ||||
|         break; | ||||
|     default: | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| execStringComparisonExpression(ExecContext *ctx, | ||||
|         const AmStringComparisonExpression *stringComparisonExpression, | ||||
|         bool *result) | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     assert(ctx != NULL); | ||||
|     assert(stringComparisonExpression != NULL); | ||||
|     assert(result != NULL); | ||||
|     if (ctx == NULL || stringComparisonExpression == NULL || result == NULL) { | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     const char *arg1, *arg2; | ||||
|     ret = execStringValue(ctx, stringComparisonExpression->arg1, &arg1); | ||||
|     if (ret != 0) { | ||||
|         return ret; | ||||
|     } | ||||
|     ret = execStringValue(ctx, stringComparisonExpression->arg2, &arg2); | ||||
|     if (ret != 0) { | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     int cmp = strcmp(arg1, arg2); | ||||
|  | ||||
|     switch (stringComparisonExpression->op) { | ||||
|     case AM_SOP_LT: | ||||
|         *result = (cmp < 0); | ||||
|         break; | ||||
|     case AM_SOP_LE: | ||||
|         *result = (cmp <= 0); | ||||
|         break; | ||||
|     case AM_SOP_GT: | ||||
|         *result = (cmp > 0); | ||||
|         break; | ||||
|     case AM_SOP_GE: | ||||
|         *result = (cmp >= 0); | ||||
|         break; | ||||
|     case AM_SOP_EQ: | ||||
|         *result = (cmp == 0); | ||||
|         break; | ||||
|     case AM_SOP_NE: | ||||
|         *result = (cmp != 0); | ||||
|         break; | ||||
|     default: | ||||
|         return -__LINE__; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| execBooleanValue(ExecContext *ctx, const AmBooleanValue *booleanValue, | ||||
|         bool *result) | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     assert(ctx != NULL); | ||||
|     assert(booleanValue != NULL); | ||||
|     assert(result != NULL); | ||||
|     if (ctx == NULL || booleanValue == NULL || result == NULL) { | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     switch (booleanValue->type) { | ||||
|     case AM_BVAL_EXPRESSION: | ||||
|         ret = execBooleanExpression(ctx, &booleanValue->u.expression, result); | ||||
|         break; | ||||
|     case AM_BVAL_STRING_COMPARISON: | ||||
|         ret = execStringComparisonExpression(ctx, | ||||
|                 &booleanValue->u.stringComparison, result); | ||||
|         break; | ||||
|     default: | ||||
|         ret = -__LINE__; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int | ||||
| execCommand(ExecContext *ctx, const AmCommand *command) | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     assert(ctx != NULL); | ||||
|     assert(command != NULL); | ||||
|     if (ctx == NULL || command == NULL) { | ||||
|         return -__LINE__; | ||||
|     } | ||||
|  | ||||
|     CommandArgumentType argType; | ||||
|     argType = getCommandArgumentType(command->cmd); | ||||
|     switch (argType) { | ||||
|     case CMD_ARGS_BOOLEAN: | ||||
|         { | ||||
|             bool bVal; | ||||
|             ret = execBooleanValue(ctx, command->args->u.b, &bVal); | ||||
|             if (ret == 0) { | ||||
|                 ret = callBooleanCommand(command->cmd, bVal); | ||||
|             } | ||||
|         } | ||||
|         break; | ||||
|     case CMD_ARGS_WORDS: | ||||
|         { | ||||
|             AmWordList *words = command->args->u.w; | ||||
|             ret = callCommand(command->cmd, words->argc, words->argv); | ||||
|         } | ||||
|         break; | ||||
|     default: | ||||
|         ret = -__LINE__; | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| int | ||||
| execCommandList(ExecContext *ctx, const AmCommandList *commandList) | ||||
| { | ||||
|     int i; | ||||
|     for (i = 0; i < commandList->commandCount; i++) { | ||||
|         int ret = execCommand(ctx, commandList->commands[i]); | ||||
|         if (ret != 0) { | ||||
|             int line = commandList->commands[i]->line; | ||||
|             return line > 0 ? line : ret; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										25
									
								
								amend/execute.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								amend/execute.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef AMEND_EXECUTE_H_ | ||||
| #define AMEND_EXECUTE_H_ | ||||
|  | ||||
| typedef struct ExecContext ExecContext; | ||||
|  | ||||
| /* Returns 0 on success, otherwise the line number that failed. */ | ||||
| int execCommandList(ExecContext *ctx, const AmCommandList *commandList); | ||||
|  | ||||
| #endif  // AMEND_EXECUTE_H_ | ||||
							
								
								
									
										43
									
								
								amend/lexer.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								amend/lexer.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef AMEND_LEXER_H_ | ||||
| #define AMEND_LEXER_H_ | ||||
|  | ||||
| #define AMEND_LEXER_BUFFER_INPUT 1 | ||||
|  | ||||
| void yyerror(const char *msg); | ||||
| int yylex(void); | ||||
|  | ||||
| #if AMEND_LEXER_BUFFER_INPUT | ||||
| void setLexerInputBuffer(const char *buf, size_t buflen); | ||||
| #else | ||||
| #include <stdio.h> | ||||
| void yyset_in(FILE *in_str); | ||||
| #endif | ||||
|  | ||||
| const char *tokenToString(int token); | ||||
|  | ||||
| typedef enum { | ||||
|     AM_UNKNOWN_ARGS, | ||||
|     AM_WORD_ARGS, | ||||
|     AM_BOOLEAN_ARGS, | ||||
| } AmArgumentType; | ||||
|  | ||||
| void setLexerArgumentType(AmArgumentType type); | ||||
| int getLexerLineNumber(void); | ||||
|  | ||||
| #endif  // AMEND_LEXER_H_ | ||||
							
								
								
									
										299
									
								
								amend/lexer.l
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										299
									
								
								amend/lexer.l
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,299 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| %{ | ||||
|     #include <stdio.h> | ||||
|     #include <stdlib.h> | ||||
|     #include "ast.h" | ||||
|     #include "lexer.h" | ||||
|     #include "parser.h" | ||||
|  | ||||
|     const char *tokenToString(int token) | ||||
|     { | ||||
|         static char scratch[128]; | ||||
|  | ||||
|         switch (token) { | ||||
|         case TOK_AND: | ||||
|             return "&&"; | ||||
|         case TOK_OR: | ||||
|             return "||"; | ||||
|         case TOK_EQ: | ||||
|             return "=="; | ||||
|         case TOK_NE: | ||||
|             return "!="; | ||||
|         case TOK_GE: | ||||
|             return ">="; | ||||
|         case TOK_LE: | ||||
|             return "<="; | ||||
|         case TOK_EOF: | ||||
|             return "EOF"; | ||||
|         case TOK_EOL: | ||||
|             return "EOL\n"; | ||||
|         case TOK_STRING: | ||||
|             snprintf(scratch, sizeof(scratch), | ||||
|                     "STRING<%s>", yylval.literalString); | ||||
|             return scratch; | ||||
|         case TOK_IDENTIFIER: | ||||
|             snprintf(scratch, sizeof(scratch), "IDENTIFIER<%s>", | ||||
|                     yylval.literalString); | ||||
|             return scratch; | ||||
|         case TOK_WORD: | ||||
|             snprintf(scratch, sizeof(scratch), "WORD<%s>", | ||||
|                     yylval.literalString); | ||||
|             return scratch; | ||||
|         default: | ||||
|             if (token > ' ' && token <= '~') { | ||||
|                 scratch[0] = (char)token; | ||||
|                 scratch[1] = '\0'; | ||||
|             } else { | ||||
|                 snprintf(scratch, sizeof(scratch), "??? <%d>", token); | ||||
|             } | ||||
|             return scratch; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     typedef struct { | ||||
|         char *value; | ||||
|         char *nextc; | ||||
|         unsigned int alloc_size; | ||||
|     } AmString; | ||||
|  | ||||
|     static int addCharToString(AmString *str, char c) | ||||
|     { | ||||
|         if ((unsigned int)(str->nextc - str->value) >= str->alloc_size) { | ||||
|             char *new_value; | ||||
|             unsigned int new_size; | ||||
|  | ||||
|             new_size = (str->alloc_size + 1) * 2; | ||||
|             if (new_size < 64) { | ||||
|                 new_size = 64; | ||||
|             } | ||||
|  | ||||
|             new_value = (char *)realloc(str->value, new_size); | ||||
|             if (new_value == NULL) { | ||||
|                 yyerror("out of memory"); | ||||
|                 return -1; | ||||
|             } | ||||
|             str->nextc = str->nextc - str->value + new_value; | ||||
|             str->value = new_value; | ||||
|             str->alloc_size = new_size; | ||||
|         } | ||||
|         *str->nextc++ = c; | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     static int setString(AmString *str, const char *p) | ||||
|     { | ||||
|         str->nextc = str->value; | ||||
|         while (*p != '\0') { | ||||
| //TODO: add the whole string at once | ||||
|             addCharToString(str, *p++); | ||||
|         } | ||||
|         return addCharToString(str, '\0'); | ||||
|     } | ||||
|  | ||||
|     static AmString gStr = { NULL, NULL, 0 }; | ||||
|     static int gLineNumber = 1; | ||||
|     static AmArgumentType gArgumentType = AM_UNKNOWN_ARGS; | ||||
|     static const char *gErrorMessage = NULL; | ||||
|  | ||||
| #if AMEND_LEXER_BUFFER_INPUT | ||||
|     static const char *gInputBuffer; | ||||
|     static const char *gInputBufferNext; | ||||
|     static const char *gInputBufferEnd; | ||||
|  | ||||
| # define YY_INPUT(buf, result, max_size) \ | ||||
|     do { \ | ||||
|         int nbytes = gInputBufferEnd - gInputBufferNext; \ | ||||
|         if (nbytes > 0) { \ | ||||
|             if (nbytes > max_size) { \ | ||||
|                 nbytes = max_size; \ | ||||
|             } \ | ||||
|             memcpy(buf, gInputBufferNext, nbytes); \ | ||||
|             gInputBufferNext += nbytes; \ | ||||
|             result = nbytes; \ | ||||
|         } else { \ | ||||
|             result = YY_NULL; \ | ||||
|         } \ | ||||
|     } while (false) | ||||
| #endif  // AMEND_LEXER_BUFFER_INPUT | ||||
|  | ||||
| %} | ||||
|  | ||||
| %option noyywrap | ||||
|  | ||||
| %x QUOTED_STRING BOOLEAN WORDS | ||||
|  | ||||
| ident [a-zA-Z_][a-zA-Z_0-9]* | ||||
| word [^ \t\r\n"]+ | ||||
|  | ||||
| %% | ||||
|     /* This happens at the beginning of each call to yylex(). | ||||
|      */ | ||||
|     if (gArgumentType == AM_WORD_ARGS) { | ||||
|         BEGIN(WORDS); | ||||
|     } else if (gArgumentType == AM_BOOLEAN_ARGS) { | ||||
|         BEGIN(BOOLEAN); | ||||
|     } | ||||
|  | ||||
|         /*xxx require everything to be 7-bit-clean, printable characters */ | ||||
| <INITIAL>{ | ||||
|         {ident}/[ \t\r\n] { | ||||
|                 /* The only token we recognize in the initial | ||||
|                  * state is an identifier followed by whitespace. | ||||
|                  */ | ||||
|                 setString(&gStr, yytext); | ||||
|                 yylval.literalString = gStr.value; | ||||
|                 return TOK_IDENTIFIER; | ||||
|             } | ||||
|     } | ||||
|  | ||||
| <BOOLEAN>{ | ||||
|         {ident} { | ||||
|                 /* Non-quoted identifier-style string */ | ||||
|                 setString(&gStr, yytext); | ||||
|                 yylval.literalString = gStr.value; | ||||
|                 return TOK_IDENTIFIER; | ||||
|             } | ||||
|         "&&"    return TOK_AND; | ||||
|         "||"    return TOK_OR; | ||||
|         "=="    return TOK_EQ; | ||||
|         "!="    return TOK_NE; | ||||
|         ">="    return TOK_GE; | ||||
|         "<="    return TOK_LE; | ||||
|         [<>()!,] return yytext[0]; | ||||
|     } | ||||
|  | ||||
|     /* Double-quoted string handling */ | ||||
|  | ||||
| <WORDS,BOOLEAN>\"  { | ||||
|         /* Initial quote */ | ||||
|         gStr.nextc = gStr.value; | ||||
|         BEGIN(QUOTED_STRING); | ||||
|     } | ||||
|  | ||||
| <QUOTED_STRING>{ | ||||
|         \"  { | ||||
|                 /* Closing quote */ | ||||
|                 BEGIN(INITIAL); | ||||
|                 addCharToString(&gStr, '\0'); | ||||
|                 yylval.literalString = gStr.value; | ||||
|                 if (gArgumentType == AM_WORD_ARGS) { | ||||
|                     return TOK_WORD; | ||||
|                 } else { | ||||
|                     return TOK_STRING; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         <<EOF>> | | ||||
|         \n  { | ||||
|                 /* Unterminated string */ | ||||
|                 yyerror("unterminated string"); | ||||
|                 return TOK_ERROR; | ||||
|             } | ||||
|  | ||||
|         \\\" { | ||||
|                 /* Escaped quote */ | ||||
|                 addCharToString(&gStr, '"'); | ||||
|             } | ||||
|  | ||||
|         \\\\ { | ||||
|                 /* Escaped backslash */ | ||||
|                 addCharToString(&gStr, '\\'); | ||||
|             } | ||||
|  | ||||
|         \\. { | ||||
|                 /* No other escapes allowed. */ | ||||
|                 gErrorMessage = "illegal escape"; | ||||
|                 return TOK_ERROR; | ||||
|             } | ||||
|  | ||||
|         [^\\\n\"]+ { | ||||
|                 /* String contents */ | ||||
|                 char *p = yytext; | ||||
|                 while (*p != '\0') { | ||||
|         /* TODO: add the whole string at once */ | ||||
|                     addCharToString(&gStr, *p++); | ||||
|                 } | ||||
|             } | ||||
|     } | ||||
|  | ||||
| <WORDS>{ | ||||
|         /*xxx look out for backslashes; escape backslashes and quotes */ | ||||
|         /*xxx if a quote is right against a char, we should append */ | ||||
|         {word} { | ||||
|                 /* Whitespace-separated word */ | ||||
|                 setString(&gStr, yytext); | ||||
|                 yylval.literalString = gStr.value; | ||||
|                 return TOK_WORD; | ||||
|             } | ||||
|     } | ||||
|  | ||||
| <INITIAL,WORDS,BOOLEAN>{ | ||||
|         \n  { | ||||
|                 /* Count lines */ | ||||
|                 gLineNumber++; | ||||
|                 gArgumentType = AM_UNKNOWN_ARGS; | ||||
|                 BEGIN(INITIAL); | ||||
|                 return TOK_EOL; | ||||
|             } | ||||
|  | ||||
|         /*xxx backslashes to extend lines? */ | ||||
|             /* Skip whitespace and comments. | ||||
|              */ | ||||
|         [ \t\r]+ ; | ||||
|         #.*      ; | ||||
|  | ||||
|         .   { | ||||
|                 /* Fail on anything we didn't expect. */ | ||||
|                 gErrorMessage = "unexpected character"; | ||||
|                 return TOK_ERROR; | ||||
|             } | ||||
|     } | ||||
| %% | ||||
|  | ||||
| void | ||||
| yyerror(const char *msg) | ||||
| { | ||||
|     if (!strcmp(msg, "syntax error") && gErrorMessage != NULL) { | ||||
|         msg = gErrorMessage; | ||||
|         gErrorMessage = NULL; | ||||
|     } | ||||
|     fprintf(stderr, "line %d: %s at '%s'\n", gLineNumber, msg, yytext); | ||||
| } | ||||
|  | ||||
| #if AMEND_LEXER_BUFFER_INPUT | ||||
| void | ||||
| setLexerInputBuffer(const char *buf, size_t buflen) | ||||
| { | ||||
|     gLineNumber = 1; | ||||
|     gInputBuffer = buf; | ||||
|     gInputBufferNext = gInputBuffer; | ||||
|     gInputBufferEnd = gInputBuffer + buflen; | ||||
| } | ||||
| #endif  // AMEND_LEXER_BUFFER_INPUT | ||||
|  | ||||
| void | ||||
| setLexerArgumentType(AmArgumentType type) | ||||
| { | ||||
|     gArgumentType = type; | ||||
| } | ||||
|  | ||||
| int | ||||
| getLexerLineNumber(void) | ||||
| { | ||||
|     return gLineNumber; | ||||
| } | ||||
							
								
								
									
										195
									
								
								amend/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										195
									
								
								amend/main.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,195 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include "ast.h" | ||||
| #include "lexer.h" | ||||
| #include "parser.h" | ||||
| #include "register.h" | ||||
| #include "execute.h" | ||||
|  | ||||
| void | ||||
| lexTest() | ||||
| { | ||||
|     int token; | ||||
|     do { | ||||
|         token = yylex(); | ||||
|         if (token == 0) { | ||||
|             printf(" EOF"); | ||||
|             fflush(stdout); | ||||
|             break; | ||||
|         } else { | ||||
|             printf(" %s", tokenToString(token)); | ||||
|             fflush(stdout); | ||||
|             if (token == TOK_IDENTIFIER) { | ||||
|                 if (strcmp(yylval.literalString, "assert") == 0) { | ||||
|                     setLexerArgumentType(AM_BOOLEAN_ARGS); | ||||
|                 } else { | ||||
|                     setLexerArgumentType(AM_WORD_ARGS); | ||||
|                 } | ||||
|                 do { | ||||
|                     token = yylex(); | ||||
|                     printf(" %s", tokenToString(token)); | ||||
|                     fflush(stdout); | ||||
|                 } while (token != TOK_EOL && token != TOK_EOF && token != 0); | ||||
|             } else if (token != TOK_EOL) { | ||||
|                 fprintf(stderr, "syntax error: expected identifier\n"); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|     } while (token != 0); | ||||
|     printf("\n"); | ||||
| } | ||||
|  | ||||
| void | ||||
| usage() | ||||
| { | ||||
|     printf("usage: amend [--debug-lex|--debug-ast] [<filename>]\n"); | ||||
|     exit(1); | ||||
| } | ||||
|  | ||||
| extern const AmCommandList *gCommands; | ||||
| int | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
|     FILE *inputFile = NULL; | ||||
|     bool debugLex = false; | ||||
|     bool debugAst = false; | ||||
|     const char *fileName = NULL; | ||||
|     int err; | ||||
|  | ||||
| #if 1 | ||||
|     extern int test_symtab(void); | ||||
|     int ret = test_symtab(); | ||||
|     if (ret != 0) { | ||||
|         fprintf(stderr, "test_symtab() failed: %d\n", ret); | ||||
|         exit(ret); | ||||
|     } | ||||
|     extern int test_cmd_fn(void); | ||||
|     ret = test_cmd_fn(); | ||||
|     if (ret != 0) { | ||||
|         fprintf(stderr, "test_cmd_fn() failed: %d\n", ret); | ||||
|         exit(ret); | ||||
|     } | ||||
|     extern int test_permissions(void); | ||||
|     ret = test_permissions(); | ||||
|     if (ret != 0) { | ||||
|         fprintf(stderr, "test_permissions() failed: %d\n", ret); | ||||
|         exit(ret); | ||||
|     } | ||||
| #endif | ||||
|  | ||||
|     argc--; | ||||
|     argv++; | ||||
|     while (argc > 0) { | ||||
|         if (strcmp("--debug-lex", argv[0]) == 0) { | ||||
|             debugLex = true; | ||||
|         } else if (strcmp("--debug-ast", argv[0]) == 0) { | ||||
|             debugAst = true; | ||||
|         } else if (argv[0][0] == '-') { | ||||
|             fprintf(stderr, "amend: Unknown option \"%s\"\n", argv[0]); | ||||
|             usage(); | ||||
|         } else { | ||||
|             fileName = argv[0]; | ||||
|         } | ||||
|         argc--; | ||||
|         argv++; | ||||
|     } | ||||
|  | ||||
|     if (fileName != NULL) { | ||||
|         inputFile = fopen(fileName, "r"); | ||||
|         if (inputFile == NULL) { | ||||
|             fprintf(stderr, "amend: Can't open input file '%s'\n", fileName); | ||||
|             usage(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     commandInit(); | ||||
| //xxx clean up | ||||
|  | ||||
|     err = registerUpdateCommands(); | ||||
|     if (err < 0) { | ||||
|         fprintf(stderr, "amend: Error registering commands: %d\n", err); | ||||
|         exit(-err); | ||||
|     } | ||||
|     err = registerUpdateFunctions(); | ||||
|     if (err < 0) { | ||||
|         fprintf(stderr, "amend: Error registering functions: %d\n", err); | ||||
|         exit(-err); | ||||
|     } | ||||
|  | ||||
| #if AMEND_LEXER_BUFFER_INPUT | ||||
|     if (inputFile == NULL) { | ||||
|         fprintf(stderr, "amend: No input file\n"); | ||||
|         usage(); | ||||
|     } | ||||
|     char *fileData; | ||||
|     int fileDataLen; | ||||
|     fseek(inputFile, 0, SEEK_END); | ||||
|     fileDataLen = ftell(inputFile); | ||||
|     rewind(inputFile); | ||||
|     if (fileDataLen < 0) { | ||||
|         fprintf(stderr, "amend: Can't get file length\n"); | ||||
|         exit(2); | ||||
|     } else if (fileDataLen == 0) { | ||||
|         printf("amend: Empty input file\n"); | ||||
|         exit(0); | ||||
|     } | ||||
|     fileData = (char *)malloc(fileDataLen + 1); | ||||
|     if (fileData == NULL) { | ||||
|         fprintf(stderr, "amend: Can't allocate %d bytes\n", fileDataLen + 1); | ||||
|         exit(2); | ||||
|     } | ||||
|     size_t nread = fread(fileData, 1, fileDataLen, inputFile); | ||||
|     if (nread != (size_t)fileDataLen) { | ||||
|         fprintf(stderr, "amend: Didn't read %d bytes, only %zd\n", fileDataLen, | ||||
|                 nread); | ||||
|         exit(2); | ||||
|     } | ||||
|     fileData[fileDataLen] = '\0'; | ||||
|     setLexerInputBuffer(fileData, fileDataLen); | ||||
| #else | ||||
|     if (inputFile == NULL) { | ||||
|         inputFile = stdin; | ||||
|     } | ||||
|     yyset_in(inputFile); | ||||
| #endif | ||||
|  | ||||
|     if (debugLex) { | ||||
|         lexTest(); | ||||
|     } else { | ||||
|         int ret = yyparse(); | ||||
|         if (ret != 0) { | ||||
|             fprintf(stderr, "amend: Parse failed (%d)\n", ret); | ||||
|             exit(2); | ||||
|         } else { | ||||
|             if (debugAst) { | ||||
|                 dumpCommandList(gCommands); | ||||
|             } | ||||
| printf("amend: Parse successful.\n"); | ||||
|             ret = execCommandList((ExecContext *)1, gCommands); | ||||
|             if (ret != 0) { | ||||
|                 fprintf(stderr, "amend: Execution failed (%d)\n", ret); | ||||
|                 exit(3); | ||||
|             } | ||||
| printf("amend: Execution successful.\n"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										24
									
								
								amend/parser.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								amend/parser.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef AMEND_PARSER_H_ | ||||
| #define AMEND_PARSER_H_ | ||||
|  | ||||
| #include "parser_y.h" | ||||
|  | ||||
| int yyparse(void); | ||||
|  | ||||
| #endif  // AMEND_PARSER_H_ | ||||
							
								
								
									
										430
									
								
								amend/parser_y.y
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										430
									
								
								amend/parser_y.y
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,430 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| %{ | ||||
| #undef NDEBUG | ||||
|     #include <stdlib.h> | ||||
|     #include <string.h> | ||||
|     #include <assert.h> | ||||
|     #include <stdio.h> | ||||
|     #include "ast.h" | ||||
|     #include "lexer.h" | ||||
|     #include "commands.h" | ||||
|  | ||||
|     void yyerror(const char *msg); | ||||
|     int yylex(void); | ||||
|  | ||||
| #define STRING_COMPARISON(out, a1, sop, a2) \ | ||||
|     do { \ | ||||
|         out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \ | ||||
|         if (out == NULL) { \ | ||||
|             YYABORT; \ | ||||
|         } \ | ||||
|         out->type = AM_BVAL_STRING_COMPARISON; \ | ||||
|         out->u.stringComparison.op = sop; \ | ||||
|         out->u.stringComparison.arg1 = a1; \ | ||||
|         out->u.stringComparison.arg2 = a2; \ | ||||
|     } while (false) | ||||
|  | ||||
| #define BOOLEAN_EXPRESSION(out, a1, bop, a2) \ | ||||
|     do { \ | ||||
|         out = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); \ | ||||
|         if (out == NULL) { \ | ||||
|             YYABORT; \ | ||||
|         } \ | ||||
|         out->type = AM_BVAL_EXPRESSION; \ | ||||
|         out->u.expression.op = bop; \ | ||||
|         out->u.expression.arg1 = a1; \ | ||||
|         out->u.expression.arg2 = a2; \ | ||||
|     } while (false) | ||||
|  | ||||
| AmCommandList *gCommands = NULL; | ||||
| %} | ||||
|  | ||||
| %start  lines | ||||
|  | ||||
| %union  { | ||||
|         char *literalString; | ||||
|         AmFunctionArgumentBuilder *functionArgumentBuilder; | ||||
|         AmFunctionArguments *functionArguments; | ||||
|         AmFunctionCall *functionCall; | ||||
|         AmStringValue *stringValue; | ||||
|         AmBooleanValue *booleanValue; | ||||
|         AmWordListBuilder *wordListBuilder; | ||||
|         AmCommandArguments *commandArguments; | ||||
|         AmCommand *command; | ||||
|         AmCommandList *commandList; | ||||
|     } | ||||
|  | ||||
| %token  TOK_AND TOK_OR TOK_EQ TOK_NE TOK_GE TOK_LE TOK_EOF TOK_EOL TOK_ERROR | ||||
| %token  <literalString> TOK_STRING TOK_IDENTIFIER TOK_WORD | ||||
|  | ||||
| %type   <commandList> lines | ||||
| %type   <command> command line | ||||
| %type   <functionArgumentBuilder> function_arguments | ||||
| %type   <functionArguments> function_arguments_or_empty | ||||
| %type   <functionCall> function_call | ||||
| %type   <literalString> function_name | ||||
| %type   <stringValue> string_value | ||||
| %type   <booleanValue> boolean_expression | ||||
| %type   <wordListBuilder> word_list | ||||
| %type   <commandArguments> arguments | ||||
|  | ||||
| /* Operator precedence, weakest to strongest. | ||||
|  * Same as C/Java precedence. | ||||
|  */ | ||||
|  | ||||
| %left   TOK_OR | ||||
| %left   TOK_AND | ||||
| %left   TOK_EQ TOK_NE | ||||
| %left   '<' '>' TOK_LE TOK_GE | ||||
| %right   '!' | ||||
|  | ||||
| %% | ||||
|  | ||||
| lines :     /* empty */ | ||||
|                 { | ||||
|                     $$ = (AmCommandList *)malloc(sizeof(AmCommandList)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
| gCommands = $$; | ||||
|                     $$->arraySize = 64; | ||||
|                     $$->commandCount = 0; | ||||
|                     $$->commands = (AmCommand **)malloc( | ||||
|                             sizeof(AmCommand *) * $$->arraySize); | ||||
|                     if ($$->commands == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                 } | ||||
|         |   lines line | ||||
|                 { | ||||
|                     if ($2 != NULL) { | ||||
|                         if ($1->commandCount >= $1->arraySize) { | ||||
|                             AmCommand **newArray; | ||||
|                             newArray = (AmCommand **)realloc($$->commands, | ||||
|                                 sizeof(AmCommand *) * $$->arraySize * 2); | ||||
|                             if (newArray == NULL) { | ||||
|                                 YYABORT; | ||||
|                             } | ||||
|                             $$->commands = newArray; | ||||
|                             $$->arraySize *= 2; | ||||
|                         } | ||||
|                         $1->commands[$1->commandCount++] = $2; | ||||
|                     } | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
| line :      line_ending | ||||
|                 { | ||||
|                     $$ = NULL;  /* ignore blank lines */ | ||||
|                 } | ||||
|         |   command arguments line_ending | ||||
|                 { | ||||
|                     $$ = $1; | ||||
|                     $$->args = $2; | ||||
|                     setLexerArgumentType(AM_UNKNOWN_ARGS); | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
| command :   TOK_IDENTIFIER | ||||
|                 { | ||||
|                     Command *cmd = findCommand($1); | ||||
|                     if (cmd == NULL) { | ||||
|                         fprintf(stderr, "Unknown command \"%s\"\n", $1); | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$ = (AmCommand *)malloc(sizeof(AmCommand)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->line = getLexerLineNumber(); | ||||
|                     $$->name = strdup($1); | ||||
|                     if ($$->name == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->args = NULL; | ||||
|                     CommandArgumentType argType = getCommandArgumentType(cmd); | ||||
|                     if (argType == CMD_ARGS_BOOLEAN) { | ||||
|                         setLexerArgumentType(AM_BOOLEAN_ARGS); | ||||
|                     } else { | ||||
|                         setLexerArgumentType(AM_WORD_ARGS); | ||||
|                     } | ||||
|                     $$->cmd = cmd; | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
| line_ending : | ||||
|             TOK_EOL | ||||
|         |   TOK_EOF | ||||
|         ; | ||||
|  | ||||
| arguments : boolean_expression | ||||
|                 { | ||||
|                     $$ = (AmCommandArguments *)malloc( | ||||
|                             sizeof(AmCommandArguments)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->booleanArgs = true; | ||||
|                     $$->u.b = $1; | ||||
|                 } | ||||
|         |   word_list | ||||
|                 { | ||||
|                     /* Convert the builder list into an array. | ||||
|                      * Do it in reverse order; the words were pushed | ||||
|                      * onto the list in LIFO order. | ||||
|                      */ | ||||
|                     AmWordList *w = (AmWordList *)malloc(sizeof(AmWordList)); | ||||
|                     if (w == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     if ($1 != NULL) { | ||||
|                         AmWordListBuilder *words = $1; | ||||
|  | ||||
|                         w->argc = words->wordCount; | ||||
|                         w->argv = (const char **)malloc(w->argc * | ||||
|                                         sizeof(char *)); | ||||
|                         if (w->argv == NULL) { | ||||
|                             YYABORT; | ||||
|                         } | ||||
|                         int i; | ||||
|                         for (i = w->argc; words != NULL && i > 0; --i) { | ||||
|                             AmWordListBuilder *f = words; | ||||
|                             w->argv[i-1] = words->word; | ||||
|                             words = words->next; | ||||
|                             free(f); | ||||
|                         } | ||||
|                         assert(i == 0); | ||||
|                         assert(words == NULL); | ||||
|                     } else { | ||||
|                         w->argc = 0; | ||||
|                         w->argv = NULL; | ||||
|                     } | ||||
|                     $$ = (AmCommandArguments *)malloc( | ||||
|                             sizeof(AmCommandArguments)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->booleanArgs = false; | ||||
|                     $$->u.w = w; | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
| word_list : /* empty */ | ||||
|                 { $$ = NULL; } | ||||
|         |   word_list TOK_WORD | ||||
|                 { | ||||
|                     if ($1 == NULL) { | ||||
|                         $$ = (AmWordListBuilder *)malloc( | ||||
|                                 sizeof(AmWordListBuilder)); | ||||
|                         if ($$ == NULL) { | ||||
|                             YYABORT; | ||||
|                         } | ||||
|                         $$->next = NULL; | ||||
|                         $$->wordCount = 1; | ||||
|                     } else { | ||||
|                         $$ = (AmWordListBuilder *)malloc( | ||||
|                                 sizeof(AmWordListBuilder)); | ||||
|                         if ($$ == NULL) { | ||||
|                             YYABORT; | ||||
|                         } | ||||
|                         $$->next = $1; | ||||
|                         $$->wordCount = $$->next->wordCount + 1; | ||||
|                     } | ||||
|                     $$->word = strdup($2); | ||||
|                     if ($$->word == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
| boolean_expression : | ||||
|             '!' boolean_expression | ||||
|                 { | ||||
|                     $$ = (AmBooleanValue *)malloc(sizeof(AmBooleanValue)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->type = AM_BVAL_EXPRESSION; | ||||
|                     $$->u.expression.op = AM_BOP_NOT; | ||||
|                     $$->u.expression.arg1 = $2; | ||||
|                     $$->u.expression.arg2 = NULL; | ||||
|                 } | ||||
|     /* TODO: if both expressions are literals, evaluate now */ | ||||
|         |   boolean_expression TOK_AND boolean_expression | ||||
|                 { BOOLEAN_EXPRESSION($$, $1, AM_BOP_AND, $3); } | ||||
|         |   boolean_expression TOK_OR boolean_expression | ||||
|                 { BOOLEAN_EXPRESSION($$, $1, AM_BOP_OR, $3); } | ||||
|         |   boolean_expression TOK_EQ boolean_expression | ||||
|                 { BOOLEAN_EXPRESSION($$, $1, AM_BOP_EQ, $3); } | ||||
|         |   boolean_expression TOK_NE boolean_expression | ||||
|                 { BOOLEAN_EXPRESSION($$, $1, AM_BOP_NE, $3); } | ||||
|         |   '(' boolean_expression ')' | ||||
|                 { $$ = $2; } | ||||
|     /* TODO: if both strings are literals, evaluate now */ | ||||
|         |   string_value '<' string_value | ||||
|                 { STRING_COMPARISON($$, $1, AM_SOP_LT, $3); } | ||||
|         |   string_value '>' string_value | ||||
|                 { STRING_COMPARISON($$, $1, AM_SOP_GT, $3); } | ||||
|         |   string_value TOK_EQ string_value | ||||
|                 { STRING_COMPARISON($$, $1, AM_SOP_EQ, $3); } | ||||
|         |   string_value TOK_NE string_value | ||||
|                 { STRING_COMPARISON($$, $1, AM_SOP_NE, $3); } | ||||
|         |   string_value TOK_LE string_value | ||||
|                 { STRING_COMPARISON($$, $1, AM_SOP_LE, $3); } | ||||
|         |   string_value TOK_GE string_value | ||||
|                 { STRING_COMPARISON($$, $1, AM_SOP_GE, $3); } | ||||
|         ; | ||||
|  | ||||
| string_value : | ||||
|             TOK_IDENTIFIER | ||||
|                 { | ||||
|                     $$ = (AmStringValue *)malloc(sizeof(AmStringValue)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->type = AM_SVAL_LITERAL; | ||||
|                     $$->u.literal = strdup($1); | ||||
|                     if ($$->u.literal == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                 } | ||||
|         |   TOK_STRING | ||||
|                 { | ||||
|                     $$ = (AmStringValue *)malloc(sizeof(AmStringValue)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->type = AM_SVAL_LITERAL; | ||||
|                     $$->u.literal = strdup($1); | ||||
|                     if ($$->u.literal == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                 } | ||||
|         |   function_call | ||||
|                 { | ||||
|                     $$ = (AmStringValue *)malloc(sizeof(AmStringValue)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->type = AM_SVAL_FUNCTION; | ||||
|                     $$->u.function = $1; | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
|         /* We can't just say | ||||
|          *  TOK_IDENTIFIER '(' function_arguments_or_empty ')' | ||||
|          * because parsing function_arguments_or_empty will clobber | ||||
|          * the underlying string that yylval.literalString points to. | ||||
|          */ | ||||
| function_call : | ||||
|             function_name '(' function_arguments_or_empty ')' | ||||
|                 { | ||||
|                     Function *fn = findFunction($1); | ||||
|                     if (fn == NULL) { | ||||
|                         fprintf(stderr, "Unknown function \"%s\"\n", $1); | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$ = (AmFunctionCall *)malloc(sizeof(AmFunctionCall)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->name = $1; | ||||
|                     if ($$->name == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->fn = fn; | ||||
|                     $$->args = $3; | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
| function_name : | ||||
|             TOK_IDENTIFIER | ||||
|                 { | ||||
|                     $$ = strdup($1); | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
| function_arguments_or_empty : | ||||
|             /* empty */ | ||||
|                 { | ||||
|                     $$ = (AmFunctionArguments *)malloc( | ||||
|                             sizeof(AmFunctionArguments)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->argc = 0; | ||||
|                     $$->argv = NULL; | ||||
|                 } | ||||
|         |   function_arguments | ||||
|                 { | ||||
|                     AmFunctionArgumentBuilder *args = $1; | ||||
|                     assert(args != NULL); | ||||
|  | ||||
|                     /* Convert the builder list into an array. | ||||
|                      * Do it in reverse order; the args were pushed | ||||
|                      * onto the list in LIFO order. | ||||
|                      */ | ||||
|                     $$ = (AmFunctionArguments *)malloc( | ||||
|                             sizeof(AmFunctionArguments)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->argc = args->argCount; | ||||
|                     $$->argv = (AmStringValue *)malloc( | ||||
|                             $$->argc * sizeof(AmStringValue)); | ||||
|                     if ($$->argv == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     int i; | ||||
|                     for (i = $$->argc; args != NULL && i > 0; --i) { | ||||
|                         AmFunctionArgumentBuilder *f = args; | ||||
|                         $$->argv[i-1] = *args->arg; | ||||
|                         args = args->next; | ||||
|                         free(f->arg); | ||||
|                         free(f); | ||||
|                     } | ||||
|                     assert(i == 0); | ||||
|                     assert(args == NULL); | ||||
|                 } | ||||
|         ; | ||||
|  | ||||
| function_arguments : | ||||
|             string_value | ||||
|                 { | ||||
|                     $$ = (AmFunctionArgumentBuilder *)malloc( | ||||
|                             sizeof(AmFunctionArgumentBuilder)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->next = NULL; | ||||
|                     $$->argCount = 1; | ||||
|                     $$->arg = $1; | ||||
|                 } | ||||
|         |   function_arguments ',' string_value | ||||
|                 { | ||||
|                     $$ = (AmFunctionArgumentBuilder *)malloc( | ||||
|                             sizeof(AmFunctionArgumentBuilder)); | ||||
|                     if ($$ == NULL) { | ||||
|                         YYABORT; | ||||
|                     } | ||||
|                     $$->next = $1; | ||||
|                     $$->argCount = $$->next->argCount + 1; | ||||
|                     $$->arg = $3; | ||||
|                 } | ||||
|         ; | ||||
|     /* xxx this whole tool needs to be hardened */ | ||||
							
								
								
									
										270
									
								
								amend/permissions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								amend/permissions.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,270 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include "permissions.h" | ||||
|  | ||||
| int | ||||
| initPermissionRequestList(PermissionRequestList *list) | ||||
| { | ||||
|     if (list != NULL) { | ||||
|         list->requests = NULL; | ||||
|         list->numRequests = 0; | ||||
|         list->requestsAllocated = 0; | ||||
|         return 0; | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| addPermissionRequestToList(PermissionRequestList *list, | ||||
|         const char *path, bool recursive, unsigned int permissions) | ||||
| { | ||||
|     if (list == NULL || list->numRequests < 0 || | ||||
|             list->requestsAllocated < list->numRequests || path == NULL) | ||||
|     { | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     if (list->numRequests == list->requestsAllocated) { | ||||
|         int newSize; | ||||
|         PermissionRequest *newRequests; | ||||
|  | ||||
|         newSize = list->requestsAllocated * 2; | ||||
|         if (newSize < 16) { | ||||
|             newSize = 16; | ||||
|         } | ||||
|         newRequests = (PermissionRequest *)realloc(list->requests, | ||||
|                 newSize * sizeof(PermissionRequest)); | ||||
|         if (newRequests == NULL) { | ||||
|             return -2; | ||||
|         } | ||||
|         list->requests = newRequests; | ||||
|         list->requestsAllocated = newSize; | ||||
|     } | ||||
|  | ||||
|     PermissionRequest *req; | ||||
|     req = &list->requests[list->numRequests++]; | ||||
|     req->path = strdup(path); | ||||
|     if (req->path == NULL) { | ||||
|         list->numRequests--; | ||||
|         return -3; | ||||
|     } | ||||
|     req->recursive = recursive; | ||||
|     req->requested = permissions; | ||||
|     req->allowed = 0; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| freePermissionRequestListElements(PermissionRequestList *list) | ||||
| { | ||||
|     if (list != NULL && list->numRequests >= 0 && | ||||
|             list->requestsAllocated >= list->numRequests) | ||||
|     { | ||||
|         int i; | ||||
|         for (i = 0; i < list->numRequests; i++) { | ||||
|             free((void *)list->requests[i].path); | ||||
|         } | ||||
|         free(list->requests); | ||||
|         initPermissionRequestList(list); | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Global permission table | ||||
|  */ | ||||
|  | ||||
| static struct { | ||||
|     Permission *permissions; | ||||
|     int numPermissionEntries; | ||||
|     int allocatedPermissionEntries; | ||||
|     bool permissionStateInitialized; | ||||
| } gPermissionState = { | ||||
| #if 1 | ||||
|     NULL, 0, 0, false | ||||
| #else | ||||
|     .permissions = NULL, | ||||
|     .numPermissionEntries = 0, | ||||
|     .allocatedPermissionEntries = 0, | ||||
|     .permissionStateInitialized = false | ||||
| #endif | ||||
| }; | ||||
|  | ||||
| int | ||||
| permissionInit() | ||||
| { | ||||
|     if (gPermissionState.permissionStateInitialized) { | ||||
|         return -1; | ||||
|     } | ||||
|     gPermissionState.permissions = NULL; | ||||
|     gPermissionState.numPermissionEntries = 0; | ||||
|     gPermissionState.allocatedPermissionEntries = 0; | ||||
|     gPermissionState.permissionStateInitialized = true; | ||||
| //xxx maybe add an "namespace root gets no permissions" fallback by default | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| permissionCleanup() | ||||
| { | ||||
|     if (gPermissionState.permissionStateInitialized) { | ||||
|         gPermissionState.permissionStateInitialized = false; | ||||
|         if (gPermissionState.permissions != NULL) { | ||||
|             int i; | ||||
|             for (i = 0; i < gPermissionState.numPermissionEntries; i++) { | ||||
|                 free((void *)gPermissionState.permissions[i].path); | ||||
|             } | ||||
|             free(gPermissionState.permissions); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| int | ||||
| getPermissionCount() | ||||
| { | ||||
|     if (gPermissionState.permissionStateInitialized) { | ||||
|         return gPermissionState.numPermissionEntries; | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| const Permission * | ||||
| getPermissionAt(int index) | ||||
| { | ||||
|     if (!gPermissionState.permissionStateInitialized) { | ||||
|         return NULL; | ||||
|     } | ||||
|     if (index < 0 || index >= gPermissionState.numPermissionEntries) { | ||||
|         return NULL; | ||||
|     } | ||||
|     return &gPermissionState.permissions[index]; | ||||
| } | ||||
|  | ||||
| int | ||||
| getAllowedPermissions(const char *path, bool recursive, | ||||
|         unsigned int *outAllowed) | ||||
| { | ||||
|     if (!gPermissionState.permissionStateInitialized) { | ||||
|         return -2; | ||||
|     } | ||||
|     if (outAllowed == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     *outAllowed = 0; | ||||
|     if (path == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     //TODO: implement this for real. | ||||
|     recursive = false; | ||||
|     *outAllowed = PERMSET_ALL; | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| countPermissionConflicts(PermissionRequestList *requests, bool updateAllowed) | ||||
| { | ||||
|     if (!gPermissionState.permissionStateInitialized) { | ||||
|         return -2; | ||||
|     } | ||||
|     if (requests == NULL || requests->requests == NULL || | ||||
|             requests->numRequests < 0 || | ||||
|             requests->requestsAllocated < requests->numRequests) | ||||
|     { | ||||
|         return -1; | ||||
|     } | ||||
|     int conflicts = 0; | ||||
|     int i; | ||||
|     for (i = 0; i < requests->numRequests; i++) { | ||||
|         PermissionRequest *req; | ||||
|         unsigned int allowed; | ||||
|         int ret; | ||||
|  | ||||
|         req = &requests->requests[i]; | ||||
|         ret = getAllowedPermissions(req->path, req->recursive, &allowed); | ||||
|         if (ret < 0) { | ||||
|             return ret; | ||||
|         } | ||||
|         if ((req->requested & ~allowed) != 0) { | ||||
|             conflicts++; | ||||
|         } | ||||
|         if (updateAllowed) { | ||||
|             req->allowed = allowed; | ||||
|         } | ||||
|     } | ||||
|     return conflicts; | ||||
| } | ||||
|  | ||||
| int | ||||
| registerPermissionSet(int count, Permission *set) | ||||
| { | ||||
|     if (!gPermissionState.permissionStateInitialized) { | ||||
|         return -2; | ||||
|     } | ||||
|     if (count < 0 || (count > 0 && set == NULL)) { | ||||
|         return -1; | ||||
|     } | ||||
|     if (count == 0) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     if (gPermissionState.numPermissionEntries + count >= | ||||
|             gPermissionState.allocatedPermissionEntries) | ||||
|     { | ||||
|         Permission *newList; | ||||
|         int newSize; | ||||
|  | ||||
|         newSize = (gPermissionState.allocatedPermissionEntries + count) * 2; | ||||
|         if (newSize < 16) { | ||||
|             newSize = 16; | ||||
|         } | ||||
|         newList = (Permission *)realloc(gPermissionState.permissions, | ||||
|                 newSize * sizeof(Permission)); | ||||
|         if (newList == NULL) { | ||||
|             return -3; | ||||
|         } | ||||
|         gPermissionState.permissions = newList; | ||||
|         gPermissionState.allocatedPermissionEntries = newSize; | ||||
|     } | ||||
|  | ||||
|     Permission *p = &gPermissionState.permissions[ | ||||
|                         gPermissionState.numPermissionEntries]; | ||||
|     int i; | ||||
|     for (i = 0; i < count; i++) { | ||||
|         *p = set[i]; | ||||
|         //TODO: cache the strlen of the path | ||||
|         //TODO: normalize; strip off trailing / | ||||
|         p->path = strdup(p->path); | ||||
|         if (p->path == NULL) { | ||||
|             /* If we can't add all of the entries, we don't | ||||
|              * add any of them. | ||||
|              */ | ||||
|             Permission *pp = &gPermissionState.permissions[ | ||||
|                                 gPermissionState.numPermissionEntries]; | ||||
|             while (pp != p) { | ||||
|                 free((void *)pp->path); | ||||
|                 pp++; | ||||
|             } | ||||
|             return -4; | ||||
|         } | ||||
|         p++; | ||||
|     } | ||||
|     gPermissionState.numPermissionEntries += count; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										111
									
								
								amend/permissions.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								amend/permissions.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef AMEND_PERMISSIONS_H_ | ||||
| #define AMEND_PERMISSIONS_H_ | ||||
|  | ||||
| #include <stdbool.h> | ||||
|  | ||||
| #define PERM_NONE   (0) | ||||
| #define PERM_STAT   (1<<0) | ||||
| #define PERM_READ   (1<<1) | ||||
| #define PERM_WRITE  (1<<2)  // including create, delete, mkdir, rmdir | ||||
| #define PERM_CHMOD  (1<<3) | ||||
| #define PERM_CHOWN  (1<<4) | ||||
| #define PERM_CHGRP  (1<<5) | ||||
| #define PERM_SETUID (1<<6) | ||||
| #define PERM_SETGID (1<<7) | ||||
|  | ||||
| #define PERMSET_READ (PERM_STAT | PERM_READ) | ||||
| #define PERMSET_WRITE (PERMSET_READ | PERM_WRITE) | ||||
|  | ||||
| #define PERMSET_ALL \ | ||||
|     (PERM_STAT | PERM_READ | PERM_WRITE | PERM_CHMOD | \ | ||||
|     PERM_CHOWN | PERM_CHGRP | PERM_SETUID | PERM_SETGID) | ||||
|  | ||||
| typedef struct { | ||||
|     unsigned int requested; | ||||
|     unsigned int allowed; | ||||
|     const char *path; | ||||
|     bool recursive; | ||||
| } PermissionRequest; | ||||
|  | ||||
| typedef struct { | ||||
|     PermissionRequest *requests; | ||||
|     int numRequests; | ||||
|     int requestsAllocated; | ||||
| } PermissionRequestList; | ||||
|  | ||||
| /* Properly clear out a PermissionRequestList. | ||||
|  * | ||||
|  * @return 0 if list is non-NULL, negative otherwise. | ||||
|  */ | ||||
| int initPermissionRequestList(PermissionRequestList *list); | ||||
|  | ||||
| /* Add a permission request to the list, allocating more space | ||||
|  * if necessary. | ||||
|  * | ||||
|  * @return 0 on success or a negative value on failure. | ||||
|  */ | ||||
| int addPermissionRequestToList(PermissionRequestList *list, | ||||
|         const char *path, bool recursive, unsigned int permissions); | ||||
|  | ||||
| /* Free anything allocated by addPermissionRequestToList().  The caller | ||||
|  * is responsible for freeing the actual PermissionRequestList. | ||||
|  */ | ||||
| void freePermissionRequestListElements(PermissionRequestList *list); | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Global permission table | ||||
|  */ | ||||
|  | ||||
| typedef struct { | ||||
|     const char *path; | ||||
|     unsigned int allowed; | ||||
| } Permission; | ||||
|  | ||||
| int permissionInit(void); | ||||
| void permissionCleanup(void); | ||||
|  | ||||
| /* Returns the allowed permissions for the path in "outAllowed". | ||||
|  * Returns 0 if successful, negative if a parameter or global state | ||||
|  * is bad. | ||||
|  */ | ||||
| int getAllowedPermissions(const char *path, bool recursive, | ||||
|         unsigned int *outAllowed); | ||||
|  | ||||
| /* More-recently-registered permissions override older permissions. | ||||
|  */ | ||||
| int registerPermissionSet(int count, Permission *set); | ||||
|  | ||||
| /* Check to make sure that each request is allowed. | ||||
|  * | ||||
|  * @param requests The list of permission requests | ||||
|  * @param updateAllowed If true, update the "allowed" field in each | ||||
|  *                      element of the list | ||||
|  * @return the number of requests that were denied, or negative if | ||||
|  *         an error occurred. | ||||
|  */ | ||||
| int countPermissionConflicts(PermissionRequestList *requests, | ||||
|         bool updateAllowed); | ||||
|  | ||||
| /* Inspection/testing/debugging functions | ||||
|  */ | ||||
| int getPermissionCount(void); | ||||
| const Permission *getPermissionAt(int index); | ||||
|  | ||||
| #endif  // AMEND_PERMISSIONS_H_ | ||||
							
								
								
									
										394
									
								
								amend/register.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										394
									
								
								amend/register.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,394 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #undef NDEBUG | ||||
| #include <assert.h> | ||||
| #include "commands.h" | ||||
|  | ||||
| #include "register.h" | ||||
|  | ||||
| #define UNUSED(p)   ((void)(p)) | ||||
|  | ||||
| #define CHECK_BOOL() \ | ||||
|     do { \ | ||||
|         assert(argv == NULL); \ | ||||
|         if (argv != NULL) return -1; \ | ||||
|         assert(argc == true || argc == false); \ | ||||
|         if (argc != true && argc != false) return -1; \ | ||||
|     } while (false) | ||||
|  | ||||
| #define CHECK_WORDS() \ | ||||
|     do { \ | ||||
|         assert(argc >= 0); \ | ||||
|         if (argc < 0) return -1; \ | ||||
|         assert(argc == 0 || argv != NULL); \ | ||||
|         if (argc != 0 && argv == NULL) return -1; \ | ||||
|         if (permissions != NULL) { \ | ||||
|             int CW_I_; \ | ||||
|             for (CW_I_ = 0; CW_I_ < argc; CW_I_++) { \ | ||||
|                 assert(argv[CW_I_] != NULL); \ | ||||
|                 if (argv[CW_I_] == NULL) return -1; \ | ||||
|             } \ | ||||
|         } \ | ||||
|     } while (false) | ||||
|  | ||||
| #define CHECK_FN() \ | ||||
|     do { \ | ||||
|         CHECK_WORDS(); \ | ||||
|         if (permissions != NULL) { \ | ||||
|             assert(result == NULL); \ | ||||
|             if (result != NULL) return -1; \ | ||||
|         } else { \ | ||||
|             assert(result != NULL); \ | ||||
|             if (result == NULL) return -1; \ | ||||
|         } \ | ||||
|     } while (false) | ||||
|  | ||||
| #define NO_PERMS(perms) \ | ||||
|     do { \ | ||||
|         PermissionRequestList *NP_PRL_ = (perms); \ | ||||
|         if (NP_PRL_ != NULL) { \ | ||||
|             int NP_RET_ = addPermissionRequestToList(NP_PRL_, \ | ||||
|                     "", false, PERM_NONE); \ | ||||
|             if (NP_RET_ < 0) { \ | ||||
|                 /* Returns from the calling function. \ | ||||
|                  */ \ | ||||
|                 return NP_RET_; \ | ||||
|             } \ | ||||
|         } \ | ||||
|     } while (false) | ||||
|  | ||||
| /* | ||||
|  * Command definitions | ||||
|  */ | ||||
|  | ||||
| /* assert <boolexpr> | ||||
|  */ | ||||
| static int | ||||
| cmd_assert(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_BOOL(); | ||||
|     NO_PERMS(permissions); | ||||
|  | ||||
|     /* If our argument is false, return non-zero (failure) | ||||
|      * If our argument is true, return zero (success) | ||||
|      */ | ||||
|     if (argc) { | ||||
|         return 0; | ||||
|     } else { | ||||
|         return 1; | ||||
|     } | ||||
| } | ||||
|  | ||||
| /* format <root> | ||||
|  */ | ||||
| static int | ||||
| cmd_format(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_WORDS(); | ||||
| //xxx | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| /* copy_dir <srcdir> <dstdir> | ||||
|  */ | ||||
| static int | ||||
| cmd_copy_dir(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_WORDS(); | ||||
| //xxx | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| /* mark <resource> dirty|clean | ||||
|  */ | ||||
| static int | ||||
| cmd_mark(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_WORDS(); | ||||
| //xxx when marking, save the top-level hash at the mark point | ||||
| //    so we can retry on failure.  Otherwise the hashes won't match, | ||||
| //    or someone could intentionally dirty the FS to force a downgrade | ||||
| //xxx | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| /* done | ||||
|  */ | ||||
| static int | ||||
| cmd_done(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_WORDS(); | ||||
| //xxx | ||||
|     return -1; | ||||
| } | ||||
|  | ||||
| int | ||||
| registerUpdateCommands() | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     ret = registerCommand("assert", CMD_ARGS_BOOLEAN, cmd_assert, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
|     ret = registerCommand("copy_dir", CMD_ARGS_WORDS, cmd_copy_dir, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
|     ret = registerCommand("format", CMD_ARGS_WORDS, cmd_format, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
|     ret = registerCommand("mark", CMD_ARGS_WORDS, cmd_mark, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
|     ret = registerCommand("done", CMD_ARGS_WORDS, cmd_done, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
| //xxx some way to fix permissions | ||||
| //xxx could have "installperms" commands that build the fs_config list | ||||
| //xxx along with a "commitperms", and any copy_dir etc. needs to see | ||||
| //    a commitperms before it will work | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Function definitions | ||||
|  */ | ||||
|  | ||||
| /* update_forced() | ||||
|  * | ||||
|  * Returns "true" if some system setting has determined that | ||||
|  * the update should happen no matter what. | ||||
|  */ | ||||
| static int | ||||
| fn_update_forced(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         char **result, size_t *resultLen, | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_FN(); | ||||
|     NO_PERMS(permissions); | ||||
|  | ||||
|     if (argc != 0) { | ||||
|         fprintf(stderr, "%s: wrong number of arguments (%d)\n", | ||||
|                 name, argc); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     //xxx check some global or property | ||||
|     bool force = true; | ||||
|     if (force) { | ||||
|         *result = strdup("true"); | ||||
|     } else { | ||||
|         *result = strdup(""); | ||||
|     } | ||||
|     if (resultLen != NULL) { | ||||
|         *resultLen = strlen(*result); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /* get_mark(<resource>) | ||||
|  * | ||||
|  * Returns the current mark associated with the provided resource. | ||||
|  */ | ||||
| static int | ||||
| fn_get_mark(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         char **result, size_t *resultLen, | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_FN(); | ||||
|     NO_PERMS(permissions); | ||||
|  | ||||
|     if (argc != 1) { | ||||
|         fprintf(stderr, "%s: wrong number of arguments (%d)\n", | ||||
|                 name, argc); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     //xxx look up the value | ||||
|     *result = strdup(""); | ||||
|     if (resultLen != NULL) { | ||||
|         *resultLen = strlen(*result); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /* hash_dir(<path-to-directory>) | ||||
|  */ | ||||
| static int | ||||
| fn_hash_dir(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         char **result, size_t *resultLen, | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     int ret = -1; | ||||
|  | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_FN(); | ||||
|  | ||||
|     const char *dir; | ||||
|     if (argc != 1) { | ||||
|         fprintf(stderr, "%s: wrong number of arguments (%d)\n", | ||||
|                 name, argc); | ||||
|         return 1; | ||||
|     } else { | ||||
|         dir = argv[0]; | ||||
|     } | ||||
|  | ||||
|     if (permissions != NULL) { | ||||
|         if (dir == NULL) { | ||||
|             /* The argument is the result of another function. | ||||
|              * Assume the worst case, where the function returns | ||||
|              * the root. | ||||
|              */ | ||||
|             dir = "/"; | ||||
|         } | ||||
|         ret = addPermissionRequestToList(permissions, dir, true, PERM_READ); | ||||
|     } else { | ||||
| //xxx build and return the string | ||||
|         *result = strdup("hashvalue"); | ||||
|         if (resultLen != NULL) { | ||||
|             *resultLen = strlen(*result); | ||||
|         } | ||||
|         ret = 0; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| /* matches(<str>, <str1> [, <strN>...]) | ||||
|  * If <str> matches (strcmp) any of <str1>...<strN>, returns <str>, | ||||
|  * otherwise returns "". | ||||
|  * | ||||
|  * E.g., assert matches(hash_dir("/path"), "hash1", "hash2") | ||||
|  */ | ||||
| static int | ||||
| fn_matches(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         char **result, size_t *resultLen, | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_FN(); | ||||
|     NO_PERMS(permissions); | ||||
|  | ||||
|     if (argc < 2) { | ||||
|         fprintf(stderr, "%s: not enough arguments (%d < 2)\n", | ||||
|                 name, argc); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     int i; | ||||
|     for (i = 1; i < argc; i++) { | ||||
|         if (strcmp(argv[0], argv[i]) == 0) { | ||||
|             *result = strdup(argv[0]); | ||||
|             if (resultLen != NULL) { | ||||
|                 *resultLen = strlen(*result); | ||||
|             } | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     *result = strdup(""); | ||||
|     if (resultLen != NULL) { | ||||
|         *resultLen = 1; | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| /* concat(<str>, <str1> [, <strN>...]) | ||||
|  * Returns the concatenation of all strings. | ||||
|  */ | ||||
| static int | ||||
| fn_concat(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         char **result, size_t *resultLen, | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     UNUSED(name); | ||||
|     UNUSED(cookie); | ||||
|     CHECK_FN(); | ||||
|     NO_PERMS(permissions); | ||||
|  | ||||
|     size_t totalLen = 0; | ||||
|     int i; | ||||
|     for (i = 0; i < argc; i++) { | ||||
|         totalLen += strlen(argv[i]); | ||||
|     } | ||||
|  | ||||
|     char *s = (char *)malloc(totalLen + 1); | ||||
|     if (s == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     s[totalLen] = '\0'; | ||||
|     for (i = 0; i < argc; i++) { | ||||
|         //TODO: keep track of the end to avoid walking the string each time | ||||
|         strcat(s, argv[i]); | ||||
|     } | ||||
|     *result = s; | ||||
|     if (resultLen != NULL) { | ||||
|         *resultLen = strlen(s); | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| registerUpdateFunctions() | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     ret = registerFunction("update_forced", fn_update_forced, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
|     ret = registerFunction("get_mark", fn_get_mark, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
|     ret = registerFunction("hash_dir", fn_hash_dir, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
|     ret = registerFunction("matches", fn_matches, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
|     ret = registerFunction("concat", fn_concat, NULL); | ||||
|     if (ret < 0) return ret; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										23
									
								
								amend/register.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								amend/register.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef AMEND_REGISTER_H_ | ||||
| #define AMEND_REGISTER_H_ | ||||
|  | ||||
| int registerUpdateCommands(void); | ||||
| int registerUpdateFunctions(void); | ||||
|  | ||||
| #endif  // AMEND_REGISTER_H_ | ||||
							
								
								
									
										132
									
								
								amend/symtab.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								amend/symtab.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,132 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include "symtab.h" | ||||
|  | ||||
| #define DEFAULT_TABLE_SIZE 16 | ||||
|  | ||||
| typedef struct { | ||||
|     char *symbol; | ||||
|     const void *cookie; | ||||
|     unsigned int flags; | ||||
| } SymbolTableEntry; | ||||
|  | ||||
| struct SymbolTable { | ||||
|     SymbolTableEntry *table; | ||||
|     int numEntries; | ||||
|     int maxSize; | ||||
| }; | ||||
|  | ||||
| SymbolTable * | ||||
| createSymbolTable() | ||||
| { | ||||
|     SymbolTable *tab; | ||||
|  | ||||
|     tab = (SymbolTable *)malloc(sizeof(SymbolTable)); | ||||
|     if (tab != NULL) { | ||||
|         tab->numEntries = 0; | ||||
|         tab->maxSize = DEFAULT_TABLE_SIZE; | ||||
|         tab->table = (SymbolTableEntry *)malloc( | ||||
|                             tab->maxSize * sizeof(SymbolTableEntry)); | ||||
|         if (tab->table == NULL) { | ||||
|             free(tab); | ||||
|             tab = NULL; | ||||
|         } | ||||
|     } | ||||
|     return tab; | ||||
| } | ||||
|  | ||||
| void | ||||
| deleteSymbolTable(SymbolTable *tab) | ||||
| { | ||||
|     if (tab != NULL) { | ||||
|         while (tab->numEntries > 0) { | ||||
|             free(tab->table[--tab->numEntries].symbol); | ||||
|         } | ||||
|         free(tab->table); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void * | ||||
| findInSymbolTable(SymbolTable *tab, const char *symbol, unsigned int flags) | ||||
| { | ||||
|     int i; | ||||
|  | ||||
|     if (tab == NULL || symbol == NULL) { | ||||
|         return NULL; | ||||
|     } | ||||
|  | ||||
|     // TODO: Sort the table and binary search | ||||
|     for (i = 0; i < tab->numEntries; i++) { | ||||
|         if (strcmp(tab->table[i].symbol, symbol) == 0 && | ||||
|                 tab->table[i].flags == flags) | ||||
|         { | ||||
|             return (void *)tab->table[i].cookie; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return NULL; | ||||
| } | ||||
|  | ||||
| int | ||||
| addToSymbolTable(SymbolTable *tab, const char *symbol, unsigned int flags, | ||||
|         const void *cookie) | ||||
| { | ||||
|     if (tab == NULL || symbol == NULL || cookie == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     /* Make sure that this symbol isn't already in the table. | ||||
|      */ | ||||
|     if (findInSymbolTable(tab, symbol, flags) != NULL) { | ||||
|         return -2; | ||||
|     } | ||||
|  | ||||
|     /* Make sure there's enough space for the new entry. | ||||
|      */ | ||||
|     if (tab->numEntries == tab->maxSize) { | ||||
|         SymbolTableEntry *newTable; | ||||
|         int newSize; | ||||
|  | ||||
|         newSize = tab->numEntries * 2; | ||||
|         if (newSize < DEFAULT_TABLE_SIZE) { | ||||
|             newSize = DEFAULT_TABLE_SIZE; | ||||
|         } | ||||
|         newTable = (SymbolTableEntry *)realloc(tab->table, | ||||
|                             newSize * sizeof(SymbolTableEntry)); | ||||
|         if (newTable == NULL) { | ||||
|             return -1; | ||||
|         } | ||||
|         tab->maxSize = newSize; | ||||
|         tab->table = newTable; | ||||
|     } | ||||
|  | ||||
|     /* Insert the new entry. | ||||
|      */ | ||||
|     symbol = strdup(symbol); | ||||
|     if (symbol == NULL) { | ||||
|         return -1; | ||||
|     } | ||||
|     // TODO: Sort the table | ||||
|     tab->table[tab->numEntries].symbol = (char *)symbol; | ||||
|     tab->table[tab->numEntries].cookie = cookie; | ||||
|     tab->table[tab->numEntries].flags = flags; | ||||
|     tab->numEntries++; | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										34
									
								
								amend/symtab.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								amend/symtab.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #ifndef AMEND_SYMTAB_H_ | ||||
| #define AMEND_SYMTAB_H_ | ||||
|  | ||||
| typedef struct SymbolTable SymbolTable; | ||||
|  | ||||
| SymbolTable *createSymbolTable(void); | ||||
|  | ||||
| void deleteSymbolTable(SymbolTable *tab); | ||||
|  | ||||
| /* symbol and cookie must be non-NULL. | ||||
|  */ | ||||
| int addToSymbolTable(SymbolTable *tab, const char *symbol, unsigned int flags, | ||||
|         const void *cookie); | ||||
|  | ||||
| void *findInSymbolTable(SymbolTable *tab, const char *symbol, | ||||
|         unsigned int flags); | ||||
|  | ||||
| #endif  // AMEND_SYMTAB_H_ | ||||
							
								
								
									
										538
									
								
								amend/test_commands.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										538
									
								
								amend/test_commands.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,538 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <stdio.h> | ||||
| #undef NDEBUG | ||||
| #include <assert.h> | ||||
| #include "commands.h" | ||||
|  | ||||
| static struct { | ||||
|     bool called; | ||||
|     const char *name; | ||||
|     void *cookie; | ||||
|     int argc; | ||||
|     const char **argv; | ||||
|     PermissionRequestList *permissions; | ||||
|     int returnValue; | ||||
|     char *functionResult; | ||||
| } gTestCommandState; | ||||
|  | ||||
| static int | ||||
| testCommand(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         PermissionRequestList *permissions) | ||||
| { | ||||
|     gTestCommandState.called = true; | ||||
|     gTestCommandState.name = name; | ||||
|     gTestCommandState.cookie = cookie; | ||||
|     gTestCommandState.argc = argc; | ||||
|     gTestCommandState.argv = argv; | ||||
|     gTestCommandState.permissions = permissions; | ||||
|     return gTestCommandState.returnValue; | ||||
| } | ||||
|  | ||||
| static int | ||||
| testFunction(const char *name, void *cookie, int argc, const char *argv[], | ||||
|         char **result, size_t *resultLen, PermissionRequestList *permissions) | ||||
| { | ||||
|     gTestCommandState.called = true; | ||||
|     gTestCommandState.name = name; | ||||
|     gTestCommandState.cookie = cookie; | ||||
|     gTestCommandState.argc = argc; | ||||
|     gTestCommandState.argv = argv; | ||||
|     gTestCommandState.permissions = permissions; | ||||
|     if (result != NULL) { | ||||
|         *result = gTestCommandState.functionResult; | ||||
|         if (resultLen != NULL) { | ||||
|             *resultLen = strlen(*result); | ||||
|         } | ||||
|     } | ||||
|     return gTestCommandState.returnValue; | ||||
| } | ||||
|  | ||||
| static int | ||||
| test_commands() | ||||
| { | ||||
|     Command *cmd; | ||||
|     int ret; | ||||
|     CommandArgumentType argType; | ||||
|  | ||||
|     ret = commandInit(); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Make sure we can't initialize twice. | ||||
|      */ | ||||
|     ret = commandInit(); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Try calling with some bad values. | ||||
|      */ | ||||
|     ret = registerCommand(NULL, CMD_ARGS_UNKNOWN, NULL, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = registerCommand("hello", CMD_ARGS_UNKNOWN, NULL, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = registerCommand("hello", CMD_ARGS_WORDS, NULL, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     cmd = findCommand(NULL); | ||||
|     assert(cmd == NULL); | ||||
|  | ||||
|     argType = getCommandArgumentType(NULL); | ||||
|     assert((int)argType < 0); | ||||
|  | ||||
|     ret = callCommand(NULL, -1, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = callBooleanCommand(NULL, false); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Register some commands. | ||||
|      */ | ||||
|     ret = registerCommand("one", CMD_ARGS_WORDS, testCommand, | ||||
|             &gTestCommandState); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = registerCommand("two", CMD_ARGS_WORDS, testCommand, | ||||
|             &gTestCommandState); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = registerCommand("bool", CMD_ARGS_BOOLEAN, testCommand, | ||||
|             &gTestCommandState); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Make sure that all of those commands exist and that their | ||||
|      * argument types are correct. | ||||
|      */ | ||||
|     cmd = findCommand("one"); | ||||
|     assert(cmd != NULL); | ||||
|     argType = getCommandArgumentType(cmd); | ||||
|     assert(argType == CMD_ARGS_WORDS); | ||||
|  | ||||
|     cmd = findCommand("two"); | ||||
|     assert(cmd != NULL); | ||||
|     argType = getCommandArgumentType(cmd); | ||||
|     assert(argType == CMD_ARGS_WORDS); | ||||
|  | ||||
|     cmd = findCommand("bool"); | ||||
|     assert(cmd != NULL); | ||||
|     argType = getCommandArgumentType(cmd); | ||||
|     assert(argType == CMD_ARGS_BOOLEAN); | ||||
|  | ||||
|     /* Make sure that no similar commands exist. | ||||
|      */ | ||||
|     cmd = findCommand("on"); | ||||
|     assert(cmd == NULL); | ||||
|  | ||||
|     cmd = findCommand("onee"); | ||||
|     assert(cmd == NULL); | ||||
|  | ||||
|     /* Make sure that a double insertion fails. | ||||
|      */ | ||||
|     ret = registerCommand("one", CMD_ARGS_WORDS, testCommand, | ||||
|             &gTestCommandState); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Make sure that bad args fail. | ||||
|      */ | ||||
|     cmd = findCommand("one"); | ||||
|     assert(cmd != NULL); | ||||
|  | ||||
|     ret = callCommand(cmd, -1, NULL);   // argc must be non-negative | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = callCommand(cmd, 1, NULL);    // argv can't be NULL if argc > 0 | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Make sure that you can't make a boolean call on a regular command. | ||||
|      */ | ||||
|     cmd = findCommand("one"); | ||||
|     assert(cmd != NULL); | ||||
|  | ||||
|     ret = callBooleanCommand(cmd, false); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Make sure that you can't make a regular call on a boolean command. | ||||
|      */ | ||||
|     cmd = findCommand("bool"); | ||||
|     assert(cmd != NULL); | ||||
|  | ||||
|     ret = callCommand(cmd, 0, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Set up some arguments. | ||||
|      */ | ||||
|     int argc = 4; | ||||
|     const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" }; | ||||
|  | ||||
|     /* Make a call and make sure that it occurred. | ||||
|      */ | ||||
|     cmd = findCommand("one"); | ||||
|     assert(cmd != NULL); | ||||
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState)); | ||||
|     gTestCommandState.called = false; | ||||
|     gTestCommandState.returnValue = 25; | ||||
|     gTestCommandState.permissions = (PermissionRequestList *)1; | ||||
|     ret = callCommand(cmd, argc, argv); | ||||
| //xxx also try calling with a null argv element (should fail) | ||||
|     assert(ret == 25); | ||||
|     assert(gTestCommandState.called); | ||||
|     assert(strcmp(gTestCommandState.name, "one") == 0); | ||||
|     assert(gTestCommandState.cookie == &gTestCommandState); | ||||
|     assert(gTestCommandState.argc == argc); | ||||
|     assert(gTestCommandState.argv == argv); | ||||
|     assert(gTestCommandState.permissions == NULL); | ||||
|  | ||||
|     /* Make a boolean call and make sure that it occurred. | ||||
|      */ | ||||
|     cmd = findCommand("bool"); | ||||
|     assert(cmd != NULL); | ||||
|  | ||||
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState)); | ||||
|     gTestCommandState.called = false; | ||||
|     gTestCommandState.returnValue = 12; | ||||
|     gTestCommandState.permissions = (PermissionRequestList *)1; | ||||
|     ret = callBooleanCommand(cmd, false); | ||||
|     assert(ret == 12); | ||||
|     assert(gTestCommandState.called); | ||||
|     assert(strcmp(gTestCommandState.name, "bool") == 0); | ||||
|     assert(gTestCommandState.cookie == &gTestCommandState); | ||||
|     assert(gTestCommandState.argc == 0); | ||||
|     assert(gTestCommandState.argv == NULL); | ||||
|     assert(gTestCommandState.permissions == NULL); | ||||
|  | ||||
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState)); | ||||
|     gTestCommandState.called = false; | ||||
|     gTestCommandState.returnValue = 13; | ||||
|     gTestCommandState.permissions = (PermissionRequestList *)1; | ||||
|     ret = callBooleanCommand(cmd, true); | ||||
|     assert(ret == 13); | ||||
|     assert(gTestCommandState.called); | ||||
|     assert(strcmp(gTestCommandState.name, "bool") == 0); | ||||
|     assert(gTestCommandState.cookie == &gTestCommandState); | ||||
|     assert(gTestCommandState.argc == 1); | ||||
|     assert(gTestCommandState.argv == NULL); | ||||
|     assert(gTestCommandState.permissions == NULL); | ||||
|  | ||||
|     /* Try looking up permissions. | ||||
|      */ | ||||
|     PermissionRequestList permissions; | ||||
|     cmd = findCommand("one"); | ||||
|     assert(cmd != NULL); | ||||
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState)); | ||||
|     gTestCommandState.called = false; | ||||
|     gTestCommandState.returnValue = 27; | ||||
|     gTestCommandState.permissions = (PermissionRequestList *)1; | ||||
|     argv[1] = NULL; // null out an arg, which should be ok | ||||
|     ret = getCommandPermissions(cmd, argc, argv, &permissions); | ||||
|     assert(ret == 27); | ||||
|     assert(gTestCommandState.called); | ||||
|     assert(strcmp(gTestCommandState.name, "one") == 0); | ||||
|     assert(gTestCommandState.cookie == &gTestCommandState); | ||||
|     assert(gTestCommandState.argc == argc); | ||||
|     assert(gTestCommandState.argv == argv); | ||||
|     assert(gTestCommandState.permissions == &permissions); | ||||
|  | ||||
|     /* Boolean command permissions | ||||
|      */ | ||||
|     cmd = findCommand("bool"); | ||||
|     assert(cmd != NULL); | ||||
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState)); | ||||
|     gTestCommandState.called = false; | ||||
|     gTestCommandState.returnValue = 55; | ||||
|     gTestCommandState.permissions = (PermissionRequestList *)1; | ||||
|     // argv[1] is still NULL | ||||
|     ret = getBooleanCommandPermissions(cmd, true, &permissions); | ||||
|     assert(ret == 55); | ||||
|     assert(gTestCommandState.called); | ||||
|     assert(strcmp(gTestCommandState.name, "bool") == 0); | ||||
|     assert(gTestCommandState.cookie == &gTestCommandState); | ||||
|     assert(gTestCommandState.argc == 1); | ||||
|     assert(gTestCommandState.argv == NULL); | ||||
|     assert(gTestCommandState.permissions == &permissions); | ||||
|  | ||||
|  | ||||
|     /* Smoke test commandCleanup(). | ||||
|      */ | ||||
|     commandCleanup(); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| test_functions() | ||||
| { | ||||
|     Function *fn; | ||||
|     int ret; | ||||
|  | ||||
|     ret = commandInit(); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Try calling with some bad values. | ||||
|      */ | ||||
|     ret = registerFunction(NULL, NULL, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = registerFunction("hello", NULL, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     fn = findFunction(NULL); | ||||
|     assert(fn == NULL); | ||||
|  | ||||
|     ret = callFunction(NULL, -1, NULL, NULL, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Register some functions. | ||||
|      */ | ||||
|     ret = registerFunction("one", testFunction, &gTestCommandState); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = registerFunction("two", testFunction, &gTestCommandState); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = registerFunction("three", testFunction, &gTestCommandState); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Make sure that all of those functions exist. | ||||
|      * argument types are correct. | ||||
|      */ | ||||
|     fn = findFunction("one"); | ||||
|     assert(fn != NULL); | ||||
|  | ||||
|     fn = findFunction("two"); | ||||
|     assert(fn != NULL); | ||||
|  | ||||
|     fn = findFunction("three"); | ||||
|     assert(fn != NULL); | ||||
|  | ||||
|     /* Make sure that no similar functions exist. | ||||
|      */ | ||||
|     fn = findFunction("on"); | ||||
|     assert(fn == NULL); | ||||
|  | ||||
|     fn = findFunction("onee"); | ||||
|     assert(fn == NULL); | ||||
|  | ||||
|     /* Make sure that a double insertion fails. | ||||
|      */ | ||||
|     ret = registerFunction("one", testFunction, &gTestCommandState); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Make sure that bad args fail. | ||||
|      */ | ||||
|     fn = findFunction("one"); | ||||
|     assert(fn != NULL); | ||||
|  | ||||
|     // argc must be non-negative | ||||
|     ret = callFunction(fn, -1, NULL, (char **)1, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     // argv can't be NULL if argc > 0 | ||||
|     ret = callFunction(fn, 1, NULL, (char **)1, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     // result can't be NULL | ||||
|     ret = callFunction(fn, 0, NULL, NULL, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Set up some arguments. | ||||
|      */ | ||||
|     int argc = 4; | ||||
|     const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" }; | ||||
|  | ||||
|     /* Make a call and make sure that it occurred. | ||||
|      */ | ||||
|     char *functionResult; | ||||
|     size_t functionResultLen; | ||||
|     fn = findFunction("one"); | ||||
|     assert(fn != NULL); | ||||
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState)); | ||||
|     gTestCommandState.called = false; | ||||
|     gTestCommandState.returnValue = 25; | ||||
|     gTestCommandState.functionResult = "1234"; | ||||
|     gTestCommandState.permissions = (PermissionRequestList *)1; | ||||
|     functionResult = NULL; | ||||
|     functionResultLen = 55; | ||||
|     ret = callFunction(fn, argc, argv, | ||||
|             &functionResult, &functionResultLen); | ||||
| //xxx also try calling with a null resultLen arg (should succeed) | ||||
| //xxx also try calling with a null argv element (should fail) | ||||
|     assert(ret == 25); | ||||
|     assert(gTestCommandState.called); | ||||
|     assert(strcmp(gTestCommandState.name, "one") == 0); | ||||
|     assert(gTestCommandState.cookie == &gTestCommandState); | ||||
|     assert(gTestCommandState.argc == argc); | ||||
|     assert(gTestCommandState.argv == argv); | ||||
|     assert(gTestCommandState.permissions == NULL); | ||||
|     assert(strcmp(functionResult, "1234") == 0); | ||||
|     assert(functionResultLen == strlen(functionResult)); | ||||
|  | ||||
|     /* Try looking up permissions. | ||||
|      */ | ||||
|     PermissionRequestList permissions; | ||||
|     fn = findFunction("one"); | ||||
|     assert(fn != NULL); | ||||
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState)); | ||||
|     gTestCommandState.called = false; | ||||
|     gTestCommandState.returnValue = 27; | ||||
|     gTestCommandState.permissions = (PermissionRequestList *)1; | ||||
|     argv[1] = NULL; // null out an arg, which should be ok | ||||
|     ret = getFunctionPermissions(fn, argc, argv, &permissions); | ||||
|     assert(ret == 27); | ||||
|     assert(gTestCommandState.called); | ||||
|     assert(strcmp(gTestCommandState.name, "one") == 0); | ||||
|     assert(gTestCommandState.cookie == &gTestCommandState); | ||||
|     assert(gTestCommandState.argc == argc); | ||||
|     assert(gTestCommandState.argv == argv); | ||||
|     assert(gTestCommandState.permissions == &permissions); | ||||
|  | ||||
|     /* Smoke test commandCleanup(). | ||||
|      */ | ||||
|     commandCleanup(); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| test_interaction() | ||||
| { | ||||
|     Command *cmd; | ||||
|     Function *fn; | ||||
|     int ret; | ||||
|  | ||||
|     ret = commandInit(); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Register some commands. | ||||
|      */ | ||||
|     ret = registerCommand("one", CMD_ARGS_WORDS, testCommand, (void *)0xc1); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = registerCommand("two", CMD_ARGS_WORDS, testCommand, (void *)0xc2); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Register some functions, one of which shares a name with a command. | ||||
|      */ | ||||
|     ret = registerFunction("one", testFunction, (void *)0xf1); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = registerFunction("three", testFunction, (void *)0xf3); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Look up each of the commands, and make sure no command exists | ||||
|      * with the name used only by our function. | ||||
|      */ | ||||
|     cmd = findCommand("one"); | ||||
|     assert(cmd != NULL); | ||||
|  | ||||
|     cmd = findCommand("two"); | ||||
|     assert(cmd != NULL); | ||||
|  | ||||
|     cmd = findCommand("three"); | ||||
|     assert(cmd == NULL); | ||||
|  | ||||
|     /* Look up each of the functions, and make sure no function exists | ||||
|      * with the name used only by our command. | ||||
|      */ | ||||
|     fn = findFunction("one"); | ||||
|     assert(fn != NULL); | ||||
|  | ||||
|     fn = findFunction("two"); | ||||
|     assert(fn == NULL); | ||||
|  | ||||
|     fn = findFunction("three"); | ||||
|     assert(fn != NULL); | ||||
|  | ||||
|     /* Set up some arguments. | ||||
|      */ | ||||
|     int argc = 4; | ||||
|     const char *argv[4] = { "ONE", "TWO", "THREE", "FOUR" }; | ||||
|  | ||||
|     /* Call the overlapping command and make sure that the cookie is correct. | ||||
|      */ | ||||
|     cmd = findCommand("one"); | ||||
|     assert(cmd != NULL); | ||||
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState)); | ||||
|     gTestCommandState.called = false; | ||||
|     gTestCommandState.returnValue = 123; | ||||
|     gTestCommandState.permissions = (PermissionRequestList *)1; | ||||
|     ret = callCommand(cmd, argc, argv); | ||||
|     assert(ret == 123); | ||||
|     assert(gTestCommandState.called); | ||||
|     assert(strcmp(gTestCommandState.name, "one") == 0); | ||||
|     assert((int)gTestCommandState.cookie == 0xc1); | ||||
|     assert(gTestCommandState.argc == argc); | ||||
|     assert(gTestCommandState.argv == argv); | ||||
|     assert(gTestCommandState.permissions == NULL); | ||||
|  | ||||
|     /* Call the overlapping function and make sure that the cookie is correct. | ||||
|      */ | ||||
|     char *functionResult; | ||||
|     size_t functionResultLen; | ||||
|     fn = findFunction("one"); | ||||
|     assert(fn != NULL); | ||||
|     memset(&gTestCommandState, 0, sizeof(gTestCommandState)); | ||||
|     gTestCommandState.called = false; | ||||
|     gTestCommandState.returnValue = 125; | ||||
|     gTestCommandState.functionResult = "5678"; | ||||
|     gTestCommandState.permissions = (PermissionRequestList *)2; | ||||
|     functionResult = NULL; | ||||
|     functionResultLen = 66; | ||||
|     ret = callFunction(fn, argc, argv, &functionResult, &functionResultLen); | ||||
|     assert(ret == 125); | ||||
|     assert(gTestCommandState.called); | ||||
|     assert(strcmp(gTestCommandState.name, "one") == 0); | ||||
|     assert((int)gTestCommandState.cookie == 0xf1); | ||||
|     assert(gTestCommandState.argc == argc); | ||||
|     assert(gTestCommandState.argv == argv); | ||||
|     assert(gTestCommandState.permissions == NULL); | ||||
|     assert(strcmp(functionResult, "5678") == 0); | ||||
|     assert(functionResultLen == strlen(functionResult)); | ||||
|  | ||||
|     /* Clean up. | ||||
|      */ | ||||
|     commandCleanup(); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| test_cmd_fn() | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     ret = test_commands(); | ||||
|     if (ret != 0) { | ||||
|         fprintf(stderr, "test_commands() failed: %d\n", ret); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     ret = test_functions(); | ||||
|     if (ret != 0) { | ||||
|         fprintf(stderr, "test_functions() failed: %d\n", ret); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     ret = test_interaction(); | ||||
|     if (ret != 0) { | ||||
|         fprintf(stderr, "test_interaction() failed: %d\n", ret); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										347
									
								
								amend/test_permissions.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										347
									
								
								amend/test_permissions.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,347 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #undef NDEBUG | ||||
| #include <assert.h> | ||||
| #include "permissions.h" | ||||
|  | ||||
| static int | ||||
| test_permission_list() | ||||
| { | ||||
|     PermissionRequestList list; | ||||
|     int ret; | ||||
|     int numRequests; | ||||
|  | ||||
|     /* Bad parameter | ||||
|      */ | ||||
|     ret = initPermissionRequestList(NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Good parameter | ||||
|      */ | ||||
|     ret = initPermissionRequestList(&list); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Bad parameters | ||||
|      */ | ||||
|     ret = addPermissionRequestToList(NULL, NULL, false, 0); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = addPermissionRequestToList(&list, NULL, false, 0); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Good parameters | ||||
|      */ | ||||
|     numRequests = 0; | ||||
|  | ||||
|     ret = addPermissionRequestToList(&list, "one", false, 1); | ||||
|     assert(ret == 0); | ||||
|     numRequests++; | ||||
|  | ||||
|     ret = addPermissionRequestToList(&list, "two", false, 2); | ||||
|     assert(ret == 0); | ||||
|     numRequests++; | ||||
|  | ||||
|     ret = addPermissionRequestToList(&list, "three", false, 3); | ||||
|     assert(ret == 0); | ||||
|     numRequests++; | ||||
|  | ||||
|     ret = addPermissionRequestToList(&list, "recursive", true, 55); | ||||
|     assert(ret == 0); | ||||
|     numRequests++; | ||||
|  | ||||
|     /* Validate the list | ||||
|      */ | ||||
|     assert(list.requests != NULL); | ||||
|     assert(list.numRequests == numRequests); | ||||
|     assert(list.numRequests <= list.requestsAllocated); | ||||
|     bool sawOne = false; | ||||
|     bool sawTwo = false; | ||||
|     bool sawThree = false; | ||||
|     bool sawRecursive = false; | ||||
|     int i; | ||||
|     for (i = 0; i < list.numRequests; i++) { | ||||
|         PermissionRequest *req = &list.requests[i]; | ||||
|         assert(req->allowed == 0); | ||||
|  | ||||
|         /* Order isn't guaranteed, so we have to switch every time. | ||||
|          */ | ||||
|         if (strcmp(req->path, "one") == 0) { | ||||
|             assert(!sawOne); | ||||
|             assert(req->requested == 1); | ||||
|             assert(!req->recursive); | ||||
|             sawOne = true; | ||||
|         } else if (strcmp(req->path, "two") == 0) { | ||||
|             assert(!sawTwo); | ||||
|             assert(req->requested == 2); | ||||
|             assert(!req->recursive); | ||||
|             sawTwo = true; | ||||
|         } else if (strcmp(req->path, "three") == 0) { | ||||
|             assert(!sawThree); | ||||
|             assert(req->requested == 3); | ||||
|             assert(!req->recursive); | ||||
|             sawThree = true; | ||||
|         } else if (strcmp(req->path, "recursive") == 0) { | ||||
|             assert(!sawRecursive); | ||||
|             assert(req->requested == 55); | ||||
|             assert(req->recursive); | ||||
|             sawRecursive = true; | ||||
|         } else { | ||||
|             assert(false); | ||||
|         } | ||||
|     } | ||||
|     assert(sawOne); | ||||
|     assert(sawTwo); | ||||
|     assert(sawThree); | ||||
|     assert(sawRecursive); | ||||
|  | ||||
|     /* Smoke test the teardown | ||||
|      */ | ||||
|     freePermissionRequestListElements(&list); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| test_permission_table() | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     /* Test the global permissions table. | ||||
|      * Try calling functions without initializing first. | ||||
|      */ | ||||
|     ret = registerPermissionSet(0, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = countPermissionConflicts((PermissionRequestList *)16, false); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = getPermissionCount(); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     const Permission *p; | ||||
|     p = getPermissionAt(0); | ||||
|     assert(p == NULL); | ||||
|  | ||||
|     /* Initialize. | ||||
|      */ | ||||
|     ret = permissionInit(); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Make sure we can't initialize twice. | ||||
|      */ | ||||
|     ret = permissionInit(); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Test the inspection functions. | ||||
|      */ | ||||
|     ret = getPermissionCount(); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     p = getPermissionAt(-1); | ||||
|     assert(p == NULL); | ||||
|  | ||||
|     p = getPermissionAt(0); | ||||
|     assert(p == NULL); | ||||
|  | ||||
|     p = getPermissionAt(1); | ||||
|     assert(p == NULL); | ||||
|  | ||||
|     /* Test registerPermissionSet(). | ||||
|      * Try some bad parameter values. | ||||
|      */ | ||||
|     ret = registerPermissionSet(-1, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = registerPermissionSet(1, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Register some permissions. | ||||
|      */ | ||||
|     Permission p1; | ||||
|     p1.path = "one"; | ||||
|     p1.allowed = 1; | ||||
|     ret = registerPermissionSet(1, &p1); | ||||
|     assert(ret == 0); | ||||
|     ret = getPermissionCount(); | ||||
|     assert(ret == 1); | ||||
|  | ||||
|     Permission p2[2]; | ||||
|     p2[0].path = "two"; | ||||
|     p2[0].allowed = 2; | ||||
|     p2[1].path = "three"; | ||||
|     p2[1].allowed = 3; | ||||
|     ret = registerPermissionSet(2, p2); | ||||
|     assert(ret == 0); | ||||
|     ret = getPermissionCount(); | ||||
|     assert(ret == 3); | ||||
|  | ||||
|     ret = registerPermissionSet(0, NULL); | ||||
|     assert(ret == 0); | ||||
|     ret = getPermissionCount(); | ||||
|     assert(ret == 3); | ||||
|  | ||||
|     p1.path = "four"; | ||||
|     p1.allowed = 4; | ||||
|     ret = registerPermissionSet(1, &p1); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Make sure the table looks correct. | ||||
|      * Order is important;  more-recent additions | ||||
|      * should appear at higher indices. | ||||
|      */ | ||||
|     ret = getPermissionCount(); | ||||
|     assert(ret == 4); | ||||
|  | ||||
|     int i; | ||||
|     for (i = 0; i < ret; i++) { | ||||
|         const Permission *p; | ||||
|         p = getPermissionAt(i); | ||||
|         assert(p != NULL); | ||||
|         assert(p->allowed == (unsigned int)(i + 1)); | ||||
|         switch (i) { | ||||
|         case 0: | ||||
|             assert(strcmp(p->path, "one") == 0); | ||||
|             break; | ||||
|         case 1: | ||||
|             assert(strcmp(p->path, "two") == 0); | ||||
|             break; | ||||
|         case 2: | ||||
|             assert(strcmp(p->path, "three") == 0); | ||||
|             break; | ||||
|         case 3: | ||||
|             assert(strcmp(p->path, "four") == 0); | ||||
|             break; | ||||
|         default: | ||||
|             assert(!"internal error"); | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|     p = getPermissionAt(ret); | ||||
|     assert(p == NULL); | ||||
|  | ||||
|     /* Smoke test the teardown | ||||
|      */ | ||||
|     permissionCleanup(); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| test_allowed_permissions() | ||||
| { | ||||
|     int ret; | ||||
|     int numPerms; | ||||
|  | ||||
|     /* Make sure these fail before initialization. | ||||
|      */ | ||||
|     ret = countPermissionConflicts((PermissionRequestList *)1, false); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     ret = getAllowedPermissions((const char *)1, false, (unsigned int *)1); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Initialize. | ||||
|      */ | ||||
|     ret = permissionInit(); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Make sure countPermissionConflicts() fails with bad parameters. | ||||
|      */ | ||||
|     ret = countPermissionConflicts(NULL, false); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Register a set of permissions. | ||||
|      */ | ||||
|     Permission perms[] = { | ||||
|         { "/", PERM_NONE }, | ||||
|         { "/stat", PERM_STAT }, | ||||
|         { "/read", PERMSET_READ }, | ||||
|         { "/write", PERMSET_WRITE }, | ||||
|         { "/.stat", PERM_STAT }, | ||||
|         { "/.stat/.read", PERMSET_READ }, | ||||
|         { "/.stat/.read/.write", PERMSET_WRITE }, | ||||
|         { "/.stat/.write", PERMSET_WRITE }, | ||||
|     }; | ||||
|     numPerms = sizeof(perms) / sizeof(perms[0]); | ||||
|     ret = registerPermissionSet(numPerms, perms); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Build a permission request list. | ||||
|      */ | ||||
|     PermissionRequestList list; | ||||
|     ret = initPermissionRequestList(&list); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = addPermissionRequestToList(&list, "/stat", false, PERM_STAT); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = addPermissionRequestToList(&list, "/read", false, PERM_READ); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = addPermissionRequestToList(&list, "/write", false, PERM_WRITE); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     //TODO: cover more cases once the permission stuff has been implemented | ||||
|  | ||||
|     /* All of the requests in the list should be allowed. | ||||
|      */ | ||||
|     ret = countPermissionConflicts(&list, false); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Add a request that will be denied. | ||||
|      */ | ||||
|     ret = addPermissionRequestToList(&list, "/stat", false, 1<<31 | PERM_STAT); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = countPermissionConflicts(&list, false); | ||||
|     assert(ret == 1); | ||||
|  | ||||
|     //TODO: more tests | ||||
|  | ||||
|     permissionCleanup(); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| test_permissions() | ||||
| { | ||||
|     int ret; | ||||
|  | ||||
|     ret = test_permission_list(); | ||||
|     if (ret != 0) { | ||||
|         fprintf(stderr, "test_permission_list() failed: %d\n", ret); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     ret = test_permission_table(); | ||||
|     if (ret != 0) { | ||||
|         fprintf(stderr, "test_permission_table() failed: %d\n", ret); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     ret = test_allowed_permissions(); | ||||
|     if (ret != 0) { | ||||
|         fprintf(stderr, "test_permission_table() failed: %d\n", ret); | ||||
|         return ret; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										146
									
								
								amend/test_symtab.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										146
									
								
								amend/test_symtab.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,146 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #undef NDEBUG | ||||
| #include <assert.h> | ||||
| #include "symtab.h" | ||||
|  | ||||
| int | ||||
| test_symtab() | ||||
| { | ||||
|     SymbolTable *tab; | ||||
|     void *cookie; | ||||
|     int ret; | ||||
|  | ||||
|     /* Test creation */ | ||||
|     tab = createSymbolTable(); | ||||
|     assert(tab != NULL); | ||||
|  | ||||
|     /* Smoke-test deletion */ | ||||
|     deleteSymbolTable(tab); | ||||
|  | ||||
|  | ||||
|     tab = createSymbolTable(); | ||||
|     assert(tab != NULL); | ||||
|  | ||||
|  | ||||
|     /* table parameter must be non-NULL. */ | ||||
|     ret = addToSymbolTable(NULL, NULL, 0, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* symbol parameter must be non-NULL. */ | ||||
|     ret = addToSymbolTable(tab, NULL, 0, NULL); | ||||
|     assert(ret < 0); | ||||
|      | ||||
|     /* cookie parameter must be non-NULL. */ | ||||
|     ret = addToSymbolTable(tab, "null", 0, NULL); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|  | ||||
|     /* table parameter must be non-NULL. */ | ||||
|     cookie = findInSymbolTable(NULL, NULL, 0); | ||||
|     assert(cookie == NULL); | ||||
|  | ||||
|     /* symbol parameter must be non-NULL. */ | ||||
|     cookie = findInSymbolTable(tab, NULL, 0); | ||||
|     assert(cookie == NULL); | ||||
|  | ||||
|  | ||||
|     /* Try some actual inserts. | ||||
|      */ | ||||
|     ret = addToSymbolTable(tab, "one", 0, (void *)1); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = addToSymbolTable(tab, "two", 0, (void *)2); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     ret = addToSymbolTable(tab, "three", 0, (void *)3); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Try some lookups. | ||||
|      */ | ||||
|     cookie = findInSymbolTable(tab, "one", 0); | ||||
|     assert((int)cookie == 1); | ||||
|  | ||||
|     cookie = findInSymbolTable(tab, "two", 0); | ||||
|     assert((int)cookie == 2); | ||||
|  | ||||
|     cookie = findInSymbolTable(tab, "three", 0); | ||||
|     assert((int)cookie == 3); | ||||
|  | ||||
|     /* Try to insert something that's already there. | ||||
|      */ | ||||
|     ret = addToSymbolTable(tab, "one", 0, (void *)1111); | ||||
|     assert(ret < 0); | ||||
|  | ||||
|     /* Make sure that the failed duplicate insert didn't | ||||
|      * clobber the original cookie value. | ||||
|      */ | ||||
|     cookie = findInSymbolTable(tab, "one", 0); | ||||
|     assert((int)cookie == 1); | ||||
|  | ||||
|     /* Try looking up something that isn't there. | ||||
|      */ | ||||
|     cookie = findInSymbolTable(tab, "FOUR", 0); | ||||
|     assert(cookie == NULL); | ||||
|  | ||||
|     /* Try looking up something that's similar to an existing entry. | ||||
|      */ | ||||
|     cookie = findInSymbolTable(tab, "on", 0); | ||||
|     assert(cookie == NULL); | ||||
|  | ||||
|     cookie = findInSymbolTable(tab, "onee", 0); | ||||
|     assert(cookie == NULL); | ||||
|  | ||||
|     /* Test flags. | ||||
|      * Try inserting something with a different flag. | ||||
|      */ | ||||
|     ret = addToSymbolTable(tab, "ten", 333, (void *)10); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Make sure it's there. | ||||
|      */ | ||||
|     cookie = findInSymbolTable(tab, "ten", 333); | ||||
|     assert((int)cookie == 10); | ||||
|  | ||||
|     /* Make sure it's not there when looked up with a different flag. | ||||
|      */ | ||||
|     cookie = findInSymbolTable(tab, "ten", 0); | ||||
|     assert(cookie == NULL); | ||||
|  | ||||
|     /* Try inserting something that has the same name as something | ||||
|      * with a different flag. | ||||
|      */ | ||||
|     ret = addToSymbolTable(tab, "one", 333, (void *)11); | ||||
|     assert(ret == 0); | ||||
|  | ||||
|     /* Make sure the new entry exists. | ||||
|      */ | ||||
|     cookie = findInSymbolTable(tab, "one", 333); | ||||
|     assert((int)cookie == 11); | ||||
|  | ||||
|     /* Make sure the old entry still has the right value. | ||||
|      */ | ||||
|     cookie = findInSymbolTable(tab, "one", 0); | ||||
|     assert((int)cookie == 1); | ||||
|  | ||||
|     /* Try deleting again, now that there's stuff in the table. | ||||
|      */ | ||||
|     deleteSymbolTable(tab); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
							
								
								
									
										1
									
								
								amend/tests/001-nop/expected.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/001-nop/expected.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| I am a jelly donut. | ||||
							
								
								
									
										2
									
								
								amend/tests/001-nop/info.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								amend/tests/001-nop/info.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| This is a sample no-op test, which does at least serve to verify that the | ||||
| test harness is working. | ||||
							
								
								
									
										17
									
								
								amend/tests/001-nop/run
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								amend/tests/001-nop/run
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| echo 'I am a jelly donut.' | ||||
							
								
								
									
										0
									
								
								amend/tests/002-lex-empty/SKIP
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								amend/tests/002-lex-empty/SKIP
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										1
									
								
								amend/tests/002-lex-empty/expected.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/002-lex-empty/expected.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
|  EOF | ||||
							
								
								
									
										1
									
								
								amend/tests/002-lex-empty/info.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/002-lex-empty/info.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Test to make sure that an empty file is accepted properly. | ||||
							
								
								
									
										0
									
								
								amend/tests/002-lex-empty/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								amend/tests/002-lex-empty/input
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										17
									
								
								amend/tests/002-lex-empty/run
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								amend/tests/002-lex-empty/run
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| amend --debug-lex input | ||||
							
								
								
									
										13
									
								
								amend/tests/003-lex-command/expected.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								amend/tests/003-lex-command/expected.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
|  IDENTIFIER<this_identifier_is_not_assert> EOL | ||||
|  IDENTIFIER<NEITHER_IS_THIS_123> EOL | ||||
|  IDENTIFIER<but_the_next_one_is> EOL | ||||
|  IDENTIFIER<assert> EOL | ||||
|  IDENTIFIER<next_one_is_not_an_identifier> EOL | ||||
| line 6: unexpected character at '1' | ||||
|  EOF | ||||
| line 1: unexpected character at '"' | ||||
|  EOF | ||||
| line 1: unexpected character at '=' | ||||
|  EOF | ||||
| line 1: unexpected character at '9' | ||||
|  EOF | ||||
							
								
								
									
										1
									
								
								amend/tests/003-lex-command/info.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/003-lex-command/info.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Test to make sure that simple command names are tokenized properly. | ||||
							
								
								
									
										6
									
								
								amend/tests/003-lex-command/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								amend/tests/003-lex-command/input
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| this_identifier_is_not_assert | ||||
| NEITHER_IS_THIS_123 | ||||
| but_the_next_one_is | ||||
| assert | ||||
| next_one_is_not_an_identifier | ||||
| 12not_an_identifier | ||||
							
								
								
									
										1
									
								
								amend/tests/003-lex-command/input2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/003-lex-command/input2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| "quoted" | ||||
							
								
								
									
										1
									
								
								amend/tests/003-lex-command/input3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/003-lex-command/input3
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| == | ||||
							
								
								
									
										1
									
								
								amend/tests/003-lex-command/input4
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/003-lex-command/input4
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| 99 | ||||
							
								
								
									
										20
									
								
								amend/tests/003-lex-command/run
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								amend/tests/003-lex-command/run
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| amend --debug-lex input | ||||
| amend --debug-lex input2 | ||||
| amend --debug-lex input3 | ||||
| amend --debug-lex input4 | ||||
							
								
								
									
										5
									
								
								amend/tests/004-lex-comment/expected.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								amend/tests/004-lex-comment/expected.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
|  IDENTIFIER<comment_on_this_line> EOL | ||||
|  IDENTIFIER<none_on_this_one> EOL | ||||
|  EOL | ||||
|  EOL | ||||
|  EOF | ||||
							
								
								
									
										1
									
								
								amend/tests/004-lex-comment/info.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/004-lex-comment/info.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Test to make sure that comments are stripped out. | ||||
							
								
								
									
										4
									
								
								amend/tests/004-lex-comment/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								amend/tests/004-lex-comment/input
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| comment_on_this_line # this is a "comment" (with / a bunch) # \\ of stuff \ | ||||
| none_on_this_one | ||||
| # beginning of line | ||||
|                          # preceded by whitespace | ||||
							
								
								
									
										17
									
								
								amend/tests/004-lex-comment/run
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								amend/tests/004-lex-comment/run
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| amend --debug-lex input | ||||
							
								
								
									
										13
									
								
								amend/tests/005-lex-quoted-string/expected.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								amend/tests/005-lex-quoted-string/expected.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
|  IDENTIFIER<test> WORD<string> EOL | ||||
|  IDENTIFIER<test> WORD<string with spaces> EOL | ||||
|  IDENTIFIER<test> WORD<string with "escaped" quotes> EOL | ||||
|  IDENTIFIER<test> WORD<string with \escaped\ backslashes> EOL | ||||
|  IDENTIFIER<test> WORD<string with # a comment character> EOL | ||||
|  EOF | ||||
|  EOL | ||||
|  IDENTIFIER<test1>line 2: unterminated string at ' | ||||
| ' | ||||
|  ??? <0> | ||||
|  EOL | ||||
|  IDENTIFIER<test1>line 2: illegal escape at '\n' | ||||
|  ??? <0> | ||||
							
								
								
									
										1
									
								
								amend/tests/005-lex-quoted-string/info.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/005-lex-quoted-string/info.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Test to make sure that quoted strings are tokenized properly. | ||||
							
								
								
									
										5
									
								
								amend/tests/005-lex-quoted-string/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								amend/tests/005-lex-quoted-string/input
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| test "string" | ||||
| test "string with spaces" | ||||
| test "string with \"escaped\" quotes" | ||||
| test "string with \\escaped\\ backslashes" | ||||
| test "string with # a comment character" | ||||
							
								
								
									
										2
									
								
								amend/tests/005-lex-quoted-string/input2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								amend/tests/005-lex-quoted-string/input2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| # This should fail | ||||
| test1 "unterminated string | ||||
							
								
								
									
										2
									
								
								amend/tests/005-lex-quoted-string/input3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								amend/tests/005-lex-quoted-string/input3
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| # This should fail | ||||
| test1 "string with illegal escape \n in the middle" | ||||
							
								
								
									
										19
									
								
								amend/tests/005-lex-quoted-string/run
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								amend/tests/005-lex-quoted-string/run
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| amend --debug-lex input | ||||
| amend --debug-lex input2 | ||||
| amend --debug-lex input3 | ||||
							
								
								
									
										0
									
								
								amend/tests/006-lex-words/SKIP
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								amend/tests/006-lex-words/SKIP
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										6
									
								
								amend/tests/006-lex-words/expected.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								amend/tests/006-lex-words/expected.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
|  IDENTIFIER<test> WORD<this> WORD<has> WORD<a> WORD<bunch> WORD<of> WORD<BARE> WORD<ALPHA> WORD<WORDS> EOL | ||||
|  IDENTIFIER<test> WORD<12> WORD<this> WORD<has(some> WORD<)> WORD<ALPHANUMER1C> WORD<and> WORD<\\> WORD<whatever> WORD<characters> EOL | ||||
|  IDENTIFIER<test> WORD<this> WORD<has> WORD<mixed> WORD<bare> WORD<and quoted> WORD<words> EOL | ||||
|  IDENTIFIER<test> WORD<what> WORD<about> WORD<quotesin the middle?> EOL | ||||
|  IDENTIFIER<test> WORD<"""shouldn't> WORD<be> WORD<a> WORD<quoted> WORD<string> EOL | ||||
|  EOF | ||||
							
								
								
									
										1
									
								
								amend/tests/006-lex-words/info.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/006-lex-words/info.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| Test to make sure that argument words are tokenized properly. | ||||
							
								
								
									
										5
									
								
								amend/tests/006-lex-words/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								amend/tests/006-lex-words/input
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| test this has a bunch of BARE ALPHA WORDS | ||||
| test 12 this has(some ) ALPHANUMER1C and \\ whatever characters | ||||
| test this has mixed bare "and quoted" words | ||||
| test what about quotes"in the middle?" | ||||
| test \"\"\"shouldn't be a quoted string | ||||
							
								
								
									
										2
									
								
								amend/tests/006-lex-words/input2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								amend/tests/006-lex-words/input2
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| # This should fail | ||||
| test1 "unterminated string | ||||
							
								
								
									
										2
									
								
								amend/tests/006-lex-words/input3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								amend/tests/006-lex-words/input3
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| # This should fail | ||||
| test1 "string with illegal escape \n in the middle" | ||||
							
								
								
									
										17
									
								
								amend/tests/006-lex-words/run
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								amend/tests/006-lex-words/run
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| amend --debug-lex input | ||||
							
								
								
									
										11
									
								
								amend/tests/007-lex-real-script/expected.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								amend/tests/007-lex-real-script/expected.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
|  IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<112345oldhashvalue1234123> EOL | ||||
|  IDENTIFIER<mark> WORD<SYS:> WORD<dirty> EOL | ||||
|  IDENTIFIER<copy_dir> WORD<PKG:android-files> WORD<SYS:> EOL | ||||
|  IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<667890newhashvalue6678909> EOL | ||||
|  IDENTIFIER<mark> WORD<SYS:> WORD<clean> EOL | ||||
|  IDENTIFIER<done> EOL | ||||
|  IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> , STRING<blah> ) == STRING<112345oldhashvalue1234123> EOL | ||||
|  IDENTIFIER<assert> STRING<true> == STRING<false> EOL | ||||
|  IDENTIFIER<assert> IDENTIFIER<one> ( STRING<abc> , IDENTIFIER<two> ( STRING<def> ) ) == STRING<five> EOL | ||||
|  IDENTIFIER<assert> IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<667890newhashvalue6678909> || IDENTIFIER<hash_dir> ( STRING<SYS:> ) == STRING<667890newhashvalue6678909> EOL | ||||
|  EOF | ||||
							
								
								
									
										1
									
								
								amend/tests/007-lex-real-script/info.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/007-lex-real-script/info.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| An input script similar to one that will actually be used in practice. | ||||
							
								
								
									
										10
									
								
								amend/tests/007-lex-real-script/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								amend/tests/007-lex-real-script/input
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| assert hash_dir("SYS:") == "112345oldhashvalue1234123" | ||||
| mark SYS: dirty | ||||
| copy_dir "PKG:android-files" SYS: | ||||
| assert hash_dir("SYS:") == "667890newhashvalue6678909" | ||||
| mark SYS: clean | ||||
| done | ||||
| assert hash_dir("SYS:", "blah") == "112345oldhashvalue1234123" | ||||
| assert "true" == "false" | ||||
| assert one("abc", two("def")) == "five" | ||||
| assert hash_dir("SYS:") == "667890newhashvalue6678909" || hash_dir("SYS:") == "667890newhashvalue6678909" | ||||
							
								
								
									
										17
									
								
								amend/tests/007-lex-real-script/run
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								amend/tests/007-lex-real-script/run
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| amend --debug-lex input | ||||
							
								
								
									
										74
									
								
								amend/tests/008-parse-real-script/expected.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								amend/tests/008-parse-real-script/expected.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,74 @@ | ||||
| command "assert" { | ||||
|     STRING EQ { | ||||
|         FUNCTION hash_dir ( | ||||
|             "SYS:" | ||||
|         ) | ||||
|         "112345oldhashvalue1234123" | ||||
|     } | ||||
| } | ||||
| command "mark" { | ||||
|     "SYS:" | ||||
|     "dirty" | ||||
| } | ||||
| command "copy_dir" { | ||||
|     "PKG:android-files" | ||||
|     "SYS:" | ||||
| } | ||||
| command "assert" { | ||||
|     STRING EQ { | ||||
|         FUNCTION hash_dir ( | ||||
|             "SYS:" | ||||
|         ) | ||||
|         "667890newhashvalue6678909" | ||||
|     } | ||||
| } | ||||
| command "mark" { | ||||
|     "SYS:" | ||||
|     "clean" | ||||
| } | ||||
| command "done" { | ||||
| } | ||||
| command "assert" { | ||||
|     STRING EQ { | ||||
|         FUNCTION hash_dir ( | ||||
|             "SYS:" | ||||
|             "blah" | ||||
|         ) | ||||
|         "112345oldhashvalue1234123" | ||||
|     } | ||||
| } | ||||
| command "assert" { | ||||
|     STRING EQ { | ||||
|         "true" | ||||
|         "false" | ||||
|     } | ||||
| } | ||||
| command "assert" { | ||||
|     STRING NE { | ||||
|         FUNCTION matches ( | ||||
|             FUNCTION hash_dir ( | ||||
|                 "SYS:" | ||||
|             ) | ||||
|             "667890newhashvalue6678909" | ||||
|             "999999newhashvalue6678909" | ||||
|         ) | ||||
|         "" | ||||
|     } | ||||
| } | ||||
| command "assert" { | ||||
|     BOOLEAN OR { | ||||
|         STRING EQ { | ||||
|             FUNCTION hash_dir ( | ||||
|                 "SYS:" | ||||
|             ) | ||||
|             "667890newhashvalue6678909" | ||||
|         } | ||||
|         STRING EQ { | ||||
|             FUNCTION hash_dir ( | ||||
|                 "SYS:" | ||||
|             ) | ||||
|             "999999newhashvalue6678909" | ||||
|         } | ||||
|     } | ||||
| } | ||||
| amend: Parse successful. | ||||
							
								
								
									
										1
									
								
								amend/tests/008-parse-real-script/info.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								amend/tests/008-parse-real-script/info.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| An input script similar to one that will actually be used in practice. | ||||
							
								
								
									
										10
									
								
								amend/tests/008-parse-real-script/input
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								amend/tests/008-parse-real-script/input
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| assert hash_dir("SYS:") == "112345oldhashvalue1234123" | ||||
| mark SYS: dirty | ||||
| copy_dir "PKG:android-files" SYS: | ||||
| assert hash_dir("SYS:") == "667890newhashvalue6678909" | ||||
| mark SYS: clean | ||||
| done | ||||
| assert hash_dir("SYS:", "blah") == "112345oldhashvalue1234123" | ||||
| assert "true" == "false" | ||||
| assert matches(hash_dir("SYS:"), "667890newhashvalue6678909", "999999newhashvalue6678909") != "" | ||||
| assert hash_dir("SYS:") == "667890newhashvalue6678909" || hash_dir("SYS:") == "999999newhashvalue6678909" | ||||
							
								
								
									
										17
									
								
								amend/tests/008-parse-real-script/run
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								amend/tests/008-parse-real-script/run
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| amend --debug-ast input | ||||
							
								
								
									
										0
									
								
								amend/tests/XXX-long-token/SKIP
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								amend/tests/XXX-long-token/SKIP
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								amend/tests/XXX-stack-overflow/SKIP
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								amend/tests/XXX-stack-overflow/SKIP
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										150
									
								
								amend/tests/one-test
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										150
									
								
								amend/tests/one-test
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,150 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| # Set up prog to be the path of this script, including following symlinks, | ||||
| # and set up progdir to be the fully-qualified pathname of its directory. | ||||
| prog="$0" | ||||
| while [ -h "${prog}" ]; do | ||||
|     newProg=`/bin/ls -ld "${prog}"` | ||||
|     newProg=`expr "${newProg}" : ".* -> \(.*\)$"` | ||||
|     if expr "x${newProg}" : 'x/' >/dev/null; then | ||||
|         prog="${newProg}" | ||||
|     else | ||||
|         progdir=`dirname "${prog}"` | ||||
|         prog="${progdir}/${newProg}" | ||||
|     fi | ||||
| done | ||||
| oldwd=`pwd` | ||||
| progdir=`dirname "${prog}"` | ||||
| cd "${progdir}" | ||||
| progdir=`pwd` | ||||
| prog="${progdir}"/`basename "${prog}"` | ||||
|  | ||||
| info="info.txt" | ||||
| run="run" | ||||
| expected="expected.txt" | ||||
| output="out.txt" | ||||
| skip="SKIP" | ||||
|  | ||||
| dev_mode="no" | ||||
| if [ "x$1" = "x--dev" ]; then | ||||
|     dev_mode="yes" | ||||
|     shift | ||||
| fi | ||||
|  | ||||
| update_mode="no" | ||||
| if [ "x$1" = "x--update" ]; then | ||||
|     update_mode="yes" | ||||
|     shift | ||||
| fi | ||||
|  | ||||
| usage="no" | ||||
| if [ "x$1" = "x--help" ]; then | ||||
|     usage="yes" | ||||
| else | ||||
|     if [ "x$1" = "x" ]; then | ||||
|         testdir=`basename "$oldwd"` | ||||
|     else | ||||
|         testdir="$1" | ||||
|     fi | ||||
|  | ||||
|     if [ '!' -d "$testdir" ]; then | ||||
|         td2=`echo ${testdir}-*` | ||||
|         if [ '!' -d "$td2" ]; then | ||||
|             echo "${testdir}: no such test directory" 1>&2 | ||||
|             usage="yes" | ||||
|         fi | ||||
|         testdir="$td2" | ||||
|     fi | ||||
| fi | ||||
|  | ||||
| if [ "$usage" = "yes" ]; then | ||||
|     prog=`basename $prog` | ||||
|     ( | ||||
|         echo "usage:" | ||||
|         echo "  $prog --help             Print this message." | ||||
|         echo "  $prog testname           Run test normally." | ||||
|         echo "  $prog --dev testname     Development mode (dump to stdout)." | ||||
|         echo "  $prog --update testname  Update mode (replace expected.txt)." | ||||
|         echo "  Omitting the test name uses the current directory as the test." | ||||
|     ) 1>&2 | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| td_info="$testdir"/"$info" | ||||
| td_run="$testdir"/"$run" | ||||
| td_expected="$testdir"/"$expected" | ||||
| td_skip="$testdir"/"$skip" | ||||
|  | ||||
| if [ -r "$td_skip" ]; then | ||||
|     exit 2 | ||||
| fi | ||||
|  | ||||
| tmpdir=/tmp/test-$$ | ||||
|  | ||||
| if [ '!' '(' -r "$td_info" -a -r "$td_run" -a -r "$td_expected" ')' ]; then | ||||
|     echo "${testdir}: missing files" 1>&2 | ||||
|     exit 1 | ||||
| fi | ||||
|  | ||||
| # copy the test to a temp dir and run it | ||||
|  | ||||
| echo "${testdir}: running..." 1>&2 | ||||
|  | ||||
| rm -rf "$tmpdir" | ||||
| cp -Rp "$testdir" "$tmpdir" | ||||
| cd "$tmpdir" | ||||
| chmod 755 "$run" | ||||
|  | ||||
| #PATH="${progdir}/../build/bin:${PATH}" | ||||
|  | ||||
| good="no" | ||||
| if [ "$dev_mode" = "yes" ]; then | ||||
|     "./$run" 2>&1 | ||||
|     echo "exit status: $?" 1>&2 | ||||
|     good="yes" | ||||
| elif [ "$update_mode" = "yes" ]; then | ||||
|     "./$run" >"${progdir}/$td_expected" 2>&1 | ||||
|     good="yes" | ||||
| else | ||||
|     "./$run" >"$output" 2>&1 | ||||
|     cmp -s "$expected" "$output" | ||||
|     if [ "$?" = "0" ]; then | ||||
|         # output == expected | ||||
|         good="yes" | ||||
|         echo "$testdir"': succeeded!' 1>&2 | ||||
|     fi | ||||
| fi | ||||
|  | ||||
| if [ "$good" = "yes" ]; then | ||||
|     cd "$oldwd" | ||||
|     rm -rf "$tmpdir" | ||||
|     exit 0 | ||||
| fi | ||||
|  | ||||
| ( | ||||
|     echo "${testdir}: FAILED!" | ||||
|     echo ' ' | ||||
|     echo '#################### info' | ||||
|     cat "$info" | sed 's/^/# /g' | ||||
|     echo '#################### diffs' | ||||
|     diff -u "$expected" "$output" | ||||
|     echo '####################' | ||||
|     echo ' ' | ||||
|     echo "files left in $tmpdir" | ||||
| ) 1>&2 | ||||
|  | ||||
| exit 1 | ||||
							
								
								
									
										69
									
								
								amend/tests/run-all-tests
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										69
									
								
								amend/tests/run-all-tests
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| #!/bin/bash | ||||
| # | ||||
| # Copyright (C) 2007 The Android Open Source Project | ||||
| # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | ||||
| # You may obtain a copy of the License at | ||||
| # | ||||
| #     http://www.apache.org/licenses/LICENSE-2.0 | ||||
| # | ||||
| # Unless required by applicable law or agreed to in writing, software | ||||
| # distributed under the License is distributed on an "AS IS" BASIS, | ||||
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| # See the License for the specific language governing permissions and | ||||
| # limitations under the License. | ||||
|  | ||||
| # Set up prog to be the path of this script, including following symlinks, | ||||
| # and set up progdir to be the fully-qualified pathname of its directory. | ||||
| prog="$0" | ||||
| while [ -h "${prog}" ]; do | ||||
|     newProg=`/bin/ls -ld "${prog}"` | ||||
|     newProg=`expr "${newProg}" : ".* -> \(.*\)$"` | ||||
|     if expr "x${newProg}" : 'x/' >/dev/null; then | ||||
|         prog="${newProg}" | ||||
|     else | ||||
|         progdir=`dirname "${prog}"` | ||||
|         prog="${progdir}/${newProg}" | ||||
|     fi | ||||
| done | ||||
| oldwd=`pwd` | ||||
| progdir=`dirname "${prog}"` | ||||
| cd "${progdir}" | ||||
| progdir=`pwd` | ||||
| prog="${progdir}"/`basename "${prog}"` | ||||
|  | ||||
| passed=0 | ||||
| skipped=0 | ||||
| skipNames="" | ||||
| failed=0 | ||||
| failNames="" | ||||
|  | ||||
| for i in *; do | ||||
|     if [ -d "$i" -a -r "$i" ]; then | ||||
|         ./one-test "$i" | ||||
|         status=$? | ||||
|         if [ "$status" = "0" ]; then | ||||
|             ((passed += 1)) | ||||
|         elif [ "$status" = "2" ]; then | ||||
|             ((skipped += 1)) | ||||
|             skipNames="$skipNames $i" | ||||
|         else | ||||
|             ((failed += 1)) | ||||
|             failNames="$failNames $i" | ||||
|         fi | ||||
|     fi | ||||
| done | ||||
|  | ||||
| echo "passed:  $passed test(s)" | ||||
| echo "skipped: $skipped test(s)" | ||||
|  | ||||
| for i in $skipNames; do | ||||
|     echo "skipped: $i" | ||||
| done | ||||
|  | ||||
| echo "failed:  $failed test(s)" | ||||
|      | ||||
| for i in $failNames; do | ||||
|     echo "failed: $i" | ||||
| done | ||||
| @@ -33,6 +33,7 @@ | ||||
| #include "roots.h" | ||||
| #include "verifier.h" | ||||
| #include "firmware.h" | ||||
| #include "legacy.h" | ||||
|  | ||||
| #define ASSUMED_UPDATE_BINARY_NAME  "META-INF/com/google/android/update-binary" | ||||
| #define PUBLIC_KEYS_FILE "/res/keys" | ||||
| @@ -103,7 +104,7 @@ try_update_binary(const char *path, ZipArchive *zip) { | ||||
|     const ZipEntry* binary_entry = | ||||
|             mzFindZipEntry(zip, ASSUMED_UPDATE_BINARY_NAME); | ||||
|     if (binary_entry == NULL) { | ||||
|         return INSTALL_CORRUPT; | ||||
|         return INSTALL_UPDATE_BINARY_MISSING; | ||||
|     } | ||||
|  | ||||
|     char* binary = "/tmp/update_binary"; | ||||
| @@ -240,6 +241,12 @@ handle_update_package(const char *path, ZipArchive *zip) | ||||
|     ui_print("Installing update...\n"); | ||||
|  | ||||
|     int result = try_update_binary(path, zip); | ||||
| 	if (result == INSTALL_UPDATE_BINARY_MISSING) | ||||
| 	{ | ||||
| 	    const ZipEntry *script_entry; | ||||
| 	    script_entry = find_update_script(zip); | ||||
| 	    result = handle_update_script(zip, script_entry); | ||||
| 	} | ||||
|     register_package_root(NULL, NULL);  // Unregister package root | ||||
|     return result; | ||||
| } | ||||
|   | ||||
| @@ -19,7 +19,7 @@ | ||||
|  | ||||
| #include "common.h" | ||||
|  | ||||
| enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT }; | ||||
| enum { INSTALL_SUCCESS, INSTALL_ERROR, INSTALL_CORRUPT, INSTALL_UPDATE_BINARY_MISSING }; | ||||
| int install_package(const char *root_path); | ||||
|  | ||||
| #endif  // RECOVERY_INSTALL_H_ | ||||
|   | ||||
							
								
								
									
										98
									
								
								legacy.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								legacy.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,98 @@ | ||||
| /* | ||||
|  * Copyright (C) 2007 The Android Open Source Project | ||||
|  * | ||||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|  * you may not use this file except in compliance with the License. | ||||
|  * You may obtain a copy of the License at | ||||
|  * | ||||
|  *      http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  * | ||||
|  * Unless required by applicable law or agreed to in writing, software | ||||
|  * distributed under the License is distributed on an "AS IS" BASIS, | ||||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|  * See the License for the specific language governing permissions and | ||||
|  * limitations under the License. | ||||
|  */ | ||||
|  | ||||
| #include <ctype.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <limits.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/wait.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include "common.h" | ||||
| #include "install.h" | ||||
| #include "mincrypt/rsa.h" | ||||
| #include "minui/minui.h" | ||||
| #include "minzip/SysUtil.h" | ||||
| #include "minzip/Zip.h" | ||||
| #include "mtdutils/mounts.h" | ||||
| #include "mtdutils/mtdutils.h" | ||||
| #include "roots.h" | ||||
| #include "verifier.h" | ||||
| #include "firmware.h" | ||||
|  | ||||
| #include "amend/amend.h" | ||||
| #include "common.h" | ||||
| #include "install.h" | ||||
| #include "mincrypt/rsa.h" | ||||
| #include "minui/minui.h" | ||||
| #include "minzip/SysUtil.h" | ||||
| #include "minzip/Zip.h" | ||||
| #include "mtdutils/mounts.h" | ||||
| #include "mtdutils/mtdutils.h" | ||||
| #include "roots.h" | ||||
| #include "verifier.h" | ||||
|  | ||||
| int | ||||
| handle_update_script(ZipArchive *zip, const ZipEntry *update_script_entry) | ||||
| { | ||||
|     /* Read the entire script into a buffer. | ||||
|      */ | ||||
|     int script_len; | ||||
|     char* script_data; | ||||
|     if (read_data(zip, update_script_entry, &script_data, &script_len) < 0) { | ||||
|         LOGE("Can't read update script\n"); | ||||
|         return INSTALL_ERROR; | ||||
|     } | ||||
|  | ||||
|     /* Parse the script.  Note that the script and parse tree are never freed. | ||||
|      */ | ||||
|     const AmCommandList *commands = parseAmendScript(script_data, script_len); | ||||
|     if (commands == NULL) { | ||||
|         LOGE("Syntax error in update script\n"); | ||||
|         return INSTALL_ERROR; | ||||
|     } else { | ||||
|         UnterminatedString name = mzGetZipEntryFileName(update_script_entry); | ||||
|         LOGI("Parsed %.*s\n", name.len, name.str); | ||||
|     } | ||||
|  | ||||
|     /* Execute the script. | ||||
|      */ | ||||
|     int ret = execCommandList((ExecContext *)1, commands); | ||||
|     if (ret != 0) { | ||||
|         int num = ret; | ||||
|         char *line, *next = script_data; | ||||
|         while (next != NULL && ret-- > 0) { | ||||
|             line = next; | ||||
|             next = memchr(line, '\n', script_data + script_len - line); | ||||
|             if (next != NULL) *next++ = '\0'; | ||||
|         } | ||||
|         LOGE("Failure at line %d:\n%s\n", num, next ? line : "(not found)"); | ||||
|         return INSTALL_ERROR; | ||||
|     } | ||||
|  | ||||
|     ui_print("Installation complete.\n"); | ||||
|     return INSTALL_SUCCESS; | ||||
| } | ||||
|  | ||||
| #define ASSUMED_UPDATE_SCRIPT_NAME  "META-INF/com/google/android/update-script" | ||||
|  | ||||
| const ZipEntry * | ||||
| find_update_script(ZipArchive *zip) | ||||
| { | ||||
| //TODO: Get the location of this script from the MANIFEST.MF file | ||||
|     return mzFindZipEntry(zip, ASSUMED_UPDATE_SCRIPT_NAME); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user