summaryrefslogblamecommitdiffstats
path: root/amend/register.c
blob: 167dd32e532cdbe638232661aafb3af18ec8b7bd (plain) (tree)









































































































































































































































































































































































































                                                                              
/*
 * 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;
}