vpd-tool #kw support

This commit is to enable vpd-tool read and write support for pound
keywords starting with # and for numeric keywords.

This commit enables a way to read and write keyword values using --file
option, where --file takes a file with absolute path.

when --file option used with --readKeyword flag - vpd-tool saves the
output in the given file.
and when the file option used with --writeKeyword flag - the vpd-tool
takes the value from file and performs write operation.

Test:
-----------------------------------------------
Case 1: Read from hardware and save in text file
-----------------------------------------------
vpd-tool -r -H -O /sys/bus/i2c/drivers/at24/8-0050/eeprom -R PSPD -K "#D" --file /tmp/output.txt
Value read is saved in the file /tmp/output.txt

-----------------------------------------------
Case 2: Write to hardware by taking input from a text file
-----------------------------------------------
:~# cat /tmp/write.txt
00102030405060607020304050601020304050606040302010

:~# vpd-tool -w -O /sys/bus/i2c/drivers/at24/8-0050/eeprom -R PSPD -K "#D" --file /tmp/write.txt -H
Data updated successfully

:~# vpd-tool -r -H -O /sys/bus/i2c/drivers/at24/8-0050/eeprom -R PSPD -K "#D"
{
    "/sys/bus/i2c/drivers/at24/8-0050/eeprom": {
        "#D": "0x0010203040506060702030405060102030405060604030201000000000 ...0000"
    }
}

-----------------------------------------------
Case 3: Read from cache and pipe to text file
-----------------------------------------------
:~# vpd-tool -r -O /system/chassis/motherboard -R PSPD -K "#D" --file /tmp/read-motherboard-#D.txt
Value read is saved in the file /tmp/read-motherboard-#D.txt

-----------------------------------------------
Case 4: Write to cache by taking input from text file
-----------------------------------------------
:~# cat /tmp/write.txt
00102030405060607020304050601020304050606040302010

:~# vpd-tool -w -O /system/chassis/motherboard -R PSPD -K "#D" --file /tmp/write.txt
Data updated successfully

:~# vpd-tool -r -O /system/chassis/motherboard -R PSPD -K "#D"
{
    "/system/chassis/motherboard": {
        "#D": "0x0010203040506060702030405060102030405060604030201000000000000000000....."
    }
}

-----------------------------------------------
Case 5: Write to cache by taking hex input from console
-----------------------------------------------
:~# vpd-tool -w -O /system/chassis/motherboard -R PSPD -K "#D" -V 0x65
Data updated successfully

:~# vpd-tool -r -O /system/chassis/motherboard -R PSPD -K "#D"
{
    "/system/chassis/motherboard": {
        "#D": "0x65100c0c000000000000000 ...
    }
}

Case 5.1: Write to cache by providing ascii values as input from console

vpd-tool -w -O /system/chassis/motherboard -R PSPD -K "#D" -V abcd
Data updated successfully

vpd-tool -r -O /system/chassis/motherboard -R PSPD -K "#D"
{
    "/system/chassis/motherboard": {
        "#D": "0x6162636440506060702030405060102030405060604030201000000 .."
    }
}

-----------------------------------------------
Case 6: Read from cache and display on console
-----------------------------------------------
:~# vpd-tool -r -O /system/chassis/motherboard -R PSPD -K "#D"
{
    "/system/chassis/motherboard": {
        "#D": "0x00100c0c00000000000000000000000000000000000000 .....
    }
}

-----------------------------------------------
Case 7: Read from hardware and display on console
-----------------------------------------------
vpd-tool -r -O /sys/bus/i2c/drivers/at24/8-0050/eeprom -R PSPD -K "#D" -H
{
    "/sys/bus/i2c/drivers/at24/8-0050/eeprom": {
        "#D": "0x651020304050606070203040506010203040506060403020100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 ......... 000000000000000000000000000000000000000"
    }
}

-----------------------------------------------
Case 8: Write to hardware via console
-----------------------------------------------
vpd-tool -w -H -O /sys/bus/i2c/drivers/at24/8-0050/eeprom -R PSPD -K "#D" -V 0x00100c0c000000000000000000000000000000000000
Data updated successfully

vpd-tool -r -O /sys/bus/i2c/drivers/at24/8-0050/eeprom -R PSPD -K "#D" -H
{
    "/sys/bus/i2c/drivers/at24/8-0050/eeprom": {
        "#D": "0x00100c0c00000000000000000000000000000000000030201000000000000000000000000 ...
    }
}

