Merge "platform: Added ability to add/remove hnvram vars"
diff --git a/hnvram/hnvram_main.c b/hnvram/hnvram_main.c
index 323d62e..eb0f306 100644
--- a/hnvram/hnvram_main.c
+++ b/hnvram/hnvram_main.c
@@ -1,7 +1,10 @@
// Copyright 2011 Google Inc. All Rights Reserved.
// Author: dgentry@google.com (Denny Gentry)
+#ifndef _GNU_SOURCE
#define _GNU_SOURCE
+#endif
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -16,23 +19,28 @@
// Number of bytes of GPN to be represented as hex data
#define GPN_HEX_BYTES 4
+// Holds whether -w can create new variables in NVRAM. Set with -n
+int can_add_flag = 0;
+
/* To avoid modifying the HMX code, we supply dummy versions of two
* missing routines to satisfy the linker. These are used when writing
* the complete NVRAM partiton, which we do not need in this utility. */
DRV_Error DRV_NANDFLASH_GetNvramHandle(int handle) {
return DRV_ERR;
}
-DRV_Error DRV_FLASH_Write(int offset, char *data, int nDataSize) {
+DRV_Error DRV_FLASH_Write(int offset, char* data, int nDataSize) {
return DRV_ERR;
}
void usage(const char* progname) {
- printf("Usage: %s [-d | [-q|-b] -r VARNAME] [-w VARNAME=value]\n", progname);
+ printf("Usage: %s [-d | [-q|-b] [-r|-k] VARNAME] [ [-n] -w VARNAME=value]\n", progname);
printf("\t-d : dump all NVRAM variables\n");
printf("\t-r VARNAME : read VARNAME from NVRAM\n");
printf("\t-q : quiet mode, suppress the variable name and equal sign\n");
printf("\t-b : read VARNAME from NVRAM in raw binary format, e.g. dumping a binary key\n");
printf("\t-w VARNAME=value : write value to VARNAME in NVRAM.\n");
+ printf("\t-n : toggles whether -w can create new variables. Default is off\n");
+ printf("\t-k VARNAME : delete existing key/value pair from NVRAM.\n");
}
// Format of data in the NVRAM
@@ -104,28 +112,25 @@
// ------------------ READ NVRAM -----------------------------
-void format_string(const char* data, char* output, int outlen) {
+void format_string(const unsigned char* data, char* output, int outlen) {
snprintf(output, outlen, "%s", data);
}
-void format_mac(const char* data, char* output, int outlen) {
- const unsigned char* mac = (const unsigned char*) data;
+void format_mac(const unsigned char* data, char* output, int outlen) {
snprintf(output, outlen, "%02hx:%02hx:%02hx:%02hx:%02hx:%02hx",
- mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+ data[0], data[1], data[2], data[3], data[4], data[5]);
}
-void format_hmxswvers(const char* data, char* output, int outlen) {
- const unsigned char* udata = (const unsigned char*) data;
- snprintf(output, outlen, "%hhu.%hhu", udata[1], udata[0]);
+void format_hmxswvers(const unsigned char* data, char* output, int outlen) {
+ snprintf(output, outlen, "%hhu.%hhu", data[1], data[0]);
}
-void format_uint8(const char* data, char* output, int outlen) {
- const unsigned char* d = (const unsigned char*)data;
- snprintf(output, outlen, "%u", d[0]);
+void format_uint8(const unsigned char* data, char* output, int outlen) {
+ snprintf(output, outlen, "%u", data[0]);
}
-void format_hexstring(const char* data, int datalen, char* output, int outlen) {
- const unsigned char* d = (const unsigned char*)data;
+void format_hexstring(const unsigned char* data, int datalen, char* output,
+ int outlen) {
int i;
if (outlen < (datalen * 2 + 1)) {
fprintf(stderr, "%s buffer too small %d < %d",
@@ -133,11 +138,11 @@
exit(1);
}
for (i = 0; i < datalen; ++i) {
- snprintf(output + (i * 2), 3, "%02x", d[i]);
+ snprintf(output + (i * 2), 3, "%02x", data[i]);
}
}
-void format_gpn(const char* data, const int data_len, char* output,
+void format_gpn(const unsigned char* data, const int data_len, char* output,
int outlen) {
// Format first 4 bytes as 8 digit hex.
if (data_len == GPN_HEX_BYTES)
@@ -146,7 +151,7 @@
format_string(data, output, outlen);
}
-char* format_nvram(hnvram_format_e format, const char* data,
+char* format_nvram(hnvram_format_e format, const unsigned char* data,
const int data_len, char* output, int outlen) {
output[0] = '\0';
switch(format) {
@@ -163,7 +168,7 @@
int read_raw_nvram(const char* name, char* output, int outlen) {
const hnvram_field_t* field = get_nvram_field(name);
- int ret;
+ unsigned int ret;
if (field == NULL) {
return -1;
}
@@ -180,23 +185,33 @@
return -1;
}
- return ret;
+ return (int)ret;
}
char* read_nvram(const char* name, char* output, int outlen, int quiet) {
const hnvram_field_t* field = get_nvram_field(name);
- if (field == NULL) {
- return NULL;
- }
+ int is_field = (field != NULL);
- char data[NVRAM_MAX_DATA] = {0};
- int data_len = 0;
- if (HMX_NVRAM_GetField(field->nvram_type, 0, data, sizeof(data)) != DRV_OK ||
- HMX_NVRAM_GetLength(field->nvram_type, &data_len) != DRV_OK) {
- return NULL;
+ unsigned char data[NVRAM_MAX_DATA] = {0};
+ unsigned int data_len = 0;
+ hnvram_format_e format_type;
+ if (is_field) {
+ format_type = field->format;
+ if (HMX_NVRAM_GetField(field->nvram_type, 0, data, sizeof(data)) != DRV_OK ||
+ HMX_NVRAM_GetLength(field->nvram_type, &data_len) != DRV_OK) {
+ return NULL;
+ }
+ } else {
+ format_type = HNVRAM_STRING;
+ DRV_Error e = HMX_NVRAM_Read(HMX_NVRAM_PARTITION_RW, (unsigned char*)name,
+ 0, data, sizeof(data), &data_len);
+ if (e != DRV_OK) {
+ return NULL;
+ }
}
char formatbuf[NVRAM_MAX_DATA * 2];
- char* nv = format_nvram(field->format, data, data_len, formatbuf, sizeof(formatbuf));
+ char* nv = format_nvram(format_type, data, data_len, formatbuf,
+ sizeof(formatbuf));
if (quiet) {
snprintf(output, outlen, "%s", nv);
} else {
@@ -204,13 +219,11 @@
}
return output;
}
-
-
// ----------------- WRITE NVRAM -----------------------------
unsigned char* parse_string(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
int len = strlen(input);
if (len > *outlen) {
len = *outlen;
@@ -222,7 +235,7 @@
}
unsigned char* parse_mac(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
if (*outlen < 6) return NULL;
if (sscanf(input, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
@@ -235,7 +248,7 @@
}
unsigned char* parse_hmxswvers(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
if (*outlen < 2) return NULL;
if (sscanf(input, "%hhd.%hhd", &output[1], &output[0]) != 2) {
@@ -246,7 +259,7 @@
}
unsigned char* parse_uint8(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
if (*outlen < 1) return NULL;
output[0] = input[0] - '0';
@@ -264,8 +277,8 @@
}
unsigned char* parse_hexstring(const char* input,
- unsigned char* output, int* outlen) {
- int i, len = strlen(input) / 2;
+ unsigned char* output, unsigned int* outlen) {
+ unsigned int i, len = strlen(input) / 2;
if (*outlen < len) {
len = *outlen;
}
@@ -294,7 +307,7 @@
}
unsigned char* parse_gpn(const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
if (*outlen < 4) return NULL;
// Old GPN format: 8-digit hex string
@@ -312,7 +325,7 @@
}
unsigned char* parse_nvram(hnvram_format_e format, const char* input,
- unsigned char* output, int* outlen) {
+ unsigned char* output, unsigned int* outlen) {
output[0] = '\0';
switch(format) {
case HNVRAM_STRING:
@@ -337,6 +350,15 @@
return NULL;
}
+DRV_Error clear_nvram(char* optarg) {
+ DRV_Error e = HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_RW,
+ (unsigned char*)optarg);
+ if (e == DRV_ERR) {
+ // Avoid throwing error message if variable already cleared
+ return DRV_OK;
+ }
+ return e;
+}
int write_nvram(char* optarg) {
char* equal = strchr(optarg, '=');
@@ -349,25 +371,45 @@
char* value = ++equal;
const hnvram_field_t* field = get_nvram_field(name);
- if (field == NULL) {
- return -2;
+ int is_field = (field != NULL);
+
+ hnvram_format_e format_type;
+ if (is_field) {
+ format_type = field->format;
+ } else {
+ format_type = HNVRAM_STRING;
}
unsigned char nvram_value[NVRAM_MAX_DATA];
- int nvram_len = sizeof(nvram_value);
- if (parse_nvram(field->format, value, nvram_value, &nvram_len) == NULL) {
- return -3;
+ unsigned int nvram_len = sizeof(nvram_value);
+ if (parse_nvram(format_type, value, nvram_value, &nvram_len) == NULL) {
+ return -2;
}
- if (HMX_NVRAM_SetField(field->nvram_type, 0,
- nvram_value, nvram_len) != DRV_OK) {
- return -4;
+ if (!is_field) {
+ char tmp[NVRAM_MAX_DATA] = {0};
+ int key_exists = (read_nvram(name, tmp, NVRAM_MAX_DATA, 1) != NULL);
+ if (!can_add_flag && !key_exists) {
+ fprintf(stderr, "Key not found in NVRAM. Add -n to allow creation %s\n",
+ name);
+ return -3;
+ }
+ DRV_Error er = HMX_NVRAM_Write(HMX_NVRAM_PARTITION_RW, (unsigned char*)name,
+ 0, nvram_value, nvram_len);
+ if (er != DRV_OK) {
+ return -4;
+ }
+ } else {
+ if (HMX_NVRAM_SetField(field->nvram_type, 0,
+ nvram_value, nvram_len) != DRV_OK) {
+ return -5;
+ }
}
return 0;
}
-int hnvram_main(int argc, char * const argv[]) {
+int hnvram_main(int argc, char* const argv[]) {
DRV_Error err;
libupgrade_verbose = 0;
@@ -383,7 +425,7 @@
int b_flag = 0; // binary: output the binary format
char output[NVRAM_MAX_DATA];
int c;
- while ((c = getopt(argc, argv, "dbqrw:")) != -1) {
+ while ((c = getopt(argc, argv, "dbqrnw:k:")) != -1) {
switch(c) {
case 'b':
b_flag = 1;
@@ -391,6 +433,9 @@
case 'q':
q_flag = 1;
break;
+ case 'n':
+ can_add_flag = 1;
+ break;
case 'w':
{
char* duparg = strdup(optarg);
@@ -402,6 +447,17 @@
free(duparg);
}
break;
+ case 'k':
+ {
+ char* duparg = strdup(optarg);
+ if (clear_nvram(duparg) != DRV_OK) {
+ fprintf(stderr, "Unable to remove key %s\n", duparg);
+ free(duparg);
+ exit(1);
+ }
+ free(duparg);
+ }
+ break;
case 'r':
case 'd':
if (op != c) {
@@ -459,7 +515,7 @@
}
#ifndef TEST_MAIN
-int main(int argc, char * const argv[]) {
+int main(int argc, char* const argv[]) {
return hnvram_main(argc, argv);
}
#endif // TEST_MAIN
diff --git a/hnvram/hnvram_test.cc b/hnvram/hnvram_test.cc
index d10a7a1..39f7e4a 100644
--- a/hnvram/hnvram_test.cc
+++ b/hnvram/hnvram_test.cc
@@ -8,9 +8,40 @@
int libupgrade_verbose = 1;
+char* HMX_NVRAM_Read_Data = NULL;
+DRV_Error HMX_NVRAM_Read(HMX_NVRAM_PARTITION_E partition,
+ unsigned char* pName, unsigned int offset,
+ unsigned char* pValue, unsigned int ulSize,
+ unsigned int* pLen) {
+ if (HMX_NVRAM_Read_Data == NULL) {
+ return DRV_ERR;
+ } else {
+ snprintf((char*)pValue, ulSize, "%s", HMX_NVRAM_Read_Data);
+ *pLen = strlen(HMX_NVRAM_Read_Data);
+ return DRV_OK;
+ }
+}
+
+DRV_Error HMX_NVRAM_Write(HMX_NVRAM_PARTITION_E partition,
+ unsigned char* pName, unsigned int offset,
+ unsigned char* pValue, unsigned int ulSize) {
+ HMX_NVRAM_Read_Data = (char*)malloc(ulSize);
+ snprintf(HMX_NVRAM_Read_Data, sizeof(pValue), "%s", (char*)pValue);
+ return DRV_OK;
+}
+
+DRV_Error HMX_NVRAM_Remove(HMX_NVRAM_PARTITION_E partition,
+ unsigned char* pName) {
+ if (HMX_NVRAM_Read_Data == NULL) {
+ return DRV_ERR;
+ }
+ HMX_NVRAM_Read_Data = NULL;
+ return DRV_OK;
+}
+
const char* HMX_NVRAM_GetField_Data = NULL;
DRV_Error HMX_NVRAM_GetField(NVRAM_FIELD_T field, unsigned int offset,
- void *data, int nDataSize) {
+ void* data, int nDataSize) {
if (HMX_NVRAM_GetField_Data == NULL) {
return DRV_ERR;
} else {
@@ -23,7 +54,7 @@
int HMX_NVRAM_SetField_Len = -1;
DRV_Error HMX_NVRAM_SetField_Return = DRV_OK;
DRV_Error HMX_NVRAM_SetField(NVRAM_FIELD_T field, unsigned int offset,
- void *data, int nDataSize) {
+ void* data, int nDataSize) {
HMX_NVRAM_SetField_Data = (unsigned char*)malloc(nDataSize);
memcpy(HMX_NVRAM_SetField_Data, data, nDataSize);
HMX_NVRAM_SetField_Len = nDataSize;
@@ -38,12 +69,11 @@
return DRV_OK;
}
-DRV_Error HMX_NVRAM_GetLength(tagNVRAM_FIELD partition, int *pLen) {
+DRV_Error HMX_NVRAM_GetLength(tagNVRAM_FIELD partition, unsigned int* pLen) {
*pLen = HMX_NVRAM_SetField_Len;
return DRV_OK;
}
-
#define TEST_MAIN
#include "hnvram_main.c"
@@ -54,6 +84,7 @@
virtual ~HnvramTest() {}
virtual void SetUp() {
+ HMX_NVRAM_Read_Data = NULL;
HMX_NVRAM_GetField_Data = NULL;
HMX_NVRAM_SetField_Data = NULL;
HMX_NVRAM_SetField_Len = -1;
@@ -70,49 +101,39 @@
TEST_F(HnvramTest, TestFormat) {
char out[256];
- EXPECT_STREQ("foo", format_nvram(HNVRAM_STRING, "foo", 3, out, sizeof(out)));
- EXPECT_STREQ("bar", format_nvram(HNVRAM_STRING, "bar", 3, out, sizeof(out)));
+ EXPECT_STREQ("foo", format_nvram(HNVRAM_STRING, (unsigned char*)"foo", 3,
+ out, sizeof(out)));
+ EXPECT_STREQ("bar", format_nvram(HNVRAM_STRING, (unsigned char*)"bar", 3,
+ out, sizeof(out)));
- char mac[6] = {0x11, 0x22, 0x03, 0x40, 0x55, 0xf6};
+ unsigned char mac[6] = {0x11, 0x22, 0x03, 0x40, 0x55, 0xf6};
EXPECT_STREQ("11:22:03:40:55:f6",
format_nvram(HNVRAM_MAC, mac, sizeof(mac), out, sizeof(out)));
- const char in1[1] = {1};
+ const unsigned char in1[1] = {1};
EXPECT_STREQ("1", format_nvram(HNVRAM_UINT8, in1, sizeof(in1),
out, sizeof(out)));
- const char in254[1] = {0xfe};
+ const unsigned char in254[1] = {0xfe};
EXPECT_STREQ("254", format_nvram(HNVRAM_UINT8, in254, sizeof(in254),
out, sizeof(out)));
- const char vers[] = {0x02, 0x01};
+ const unsigned char vers[] = {0x02, 0x01};
EXPECT_STREQ("1.2", format_nvram(HNVRAM_HMXSWVERS, vers, sizeof(vers),
out, sizeof(out)));
- const char gpn[] = {0x86, 0x0, 0x4, 0x0};
+ const unsigned char gpn[] = {0x86, 0x0, 0x4, 0x0};
EXPECT_STREQ("86000400", format_nvram(HNVRAM_GPN, gpn, sizeof(gpn),
out, sizeof(out)));
- const char hex[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
+ const unsigned char hex[] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
EXPECT_STREQ("0123456789abcdef", format_nvram(
HNVRAM_HEXSTRING, hex, sizeof(hex), out, sizeof(out)));
}
-TEST_F(HnvramTest, TestGetNvramField) {
- EXPECT_EQ(NULL, get_nvram_field("nosuchfield"));
- EXPECT_EQ(NVRAM_FIELD_SYSTEM_ID, get_nvram_field("SYSTEM_ID")->nvram_type);
-}
-
-TEST_F(HnvramTest, TestReadNvram) {
- char output[256];
- HMX_NVRAM_GetField_Data = "TestSystemId";
- EXPECT_STREQ("SYSTEM_ID=TestSystemId",
- read_nvram("SYSTEM_ID", output, sizeof(output), 0));
-}
-
TEST_F(HnvramTest, TestParse) {
char input[256];
unsigned char output[256];
- int outlen = sizeof(output);
+ unsigned int outlen = sizeof(output);
snprintf(input, sizeof(input), "This is a test.");
EXPECT_TRUE(NULL != parse_nvram(HNVRAM_STRING, input, output, &outlen));
@@ -156,16 +177,114 @@
EXPECT_EQ(0, memcmp(hex, output, outlen));
}
-TEST_F(HnvramTest, TestWriteNvram) {
+TEST_F(HnvramTest, TestGetNvramField) {
+ EXPECT_EQ(NULL, get_nvram_field("nosuchfield"));
+ EXPECT_EQ(NVRAM_FIELD_SYSTEM_ID, get_nvram_field("SYSTEM_ID")->nvram_type);
+}
+
+TEST_F(HnvramTest, TestReadFieldNvram) {
+ char output[256];
+ HMX_NVRAM_GetField_Data = "TestSystemId";
+ EXPECT_STREQ("SYSTEM_ID=TestSystemId",
+ read_nvram("SYSTEM_ID", output, sizeof(output), 0));
+ EXPECT_STREQ("TestSystemId",
+ read_nvram("SYSTEM_ID", output, sizeof(output), 1));
+ HMX_NVRAM_GetField_Data = NULL;
+ EXPECT_EQ(NULL, read_nvram("FAKE_SYSTEM_ID", output, sizeof(output), 1));
+}
+
+TEST_F(HnvramTest, TestReadVariableNvram) {
+ char output[256];
+ HMX_NVRAM_Read_Data = strdup("ABC123");
+ EXPECT_STREQ("TEST_VARIABLE=ABC123",
+ read_nvram("TEST_VARIABLE", output, sizeof(output), 0));
+ EXPECT_STREQ("ABC123",
+ read_nvram("TEST_VARIABLE", output, sizeof(output), 1));
+ HMX_NVRAM_Read_Data = NULL;
+ EXPECT_STREQ(NULL, read_nvram("TEST_VARIABLE", output, sizeof(output), 1));
+}
+
+TEST_F(HnvramTest, TestWriteFieldNvram) {
+ // Type integer
char* testdata = strdup("ACTIVATED_KERNEL_NUM=1");
EXPECT_EQ(DRV_OK, write_nvram(testdata));
- unsigned char expected[] = {0x01};
- EXPECT_EQ(0, memcmp(HMX_NVRAM_SetField_Data, expected, sizeof(expected)));
+ EXPECT_EQ(0x01, *HMX_NVRAM_SetField_Data);
EXPECT_EQ(1, HMX_NVRAM_SetField_Len);
+
+ // Type string
+ testdata = strdup("ACTIVATED_KERNEL_NAME=kernel1");
+ EXPECT_EQ(DRV_OK, write_nvram(testdata));
+ EXPECT_STREQ("kernel1", (char*)HMX_NVRAM_SetField_Data);
+ EXPECT_EQ(7, HMX_NVRAM_SetField_Len);
+
+ // Make sure it called SetField and not HMX_NVRAM_Write
+ EXPECT_EQ (NULL, HMX_NVRAM_Read_Data);
+
+ // Should fail trying to change value of non-exsting field
+ testdata = strdup("FAKE_FIELD=abc123");
+ EXPECT_NE(0, write_nvram(testdata));
free(testdata);
}
-int main(int argc, char **argv) {
+TEST_F(HnvramTest, TestWriteVariableNvram) {
+ char* key = strdup("TEST_FIELD");
+ char* val = strdup("abc123");
+ char* keyval = strdup("TEST_FIELD=abc123");
+
+ // Fail to add new one without -n
+ EXPECT_NE(0, write_nvram(strdup(keyval)));
+
+ // Add new one successfully
+ can_add_flag = 1;
+ EXPECT_EQ(0, write_nvram(keyval));
+ EXPECT_STREQ(val,HMX_NVRAM_Read_Data);
+
+ // Should be able to read value
+ char output[256];
+ EXPECT_STREQ(val, read_nvram(key, output, sizeof(output), 1));
+
+ char* val2 = strdup("987def");
+ char* keyval2 = strdup("TEST_FIELD=987def");
+
+ // Should be able to change value
+ EXPECT_EQ(0, write_nvram(keyval2));
+ EXPECT_STREQ(val2,HMX_NVRAM_Read_Data);
+
+ free(key);
+ free(val);
+ free(keyval);
+ free(val2);
+ free(keyval2);
+}
+
+TEST_F(HnvramTest, TestClearNvram) {
+ char* key = strdup("TEST_FIELD2");
+ char* val = strdup("abc123");
+ char* keyval = strdup("TEST_FIELD2=abc123");
+ // No error if variable already cleared
+ EXPECT_EQ(DRV_OK, clear_nvram(key));
+
+ // Create new one
+ can_add_flag = 1;
+ EXPECT_EQ(0, write_nvram(keyval));
+ EXPECT_STREQ(val, HMX_NVRAM_Read_Data);
+
+ // Should be able to read value
+ char output[256];
+ EXPECT_STREQ(val, read_nvram(key, output, sizeof(output), 1));
+
+ // Should be able to kill it
+ EXPECT_EQ(DRV_OK, clear_nvram(key));
+
+ // Should fail reading value
+ EXPECT_STREQ(NULL, read_nvram(key, output, sizeof(output), 1));
+
+ free(key);
+ free(val);
+ free(keyval);
+}
+
+int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}