1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <inttypes.h> 18 #include <stdint.h> 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <string.h> 22 23 #include <hardware/nvram.h> 24 25 #define countof(array) (sizeof(array) / sizeof((array)[0])) 26 27 // Exit status codes. These are all negative as the positive ones are used for 28 // the NV_RESULT_ codes. 29 enum StatusCode { 30 kStatusInvalidArg = -1, 31 kStatusHALError = -2, 32 kStatusAllocationFailure = -3, 33 }; 34 35 static struct { 36 int status; 37 const char* description; 38 } kStatusStringTable[] = { 39 {kStatusInvalidArg, "Bad parameter"}, 40 {kStatusHALError, "NVRAM HAL initialization error"}, 41 {kStatusAllocationFailure, "Memory allocation error"}, 42 {NV_RESULT_SUCCESS, "Success"}, 43 {NV_RESULT_INTERNAL_ERROR, "Internal error"}, 44 {NV_RESULT_ACCESS_DENIED, "Access denied"}, 45 {NV_RESULT_INVALID_PARAMETER, "Invalid NVRAM parameter"}, 46 {NV_RESULT_SPACE_DOES_NOT_EXIST, "Space does not exist"}, 47 {NV_RESULT_SPACE_ALREADY_EXISTS, "Space already exists"}, 48 {NV_RESULT_OPERATION_DISABLED, "Operation disabled"}, 49 }; 50 51 // Returns a string describing |status|. 52 static const char* StatusToString(int status) { 53 for (size_t i = 0; i < countof(kStatusStringTable); ++i) { 54 if (kStatusStringTable[i].status == status) { 55 return kStatusStringTable[i].description; 56 } 57 } 58 59 return "unknown error"; 60 } 61 62 // A table mapping control values to names. 63 static struct { 64 nvram_control_t control; 65 const char* name; 66 } kControlNameTable[] = { 67 {NV_CONTROL_PERSISTENT_WRITE_LOCK, "PERSISTENT_WRITE_LOCK"}, 68 {NV_CONTROL_BOOT_WRITE_LOCK, "BOOT_WRITE_LOCK"}, 69 {NV_CONTROL_BOOT_READ_LOCK, "BOOT_READ_LOCK"}, 70 {NV_CONTROL_WRITE_AUTHORIZATION, "WRITE_AUTHORIZATION"}, 71 {NV_CONTROL_READ_AUTHORIZATION, "READ_AUTHORIZATION"}, 72 {NV_CONTROL_WRITE_EXTEND, "WRITE_EXTEND"}, 73 }; 74 75 // Returns the string representation of |control|, or NULL if |control| isn't a 76 // valid control value. 77 static const char* ControlToString(nvram_control_t control) { 78 for (size_t i = 0; i < countof(kControlNameTable); ++i) { 79 if (kControlNameTable[i].control == control) { 80 return kControlNameTable[i].name; 81 } 82 } 83 84 return NULL; 85 } 86 87 // Sets |control| to the NV_CONTROL_ value corresponding to the string control 88 // representation found in |name|. Returns 0 if successful, 1 if name doesn't 89 // match any control string. 90 static int StringToControl(const char* name, nvram_control_t* control) { 91 for (size_t i = 0; i < countof(kControlNameTable); ++i) { 92 if (strcmp(kControlNameTable[i].name, name) == 0) { 93 *control = kControlNameTable[i].control; 94 return 0; 95 } 96 } 97 98 return 1; 99 } 100 101 static int HandleGetTotalSize(nvram_device_t* device, char* args[]) { 102 (void)args; 103 uint64_t total_size = 0; 104 nvram_result_t result = device->get_total_size_in_bytes(device, &total_size); 105 if (result != NV_RESULT_SUCCESS) { 106 return result; 107 } 108 109 printf("%" PRIu64 "\n", total_size); 110 return 0; 111 } 112 113 static int HandleGetAvailableSize(nvram_device_t* device, char* args[]) { 114 (void)args; 115 uint64_t available_size = 0; 116 nvram_result_t result = 117 device->get_available_size_in_bytes(device, &available_size); 118 if (result != NV_RESULT_SUCCESS) { 119 return result; 120 } 121 122 printf("%" PRIu64 "\n", available_size); 123 return 0; 124 } 125 126 static int HandleGetMaxSpaceSize(nvram_device_t* device, char* args[]) { 127 (void)args; 128 uint64_t max_space_size = 0; 129 nvram_result_t result = 130 device->get_max_space_size_in_bytes(device, &max_space_size); 131 if (result != NV_RESULT_SUCCESS) { 132 return result; 133 } 134 135 printf("%" PRIu64 "\n", max_space_size); 136 return 0; 137 } 138 139 static int HandleGetMaxSpaces(nvram_device_t* device, char* args[]) { 140 (void)args; 141 uint32_t max_spaces = 0; 142 nvram_result_t result = device->get_max_spaces(device, &max_spaces); 143 if (result != NV_RESULT_SUCCESS) { 144 return result; 145 } 146 147 printf("%" PRIu32 "\n", max_spaces); 148 return 0; 149 } 150 151 static int HandleGetSpaceList(nvram_device_t* device, char* args[]) { 152 (void)args; 153 uint32_t list_size = 0; 154 nvram_result_t result = device->get_space_list(device, 0, NULL, &list_size); 155 if (result != NV_RESULT_SUCCESS) { 156 return result; 157 } 158 159 uint32_t* space_index_list = calloc(list_size, sizeof(uint32_t)); 160 if (!space_index_list) { 161 return kStatusAllocationFailure; 162 } 163 164 result = 165 device->get_space_list(device, list_size, space_index_list, &list_size); 166 if (result != NV_RESULT_SUCCESS) { 167 free(space_index_list); 168 return result; 169 } 170 171 for (uint32_t i = 0; i < list_size; ++i) { 172 if (i != 0) { 173 fputs(",", stdout); 174 } 175 printf("%" PRIu32, space_index_list[i]); 176 } 177 fputs("\n", stdout); 178 179 free(space_index_list); 180 return 0; 181 } 182 183 static int HandleGetSpaceSize(nvram_device_t* device, char* args[]) { 184 uint32_t index = strtoul(args[0], NULL, 0); 185 uint64_t space_size = 0; 186 nvram_result_t result = device->get_space_size(device, index, &space_size); 187 if (result != NV_RESULT_SUCCESS) { 188 return result; 189 } 190 191 printf("%" PRIu64 "\n", space_size); 192 return 0; 193 } 194 195 static int HandleGetSpaceControls(nvram_device_t* device, char* args[]) { 196 uint32_t index = strtoul(args[0], NULL, 0); 197 uint32_t list_size = 0; 198 nvram_result_t result = 199 device->get_space_controls(device, index, 0, NULL, &list_size); 200 if (result != NV_RESULT_SUCCESS) { 201 return result; 202 } 203 204 uint32_t* controls_list = calloc(list_size, sizeof(nvram_control_t)); 205 if (!controls_list) { 206 return kStatusAllocationFailure; 207 } 208 209 result = device->get_space_controls(device, index, list_size, controls_list, 210 &list_size); 211 if (result != NV_RESULT_SUCCESS) { 212 free(controls_list); 213 return result; 214 } 215 216 for (uint32_t i = 0; i < list_size; ++i) { 217 if (i != 0) { 218 fputs(",", stdout); 219 } 220 const char* name = ControlToString(controls_list[i]); 221 if (name) { 222 fputs(name, stdout); 223 } else { 224 printf("<unknown_control_%" PRIu32 ">", controls_list[i]); 225 } 226 } 227 fputs("", stdout); 228 229 free(controls_list); 230 return 0; 231 } 232 233 static int HandleIsSpaceReadLocked(nvram_device_t* device, char* args[]) { 234 uint32_t index = strtoul(args[0], NULL, 0); 235 int read_locked = 0; 236 int write_locked = 0; 237 nvram_result_t result = 238 device->is_space_locked(device, index, &read_locked, &write_locked); 239 if (result != NV_RESULT_SUCCESS) { 240 return result; 241 } 242 243 printf("%d\n", read_locked); 244 return 0; 245 } 246 247 static int HandleIsSpaceWriteLocked(nvram_device_t* device, char* args[]) { 248 uint32_t index = strtoul(args[0], NULL, 0); 249 int read_locked = 0; 250 int write_locked = 0; 251 nvram_result_t result = 252 device->is_space_locked(device, index, &read_locked, &write_locked); 253 if (result != NV_RESULT_SUCCESS) { 254 return result; 255 } 256 257 printf("%d\n", write_locked); 258 return 0; 259 } 260 261 static int HandleCreateSpace(nvram_device_t* device, char* args[]) { 262 uint32_t index = strtoul(args[0], NULL, 0); 263 uint64_t size = strtoull(args[1], NULL, 0); 264 uint32_t list_size = 0; 265 nvram_control_t* controls_list = NULL; 266 char* tail = args[2]; 267 while (tail) { 268 ++list_size; 269 nvram_control_t* new_controls_list = 270 realloc(controls_list, sizeof(nvram_control_t) * list_size); 271 if (new_controls_list) { 272 controls_list = new_controls_list; 273 } else { 274 free(controls_list); 275 return kStatusAllocationFailure; 276 } 277 278 if (StringToControl(strsep(&tail, ","), &(controls_list[list_size - 1]))) { 279 free(controls_list); 280 return kStatusInvalidArg; 281 } 282 } 283 284 return device->create_space(device, index, size, controls_list, list_size, 285 (uint8_t*)args[3], strlen(args[3])); 286 } 287 288 static int HandleDeleteSpace(nvram_device_t* device, char* args[]) { 289 uint32_t index = strtoul(args[0], NULL, 0); 290 return device->delete_space(device, index, (uint8_t*)args[3], 291 strlen(args[3])); 292 } 293 294 static int HandleDisableCreate(nvram_device_t* device, char* args[]) { 295 (void)args; 296 return device->disable_create(device); 297 } 298 299 static int HandleWriteSpace(nvram_device_t* device, char* args[]) { 300 uint32_t index = strtoul(args[0], NULL, 0); 301 return device->write_space(device, index, (uint8_t*)args[1], strlen(args[1]), 302 (uint8_t*)args[2], strlen(args[2])); 303 } 304 305 static int HandleReadSpace(nvram_device_t* device, char* args[]) { 306 uint32_t index = strtoul(args[0], NULL, 0); 307 uint64_t size = 0; 308 nvram_result_t result = device->get_space_size(device, index, &size); 309 if (result != NV_RESULT_SUCCESS) { 310 return result; 311 } 312 313 uint8_t* buffer = calloc(sizeof(uint8_t), size); 314 if (!buffer) { 315 return kStatusAllocationFailure; 316 } 317 318 result = device->read_space(device, index, size, (uint8_t*)args[1], 319 strlen(args[1]), buffer, &size); 320 if (result != NV_RESULT_SUCCESS) { 321 free(buffer); 322 return result; 323 } 324 325 fwrite(buffer, sizeof(uint8_t), size, stdout); 326 fputs("\n", stdout); 327 free(buffer); 328 return 0; 329 } 330 331 static int HandleEnableWriteLock(nvram_device_t* device, char* args[]) { 332 uint32_t index = strtoul(args[0], NULL, 0); 333 return device->enable_write_lock(device, index, (uint8_t*)args[1], 334 strlen(args[1])); 335 } 336 337 static int HandleEnableReadLock(nvram_device_t* device, char* args[]) { 338 uint32_t index = strtoul(args[0], NULL, 0); 339 return device->enable_read_lock(device, index, (uint8_t*)args[1], 340 strlen(args[1])); 341 } 342 343 struct CommandHandler { 344 const char* name; 345 const char* params_desc; 346 int nparams; 347 int (*run)(nvram_device_t*, char* args[]); 348 }; 349 350 struct CommandHandler kCommandHandlers[] = { 351 {"get_total_size", "", 0, &HandleGetTotalSize}, 352 {"get_available_size", "", 0, &HandleGetAvailableSize}, 353 {"get_max_space_size", "", 0, &HandleGetMaxSpaceSize}, 354 {"get_max_spaces", "", 0, &HandleGetMaxSpaces}, 355 {"get_space_list", "", 0, &HandleGetSpaceList}, 356 {"get_space_size", "<index>", 1, &HandleGetSpaceSize}, 357 {"get_space_controls", "<index>", 1, &HandleGetSpaceControls}, 358 {"is_space_read_locked", "<index>", 1, &HandleIsSpaceReadLocked}, 359 {"is_space_write_locked", "<index>", 1, &HandleIsSpaceWriteLocked}, 360 {"create_space", "<index> <size> <controls> <auth>", 4, &HandleCreateSpace}, 361 {"delete_space", "<index> <auth>", 2, &HandleDeleteSpace}, 362 {"disable_create", "", 0, &HandleDisableCreate}, 363 {"write_space", "<index> <data> <auth>", 3, &HandleWriteSpace}, 364 {"read_space", "<index> <auth>", 2, &HandleReadSpace}, 365 {"enable_write_lock", "<index> <auth>", 2, &HandleEnableWriteLock}, 366 {"enable_read_lock", "<index> <auth>", 2, &HandleEnableReadLock}, 367 }; 368 369 int main(int argc, char* argv[]) { 370 if (argc < 2) { 371 fprintf(stderr, "Usage: %s <command> <command-args>\n", argv[0]); 372 fprintf(stderr, "Valid commands are:\n"); 373 for (size_t i = 0; i < countof(kCommandHandlers); ++i) { 374 fprintf(stderr, " %s %s\n", kCommandHandlers[i].name, 375 kCommandHandlers[i].params_desc); 376 } 377 return kStatusInvalidArg; 378 } 379 380 const struct CommandHandler* cmd = NULL; 381 for (size_t i = 0; i < countof(kCommandHandlers); ++i) { 382 if (strcmp(kCommandHandlers[i].name, argv[1]) == 0) { 383 cmd = &kCommandHandlers[i]; 384 } 385 } 386 387 if (!cmd) { 388 fprintf(stderr, "Bad command: %s\n", argv[1]); 389 return kStatusInvalidArg; 390 } 391 392 if (argc - 2 != cmd->nparams) { 393 fprintf(stderr, "Command %s takes %d parameters, %d given.\n", argv[1], 394 cmd->nparams, argc - 2); 395 return kStatusInvalidArg; 396 } 397 398 const hw_module_t* module = NULL; 399 nvram_device_t* nvram_device = NULL; 400 if (hw_get_module(NVRAM_HARDWARE_MODULE_ID, &module) != 0 || 401 module->methods->open(module, NVRAM_HARDWARE_DEVICE_ID, 402 (hw_device_t**)&nvram_device) != 0) { 403 fprintf(stderr, "Failed to open NVRAM HAL.\n"); 404 return kStatusHALError; 405 } 406 407 if (nvram_device->common.version != NVRAM_DEVICE_API_VERSION_1_1) { 408 fprintf(stderr, "Unsupported NVRAM HAL version.\n"); 409 nvram_device->common.close(&nvram_device->common); 410 return kStatusHALError; 411 } 412 413 int ret = cmd->run(nvram_device, argv + 2); 414 if (ret != 0) { 415 fprintf(stderr, "Command execution failure: %s (%d).\n", 416 StatusToString(ret), ret); 417 } 418 419 nvram_device->common.close(&nvram_device->common); 420 return ret; 421 } 422