-----------------------------------------------
Case 9: Write 10240 bytes on dbus
-----------------------------------------------
time vpd-tool -w -O /system/chassis/motherboard -R PSPD -K "#D" --file /tmp/output.txt

Data updated successfully

real	0m49.564s
user	0m0.047s
sys	0m0.009s

time vpd-tool -r -O /system/chassis/motherboard -R PSPD -K "#D"
{
    "/system/chassis/motherboard": {
        "#D": "0x01100c0c0000.....0000123456782746002"
    }
}

real	0m0.072s
user	0m0.057s
sys	0m0.001s
------------------------------------------------

Signed-off-by: Priyanga Ramasamy <priyanga24@in.ibm.com>
Change-Id: I3977a7778b28ebcada7788f619b18bbca6ed0c8c
diff --git a/vpd_tool.cpp b/vpd_tool.cpp
index 61518bd..bc5e37e 100644
--- a/vpd_tool.cpp
+++ b/vpd_tool.cpp
@@ -34,7 +34,7 @@
         "in hex. ascii eg: 01234; hex eg: 0x30313233");
     app.add_option("--seek, -s", offset,
                    "User can provide VPD offset using this option. Default "
-                   "offset value is 0. Using --offset is optional and is valid "
+                   "offset value is 0. Using --seek is optional and is valid "
                    "only while using --Hardware/-H option.");
 
     auto dumpObjFlag =
@@ -63,11 +63,18 @@
                "Update the value. { vpd-tool-exe "
                "--writeKeyword/-w/--updateKeyword/-u "
                "--object/-O object-name --record/-R record-name --keyword/-K "
-               "keyword-name --value/-V value-to-be-updated }")
+               "keyword-name --value/-V (or) --file }. Value can be given "
+               "directly via console using --value or via file using --file")
             ->needs(object)
             ->needs(record)
-            ->needs(kw)
-            ->needs(valOption);
+            ->needs(kw);
+
+    auto fileOption = app.add_option(
+        "--file", val,
+        "Enter the file name with its absolute path. This option can be used "
+        "in read and write operations. When used in read, the read value will "
+        "be saved to this file and when used in write, the value to be written "
+        "will be taken from this file.");
 
     auto forceResetFlag =
         app.add_flag("--forceReset, -f, -F",
@@ -99,6 +106,11 @@
 
     try
     {
+        if ((*kw) && (keyword.size() != 2))
+        {
+            throw runtime_error("Keyword " + keyword + " not supported.");
+        }
+
         if (*Hardware)
         {
             if (!fs::exists(objectPath)) // if dbus object path is given or
@@ -112,6 +124,23 @@
                 throw runtime_error(errorMsg);
             }
         }
+
+        if (*writeFlag)
+        {
+            if ((!*fileOption) && (!*valOption))
+            {
+                throw runtime_error("Please provide the data that needs to be "
+                                    "updated. Use --value/--file to "
+                                    "input data. Refer --help.");
+            }
+
+            if ((*fileOption) && (!fs::exists(val)))
+            {
+                throw runtime_error("Please provide a valid file with absolute "
+                                    "path in --file.");
+            }
+        }
+
         if (*dumpObjFlag)
         {
             VpdTool vpdToolObj(move(objectPath));
@@ -127,7 +156,7 @@
         else if (*readFlag && !*Hardware)
         {
             VpdTool vpdToolObj(move(objectPath), move(recordName),
-                               move(keyword));
+                               move(keyword), move(val));
             vpdToolObj.readKeyword();
         }
 
@@ -164,7 +193,7 @@
         else if (*readFlag && *Hardware)
         {
             VpdTool vpdToolObj(move(objectPath), move(recordName),
-                               move(keyword));
+                               move(keyword), move(val));
             vpdToolObj.readKwFromHw(offset);
         }
         else if (*fixSystemVPDFlag)
@@ -203,12 +232,13 @@
 
         if (*Hardware)
         {
-            std::cerr << "\nDid you provide a valid offset? By default VPD "
-                         "offset is taken as 0. To input offset, use --offset. "
-                         "Refer vpd-tool help.";
+            std::cerr << "Did you provide a valid offset? By default VPD "
+                         "offset is taken as 0. To input offset, use --seek. "
+                         "Refer vpd-tool help."
+                      << std::endl;
         }
         rc = -1;
     }
 
     return rc;
-}
+}
\ No newline at end of file