Home | History | Annotate | Download | only in client
      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