/* * Copyright (C) 2016 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 <inttypes.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <hardware/nvram.h> #define countof(array) (sizeof(array) / sizeof((array)[0])) // Exit status codes. These are all negative as the positive ones are used for // the NV_RESULT_ codes. enum StatusCode { kStatusInvalidArg = -1, kStatusHALError = -2, kStatusAllocationFailure = -3, }; static struct { int status; const char* description; } kStatusStringTable[] = { {kStatusInvalidArg, "Bad parameter"}, {kStatusHALError, "NVRAM HAL initialization error"}, {kStatusAllocationFailure, "Memory allocation error"}, {NV_RESULT_SUCCESS, "Success"}, {NV_RESULT_INTERNAL_ERROR, "Internal error"}, {NV_RESULT_ACCESS_DENIED, "Access denied"}, {NV_RESULT_INVALID_PARAMETER, "Invalid NVRAM parameter"}, {NV_RESULT_SPACE_DOES_NOT_EXIST, "Space does not exist"}, {NV_RESULT_SPACE_ALREADY_EXISTS, "Space already exists"}, {NV_RESULT_OPERATION_DISABLED, "Operation disabled"}, }; // Returns a string describing |status|. static const char* StatusToString(int status) { for (size_t i = 0; i < countof(kStatusStringTable); ++i) { if (kStatusStringTable[i].status == status) { return kStatusStringTable[i].description; } } return "unknown error"; } // A table mapping control values to names. static struct { nvram_control_t control; const char* name; } kControlNameTable[] = { {NV_CONTROL_PERSISTENT_WRITE_LOCK, "PERSISTENT_WRITE_LOCK"}, {NV_CONTROL_BOOT_WRITE_LOCK, "BOOT_WRITE_LOCK"}, {NV_CONTROL_BOOT_READ_LOCK, "BOOT_READ_LOCK"}, {NV_CONTROL_WRITE_AUTHORIZATION, "WRITE_AUTHORIZATION"}, {NV_CONTROL_READ_AUTHORIZATION, "READ_AUTHORIZATION"}, {NV_CONTROL_WRITE_EXTEND, "WRITE_EXTEND"}, }; // Returns the string representation of |control|, or NULL if |control| isn't a // valid control value. static const char* ControlToString(nvram_control_t control) { for (size_t i = 0; i < countof(kControlNameTable); ++i) { if (kControlNameTable[i].control == control) { return kControlNameTable[i].name; } } return NULL; } // Sets |control| to the NV_CONTROL_ value corresponding to the string control // representation found in |name|. Returns 0 if successful, 1 if name doesn't // match any control string. static int StringToControl(const char* name, nvram_control_t* control) { for (size_t i = 0; i < countof(kControlNameTable); ++i) { if (strcmp(kControlNameTable[i].name, name) == 0) { *control = kControlNameTable[i].control; return 0; } } return 1; } static int HandleGetTotalSize(nvram_device_t* device, char* args[]) { (void)args; uint64_t total_size = 0; nvram_result_t result = device->get_total_size_in_bytes(device, &total_size); if (result != NV_RESULT_SUCCESS) { return result; } printf("%" PRIu64 "\n", total_size); return 0; } static int HandleGetAvailableSize(nvram_device_t* device, char* args[]) { (void)args; uint64_t available_size = 0; nvram_result_t result = device->get_available_size_in_bytes(device, &available_size); if (result != NV_RESULT_SUCCESS) { return result; } printf("%" PRIu64 "\n", available_size); return 0; } static int HandleGetMaxSpaceSize(nvram_device_t* device, char* args[]) { (void)args; uint64_t max_space_size = 0; nvram_result_t result = device->get_max_space_size_in_bytes(device, &max_space_size); if (result != NV_RESULT_SUCCESS) { return result; } printf("%" PRIu64 "\n", max_space_size); return 0; } static int HandleGetMaxSpaces(nvram_device_t* device, char* args[]) { (void)args; uint32_t max_spaces = 0; nvram_result_t result = device->get_max_spaces(device, &max_spaces); if (result != NV_RESULT_SUCCESS) { return result; } printf("%" PRIu32 "\n", max_spaces); return 0; } static int HandleGetSpaceList(nvram_device_t* device, char* args[]) { (void)args; uint32_t list_size = 0; nvram_result_t result = device->get_space_list(device, 0, NULL, &list_size); if (result != NV_RESULT_SUCCESS) { return result; } uint32_t* space_index_list = calloc(list_size, sizeof(uint32_t)); if (!space_index_list) { return kStatusAllocationFailure; } result = device->get_space_list(device, list_size, space_index_list, &list_size); if (result != NV_RESULT_SUCCESS) { free(space_index_list); return result; } for (uint32_t i = 0; i < list_size; ++i) { if (i != 0) { fputs(",", stdout); } printf("%" PRIu32, space_index_list[i]); } fputs("\n", stdout); free(space_index_list); return 0; } static int HandleGetSpaceSize(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); uint64_t space_size = 0; nvram_result_t result = device->get_space_size(device, index, &space_size); if (result != NV_RESULT_SUCCESS) { return result; } printf("%" PRIu64 "\n", space_size); return 0; } static int HandleGetSpaceControls(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); uint32_t list_size = 0; nvram_result_t result = device->get_space_controls(device, index, 0, NULL, &list_size); if (result != NV_RESULT_SUCCESS) { return result; } uint32_t* controls_list = calloc(list_size, sizeof(nvram_control_t)); if (!controls_list) { return kStatusAllocationFailure; } result = device->get_space_controls(device, index, list_size, controls_list, &list_size); if (result != NV_RESULT_SUCCESS) { free(controls_list); return result; } for (uint32_t i = 0; i < list_size; ++i) { if (i != 0) { fputs(",", stdout); } const char* name = ControlToString(controls_list[i]); if (name) { fputs(name, stdout); } else { printf("<unknown_control_%" PRIu32 ">", controls_list[i]); } } fputs("", stdout); free(controls_list); return 0; } static int HandleIsSpaceReadLocked(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); int read_locked = 0; int write_locked = 0; nvram_result_t result = device->is_space_locked(device, index, &read_locked, &write_locked); if (result != NV_RESULT_SUCCESS) { return result; } printf("%d\n", read_locked); return 0; } static int HandleIsSpaceWriteLocked(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); int read_locked = 0; int write_locked = 0; nvram_result_t result = device->is_space_locked(device, index, &read_locked, &write_locked); if (result != NV_RESULT_SUCCESS) { return result; } printf("%d\n", write_locked); return 0; } static int HandleCreateSpace(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); uint64_t size = strtoull(args[1], NULL, 0); uint32_t list_size = 0; nvram_control_t* controls_list = NULL; char* tail = args[2]; while (tail) { ++list_size; nvram_control_t* new_controls_list = realloc(controls_list, sizeof(nvram_control_t) * list_size); if (new_controls_list) { controls_list = new_controls_list; } else { free(controls_list); return kStatusAllocationFailure; } if (StringToControl(strsep(&tail, ","), &(controls_list[list_size - 1]))) { free(controls_list); return kStatusInvalidArg; } } return device->create_space(device, index, size, controls_list, list_size, (uint8_t*)args[3], strlen(args[3])); } static int HandleDeleteSpace(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); return device->delete_space(device, index, (uint8_t*)args[3], strlen(args[3])); } static int HandleDisableCreate(nvram_device_t* device, char* args[]) { (void)args; return device->disable_create(device); } static int HandleWriteSpace(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); return device->write_space(device, index, (uint8_t*)args[1], strlen(args[1]), (uint8_t*)args[2], strlen(args[2])); } static int HandleReadSpace(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); uint64_t size = 0; nvram_result_t result = device->get_space_size(device, index, &size); if (result != NV_RESULT_SUCCESS) { return result; } uint8_t* buffer = calloc(sizeof(uint8_t), size); if (!buffer) { return kStatusAllocationFailure; } result = device->read_space(device, index, size, (uint8_t*)args[1], strlen(args[1]), buffer, &size); if (result != NV_RESULT_SUCCESS) { free(buffer); return result; } fwrite(buffer, sizeof(uint8_t), size, stdout); fputs("\n", stdout); free(buffer); return 0; } static int HandleEnableWriteLock(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); return device->enable_write_lock(device, index, (uint8_t*)args[1], strlen(args[1])); } static int HandleEnableReadLock(nvram_device_t* device, char* args[]) { uint32_t index = strtoul(args[0], NULL, 0); return device->enable_read_lock(device, index, (uint8_t*)args[1], strlen(args[1])); } struct CommandHandler { const char* name; const char* params_desc; int nparams; int (*run)(nvram_device_t*, char* args[]); }; struct CommandHandler kCommandHandlers[] = { {"get_total_size", "", 0, &HandleGetTotalSize}, {"get_available_size", "", 0, &HandleGetAvailableSize}, {"get_max_space_size", "", 0, &HandleGetMaxSpaceSize}, {"get_max_spaces", "", 0, &HandleGetMaxSpaces}, {"get_space_list", "", 0, &HandleGetSpaceList}, {"get_space_size", "<index>", 1, &HandleGetSpaceSize}, {"get_space_controls", "<index>", 1, &HandleGetSpaceControls}, {"is_space_read_locked", "<index>", 1, &HandleIsSpaceReadLocked}, {"is_space_write_locked", "<index>", 1, &HandleIsSpaceWriteLocked}, {"create_space", "<index> <size> <controls> <auth>", 4, &HandleCreateSpace}, {"delete_space", "<index> <auth>", 2, &HandleDeleteSpace}, {"disable_create", "", 0, &HandleDisableCreate}, {"write_space", "<index> <data> <auth>", 3, &HandleWriteSpace}, {"read_space", "<index> <auth>", 2, &HandleReadSpace}, {"enable_write_lock", "<index> <auth>", 2, &HandleEnableWriteLock}, {"enable_read_lock", "<index> <auth>", 2, &HandleEnableReadLock}, }; int main(int argc, char* argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s <command> <command-args>\n", argv[0]); fprintf(stderr, "Valid commands are:\n"); for (size_t i = 0; i < countof(kCommandHandlers); ++i) { fprintf(stderr, " %s %s\n", kCommandHandlers[i].name, kCommandHandlers[i].params_desc); } return kStatusInvalidArg; } const struct CommandHandler* cmd = NULL; for (size_t i = 0; i < countof(kCommandHandlers); ++i) { if (strcmp(kCommandHandlers[i].name, argv[1]) == 0) { cmd = &kCommandHandlers[i]; } } if (!cmd) { fprintf(stderr, "Bad command: %s\n", argv[1]); return kStatusInvalidArg; } if (argc - 2 != cmd->nparams) { fprintf(stderr, "Command %s takes %d parameters, %d given.\n", argv[1], cmd->nparams, argc - 2); return kStatusInvalidArg; } const hw_module_t* module = NULL; nvram_device_t* nvram_device = NULL; if (hw_get_module(NVRAM_HARDWARE_MODULE_ID, &module) != 0 || module->methods->open(module, NVRAM_HARDWARE_DEVICE_ID, (hw_device_t**)&nvram_device) != 0) { fprintf(stderr, "Failed to open NVRAM HAL.\n"); return kStatusHALError; } if (nvram_device->common.version != NVRAM_DEVICE_API_VERSION_1_1) { fprintf(stderr, "Unsupported NVRAM HAL version.\n"); nvram_device->common.close(&nvram_device->common); return kStatusHALError; } int ret = cmd->run(nvram_device, argv + 2); if (ret != 0) { fprintf(stderr, "Command execution failure: %s (%d).\n", StatusToString(ret), ret); } nvram_device->common.close(&nvram_device->common); return ret; }