/* * 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 #include #include #undef NDEBUG #include #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 */ 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 */ 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 */ 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 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() * * 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() */ 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(, [, ...]) * If matches (strcmp) any of ..., returns , * 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(, [, ...]) * 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; }