Amend (aka the recovery command language) had a half-implemented scheme of limiting which commands OTA packages were allowed to execute. It's not clear what this was ever supposed to be good for. Remove it.
		
			
				
	
	
		
			466 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			466 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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;
 | 
						|
    int returnValue;
 | 
						|
    char *functionResult;
 | 
						|
} gTestCommandState;
 | 
						|
 | 
						|
static int
 | 
						|
testCommand(const char *name, void *cookie, int argc, const char *argv[])
 | 
						|
{
 | 
						|
    gTestCommandState.called = true;
 | 
						|
    gTestCommandState.name = name;
 | 
						|
    gTestCommandState.cookie = cookie;
 | 
						|
    gTestCommandState.argc = argc;
 | 
						|
    gTestCommandState.argv = argv;
 | 
						|
    return gTestCommandState.returnValue;
 | 
						|
}
 | 
						|
 | 
						|
static int
 | 
						|
testFunction(const char *name, void *cookie, int argc, const char *argv[],
 | 
						|
        char **result, size_t *resultLen)
 | 
						|
{
 | 
						|
    gTestCommandState.called = true;
 | 
						|
    gTestCommandState.name = name;
 | 
						|
    gTestCommandState.cookie = cookie;
 | 
						|
    gTestCommandState.argc = argc;
 | 
						|
    gTestCommandState.argv = argv;
 | 
						|
    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;
 | 
						|
    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);
 | 
						|
 | 
						|
    /* 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;
 | 
						|
    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);
 | 
						|
 | 
						|
    memset(&gTestCommandState, 0, sizeof(gTestCommandState));
 | 
						|
    gTestCommandState.called = false;
 | 
						|
    gTestCommandState.returnValue = 13;
 | 
						|
    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);
 | 
						|
 | 
						|
    /* 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";
 | 
						|
    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(strcmp(functionResult, "1234") == 0);
 | 
						|
    assert(functionResultLen == strlen(functionResult));
 | 
						|
 | 
						|
    /* 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;
 | 
						|
    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);
 | 
						|
 | 
						|
    /* 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";
 | 
						|
    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(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;
 | 
						|
}
 |