cgpt.py: Add fs_options flag to the disk_layout.json file.

The fs_options flag allows to pass command line options to the
program that format the filesystem. These options are specific to
the fs_format, so a dictionary can be speficied allowing different
default options for different filesystems.

BUG=chromium:282703,chromium:382951
TEST=./build_image --board=link still works.
    `cgpt.py readfsoptions base disk_layout.json 3` also works.

Change-Id: Id0b1abb1637a08621a8f216619868be0e49d4e6b
Reviewed-on: https://chromium-review.googlesource.com/236997
Trybot-Ready: Alex Deymo <deymo@chromium.org>
Tested-by: Alex Deymo <deymo@chromium.org>
Reviewed-by: Mike Frysinger <vapier@chromium.org>
Commit-Queue: Alex Deymo <deymo@chromium.org>
diff --git a/build_library/README.disk_layout b/build_library/README.disk_layout
index 006ed9f..3a1613c 100644
--- a/build_library/README.disk_layout
+++ b/build_library/README.disk_layout
@@ -96,6 +96,18 @@
         # What file system will this partition be formatted with.
         "fs_format":"ext4",
 
+        # Optional, extra filesystem specific options passed to the program that
+        # creates the filesystem. For example, you can pass compression options
+        # to a compressed filesystem. This accepts a dictionary where the key is
+        # any of the valid fs_format values or a string, which will be used
+        # regardless of the fs_format value.
+        "fs_options":{
+          # Create an inode every 64 KiB of data on ext2 filesystems.
+          "ext2":"-i 65536",
+          # Compress squashfs with lzo.
+          "squashfs":"-comp lzo"
+        },
+
         # Optional, default is size of partition. Meaningless without
         # fs_format. Must be less than size of partition.
         # Size of filesystem in fs size
diff --git a/build_library/cgpt.py b/build_library/cgpt.py
index ecf5b24..8bf8508 100755
--- a/build_library/cgpt.py
+++ b/build_library/cgpt.py
@@ -241,7 +241,7 @@
   valid_layout_keys = set((
       '_comment', 'num', 'blocks', 'block_size', 'fs_blocks', 'fs_block_size',
       'uuid', 'label', 'format', 'fs_format', 'type', 'features', 'num',
-      'size', 'fs_size'))
+      'size', 'fs_size', 'fs_options'))
 
   config = _LoadStackedPartitionConfig(filename)
   try:
@@ -821,6 +821,38 @@
   return partition.get('fs_format')
 
 
+def GetFilesystemOptions(options, image_type, layout_filename, num):
+  """Returns the filesystem options of a given partition and layout type.
+
+  Args:
+    options: Flags passed to the script
+    image_type: Type of image eg base/test/dev/factory_install
+    layout_filename: Path to partition configuration file
+    num: Number of the partition you want to read from
+
+  Returns:
+    The selected partition's filesystem options
+  """
+
+  partitions = GetPartitionTableFromConfig(options, layout_filename, image_type)
+  partition = GetPartitionByNumber(partitions, num)
+
+  fs_options = partition.get('fs_options', {})
+  if isinstance(fs_options, dict):
+    fs_format = partition.get('fs_format')
+    result = fs_options.get(fs_format, '')
+  elif isinstance(fs_options, basestring):
+    result = fs_options
+  else:
+    raise InvalidLayout('Partition number %s: fs_format must be a string or '
+                        'dict, not "%s"' % (num, fs_options.__class__.__name__))
+  if '"' in result or "'" in result:
+    raise InvalidLayout('Partition number %s: fs_format cannot have quotes' %
+                        num)
+
+  return result
+
+
 def GetFilesystemSize(options, image_type, layout_filename, num):
   """Returns the filesystem size of a given partition for a given layout type.
 
@@ -957,6 +989,10 @@
           'usage': ['<image_type>', '<disk_layout>', '<partition_num>'],
           'func': GetFilesystemSize,
       },
+      'readfsoptions': {
+          'usage': ['<image_type>', '<disk_layout>', '<partition_num>'],
+          'func': GetFilesystemOptions,
+      },
       'readlabel': {
           'usage': ['<image_type>', '<disk_layout>', '<partition_num>'],
           'func': GetLabel,
diff --git a/build_library/legacy_disk_layout.json b/build_library/legacy_disk_layout.json
index c88138d..ac5a14d 100644
--- a/build_library/legacy_disk_layout.json
+++ b/build_library/legacy_disk_layout.json
@@ -111,6 +111,9 @@
         "label":"ROOT-A",
         "type":"rootfs",
         "fs_format":"ext2",
+        "fs_options": {
+          "squashfs":"-noI -no-xattrs -comp lzo -Xalgorithm lzo1x_999 -Xcompression-level 9"
+        },
         "size":"2048 MiB",
         "fs_size":"1224 MiB",
         "uuid": "clear"