Re-land: Use the layout.json file to actually build the FS's specified in it.

This CL refactors a bit how we build the initial base image and how we
create FS's for the partitions. Specifically, I'm changing base image
creation to work just like dev and test image creation. In the latter two,
we use mount_gpt_image.sh to mount the existing image.bin file already
containg the gpt layout and fs's and just emerge into the directories. I
do this for the base image as well by creating the GPT image and fs's first.
In order to facilitate that, I moved the mk_fs work to disk_layout_util.sh
which has a new build method build_gpt_image that does what indicated. In
addition to that refactoring I had to better centralize all the mount point
logic which I've moved into mk_fs (creates the stateful and rootfs mount
mounts). Finally, I've modified mount_gpt_image to always mount the oem
partition to both persist and extend how the oem partition gets layed on
the rootfs.

In addition to fixing the below bug, this CL should make building any image
faster since we avoid half the IO (we don't have to dd a bunch of data when
we create the base image).

Finally, this CL was reverted previously because we were creating partition
5 (ROOT-B) now which is actually a waste of time (and breaks when we have
small ROOT-B's in some layouts that don't specify a smaller fs_blocks). So,
in this patch I removed all fs_format/fs_bytes for partitions we don't want
the build system to actually create.

BUG=chromium:325495
TEST=Still going but built various images to completion. Everything is mounted
correctly. Going to create some deltas before and after.

Change-Id: I5f45509e87341386973823890f6f69d1ee069e0b
Reviewed-on: https://chromium-review.googlesource.com/180964
Tested-by: Chris Sosa <sosa@chromium.org>
Reviewed-by: Chris Sosa <sosa@chromium.org>
Commit-Queue: Chris Sosa <sosa@chromium.org>
diff --git a/build_library/base_image_util.sh b/build_library/base_image_util.sh
index 8b90575..36027fc 100755
--- a/build_library/base_image_util.sh
+++ b/build_library/base_image_util.sh
@@ -27,7 +27,6 @@
   safe_umount_tree "${root_fs_dir}"
   safe_umount_tree "${stateful_fs_dir}"
   safe_umount_tree "${esp_fs_dir}"
-  safe_umount_tree "${oem_fs_dir}"
 
    # Turn die on error back on.
   set -e
@@ -44,83 +43,6 @@
   sudo rm "${fs_mount_point}/filler"
 }
 
-# Usage: mk_fs <image_type> <partition_num> <image_file> <fs_uuid> <mount_dir>
-# Args:
-#   image_type: The layout name used to look up partition info in disk layout.
-#   partition_num: The partition to look up in the disk layout.
-#   image_file: The file to write the fs image to.
-#   fs_uuid: 'clear' will set the UUID to all zeros.  'random' will initialize
-#            the UUID with a new random value.
-#   mount_dir: (optional) Where to mount the image after creating it
-#
-# Note: After we mount the fs, we will attempt to reset the root dir ownership
-#       to 0:0 to workaround a bug in mke2fs (fixed in upstream git now).
-mk_fs() {
-  local image_type=$1
-  local part_num=$2
-  local fs_img=$3
-  local fs_uuid=$4
-  local mount_dir=$5
-
-  # These are often not in non-root $PATH, but they contain tools that
-  # we can run just fine w/non-root users when we work on plain files.
-  local p
-  for p in /sbin /usr/sbin; do
-    if [[ ":${PATH}:" != *:${p}:* ]]; then
-      PATH+=":${p}"
-    fi
-  done
-
-  # Keep `local` decl split from assignment so return code is checked.
-  local fs_bytes fs_label fs_format fs_block_size
-
-  fs_bytes=$(get_filesystem_size ${image_type} ${part_num})
-  fs_label=$(get_label ${image_type} ${part_num})
-  fs_format=$(get_filesystem_format ${image_type} ${part_num})
-  fs_block_size=$(get_fs_block_size)
-
-  if [[ ${fs_bytes} -eq 0 ]]; then
-    info "Skipping ${fs_img} (size == 0 bytes)"
-    return 0
-  fi
-
-  info "Building ${fs_img}"
-  truncate -s ${fs_bytes} "${fs_img}"
-  case ${fs_format} in
-  ext[234])
-    mkfs.${fs_format} -F -q -U 00000000-0000-0000-0000-000000000000 \
-      -b ${fs_block_size} "${fs_img}" "$((fs_bytes / fs_block_size))"
-    tune2fs -L "${fs_label}" \
-            -U "${fs_uuid}" \
-            -c 0 \
-            -i 0 \
-            -T 20091119110000 \
-            -m 0 \
-            -r 0 \
-            -e remount-ro \
-            "${fs_img}"
-    ;;
-  fat12|fat16|fat32)
-    mkfs.vfat -F ${fs_format#fat} -n "${fs_label}" "${fs_img}"
-    ;;
-  fat|vfat)
-    mkfs.vfat -n "${fs_label}" "${fs_img}"
-    ;;
-  *)
-    die "Unknown fs format '${fs_format}' for part ${part_num}";;
-  esac
-
-  if [[ -n ${mount_dir} ]]; then
-    mkdir -p "${mount_dir}"
-    local cmds=(
-      "mount -o loop '${fs_img}' '${mount_dir}'"
-      # mke2fs is funky and sets the root dir owner to current uid:gid.
-      "chown 0:0 '${mount_dir}' 2>/dev/null || :"
-    )
-    sudo_multi "${cmds[@]}"
-  fi
-}
-
 create_base_image() {
   local image_name=$1
   local rootfs_verification_enabled=$2
@@ -141,53 +63,25 @@
   info "Using image type ${image_type}"
   get_disk_layout_path
   info "Using disk layout ${DISK_LAYOUT_PATH}"
-
   root_fs_dir="${BUILD_DIR}/rootfs"
   stateful_fs_dir="${BUILD_DIR}/stateful"
   esp_fs_dir="${BUILD_DIR}/esp"
-  oem_fs_dir="${BUILD_DIR}/oem"
 
   trap "cleanup_mounts && delete_prompt" EXIT
   cleanup_mounts &> /dev/null
 
-  local root_fs_img="${BUILD_DIR}/rootfs.image"
-  local stateful_fs_img="${BUILD_DIR}/stateful.image"
-  local esp_fs_img="${BUILD_DIR}/esp.image"
-  local oem_fs_img="${BUILD_DIR}/oem.image"
+  mkdir "${root_fs_dir}" "${stateful_fs_dir}" "${esp_fs_dir}"
+  build_gpt_image "${BUILD_DIR}/${image_name}" "${image_type}"
+  mount_image "${BUILD_DIR}/${image_name}" \
+    "${root_fs_dir}" "${stateful_fs_dir}" "${esp_fs_dir}"
 
-  # Build the various FS images.
-  mk_fs "${image_type}" 3 "${root_fs_img}" clear "${root_fs_dir}"
   df -h "${root_fs_dir}"
-  mk_fs "${image_type}" 1 "${stateful_fs_img}" random "${stateful_fs_dir}"
-  mk_fs "${image_type}" 12 "${esp_fs_img}" clear
-  mk_fs "${image_type}" 8 "${oem_fs_img}" random "${oem_fs_dir}"
-
-  # Prepare stateful partition with some pre-created directories.
-  sudo mkdir "${stateful_fs_dir}/dev_image" "${stateful_fs_dir}/var_overlay"
 
   # Create symlinks so that /usr/local/usr based directories are symlinked to
   # /usr/local/ directories e.g. /usr/local/usr/bin -> /usr/local/bin, etc.
   setup_symlinks_on_root "${stateful_fs_dir}/dev_image" \
     "${stateful_fs_dir}/var_overlay" "${stateful_fs_dir}"
 
-  # Perform binding rather than symlinking because directories must exist
-  # on rootfs so that we can bind at run-time since rootfs is read-only.
-  info "Binding directories from stateful partition onto the rootfs"
-  sudo mkdir -p "${root_fs_dir}/mnt/stateful_partition"
-  sudo mount --bind "${stateful_fs_dir}" "${root_fs_dir}/mnt/stateful_partition"
-  sudo mkdir -p "${root_fs_dir}/usr/local"
-  sudo mount --bind "${stateful_fs_dir}/dev_image" "${root_fs_dir}/usr/local"
-  sudo mkdir -p "${root_fs_dir}/var"
-  sudo mount --bind "${stateful_fs_dir}/var_overlay" "${root_fs_dir}/var"
-  sudo mkdir -p "${root_fs_dir}/dev"
-
-  local oem_fs_bytes=$(get_filesystem_size ${image_type} 8)
-  if [[ ${oem_fs_bytes} -gt 0 ]]; then
-    info "Binding directories from OEM partition onto the rootfs"
-    sudo mkdir -p "${root_fs_dir}/usr/share/oem"
-    sudo mount --bind "${oem_fs_dir}" "${root_fs_dir}/usr/share/oem"
-  fi
-
   # We need to install libc manually from the cross toolchain.
   # TODO: Improve this? It would be ideal to use emerge to do this.
   PKGDIR="/var/lib/portage/pkgs"
@@ -291,19 +185,6 @@
 
   cleanup_mounts
 
-  # Create the GPT-formatted image.
-  build_gpt "${BUILD_DIR}/${image_name}" \
-          "${root_fs_img}" \
-          "${stateful_fs_img}" \
-          "${esp_fs_img}" \
-          "${oem_fs_img}"
-
-  # Clean up temporary files.
-  rm -f "${root_fs_img}" "${stateful_fs_img}" "${esp_fs_img}" "{oem_fs_img}"
-
-  # Emit helpful scripts for testers, etc.
-  emit_gpt_scripts "${BUILD_DIR}/${image_name}" "${BUILD_DIR}"
-
   USE_DEV_KEYS=
   if should_build_image ${CHROMEOS_FACTORY_INSTALL_SHIM_NAME}; then
     USE_DEV_KEYS="--use_dev_keys"
diff --git a/build_library/cgpt.py b/build_library/cgpt.py
index 7d9d145..2305ec2 100755
--- a/build_library/cgpt.py
+++ b/build_library/cgpt.py
@@ -146,7 +146,8 @@
 
   valid_keys = set(('_comment', 'hybrid_mbr', 'metadata', 'layouts', 'parent'))
   valid_layout_keys = _INHERITED_LAYOUT_KEYS | set((
-      '_comment', 'num', 'blocks', 'block_size', 'fs_blocks', 'fs_block_size'))
+      '_comment', 'num', 'blocks', 'block_size', 'fs_blocks', 'fs_block_size',
+      'uuid'))
 
   config = _LoadStackedPartitionConfig(filename)
 
@@ -343,7 +344,7 @@
   """Loads and returns the skeleton script for our output script.
 
   Returns:
-    A string containg the skeleton script
+    A string containing the skeleton script
   """
 
   script_shell_path = os.path.join(os.path.dirname(__file__), 'cgpt_shell.sh')
@@ -562,6 +563,53 @@
   return config['metadata']['fs_block_size']
 
 
+def GetType(options, image_type, layout_filename, num):
+  """Returns the type of a given partition for a given layout.
+
+  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:
+    Type of the specified partition.
+  """
+  partitions = GetPartitionTableFromConfig(options, layout_filename, image_type)
+  partition = GetPartitionByNumber(partitions, num)
+  return partition.get('type')
+
+
+def GetPartitions(options, image_type, layout_filename):
+  """Returns the partition numbers for the image_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
+  Returns:
+    A space delimited string of partition numbers.
+  """
+  partitions = GetPartitionTableFromConfig(options, layout_filename, image_type)
+  partition_nums = []
+  return ' '.join(str(p['num']) for p in partitions if 'num' in p)
+
+
+def GetUUID(options, image_type, layout_filename, num):
+  """Returns the filesystem UUID of a given partition for a given 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:
+    UUID of specified partition. Defaults to random if not set.
+  """
+  partitions = GetPartitionTableFromConfig(options, layout_filename, image_type)
+  partition = GetPartitionByNumber(partitions, num)
+  return partition.get('uuid', 'random')
+
+
 def GetPartitionSize(options, image_type, layout_filename, num):
   """Returns the partition size of a given partition for a given layout type.
 
@@ -589,7 +637,7 @@
     layout_filename: Path to partition configuration file
     num: Number of the partition you want to read from
   Returns:
-    Format of selected partition filesystem
+    Format of the selected partition's filesystem
   """
 
   partitions = GetPartitionTableFromConfig(options, layout_filename, image_type)
@@ -726,6 +774,18 @@
       'usage': ['<image_type>', '<partition_config_file>', '<partition_num>'],
       'func': GetLabel,
     },
+    'readtype': {
+      'usage': ['<image_type>', '<partition_config_file>', '<partition_num>'],
+      'func': GetType,
+    },
+    'readpartitionnums': {
+      'usage': ['<image_type>', '<partition_config_file>'],
+      'func': GetPartitions,
+    },
+    'readuuid': {
+      'usage': ['<image_type>', '<partition_config_file>', '<partition_num>'],
+      'func': GetUUID,
+    },
     'debug': {
       'usage': ['<image_type>', '<partition_config_file>'],
       'func': DoDebugOutput,
diff --git a/build_library/disk_layout_util.sh b/build_library/disk_layout_util.sh
index fa2e081..4bc616b 100644
--- a/build_library/disk_layout_util.sh
+++ b/build_library/disk_layout_util.sh
@@ -41,7 +41,6 @@
   local temp_script_file=$(mktemp)
 
   sudo mkdir -p "$(dirname "${partition_script_path}")"
-
   cgpt_py write "${image_type}" "${DISK_LAYOUT_PATH}" \
           "${temp_script_file}"
   sudo mv "${temp_script_file}" "${partition_script_path}"
@@ -50,7 +49,7 @@
 
 run_partition_script() {
   local outdev=$1
-  local root_fs_img=$2
+  local partition_script=$2
 
   local pmbr_img
   case ${ARCH} in
@@ -66,10 +65,8 @@
     ;;
   esac
 
-  sudo mount -o loop "${root_fs_img}" "${root_fs_dir}"
-  . "${root_fs_dir}/${PARTITION_SCRIPT_PATH}"
+  . "${partition_script}"
   write_partition_table "${outdev}" "${pmbr_img}"
-  sudo umount "${root_fs_dir}"
 }
 
 get_fs_block_size() {
@@ -100,6 +97,29 @@
   cgpt_py readfsformat "${image_type}" "${DISK_LAYOUT_PATH}" ${part_id}
 }
 
+get_partitions() {
+  local image_type=$1
+  get_disk_layout_path
+
+  cgpt_py readpartitionnums "${image_type}" "${DISK_LAYOUT_PATH}"
+}
+
+get_uuid() {
+  local image_type=$1
+  local part_id=$2
+  get_disk_layout_path
+
+  cgpt_py readuuid "${image_type}" "${DISK_LAYOUT_PATH}" ${part_id}
+}
+
+get_type() {
+  local image_type=$1
+  local part_id=$2
+  get_disk_layout_path
+
+  cgpt_py readtype "${image_type}" "${DISK_LAYOUT_PATH}" ${part_id}
+}
+
 get_filesystem_size() {
   local image_type=$1
   local part_id=$2
@@ -253,50 +273,138 @@
   chmod +x "${unpack}" "${pack}" "${mount}" "${umount}"
 }
 
-build_gpt() {
+# Usage: mk_fs  <image_file> <image_type> <partition_num>
+# Args:
+#   image_file: The image file.
+#   image_type: The layout name used to look up partition info in disk layout.
+#   partition_num: The partition number to look up in the disk layout.
+#
+# Note: After we mount the fs, we will attempt to reset the root dir ownership
+#       to 0:0 to workaround a bug in mke2fs (fixed in upstream git now).
+mk_fs() {
+  local image_file=$1
+  local image_type=$2
+  local part_num=$3
+
+  # These are often not in non-root $PATH, but they contain tools that
+  # we can run just fine w/non-root users when we work on plain files.
+  local p
+  for p in /sbin /usr/sbin; do
+    if [[ ":${PATH}:" != *:${p}:* ]]; then
+      PATH+=":${p}"
+    fi
+  done
+
+  # Keep `local` decl split from assignment so return code is checked.
+  local fs_bytes fs_label fs_format fs_block_size offset fs_type
+  fs_format=$(get_filesystem_format ${image_type} ${part_num})
+  if [ -z "${fs_format}" ]; then
+    # We only make fs for partitions that specify a format.
+    return 0
+  fi
+
+  fs_bytes=$(get_filesystem_size ${image_type} ${part_num})
+  fs_block_size=$(get_fs_block_size)
+  if [ "${fs_bytes}" -le ${fs_block_size} ]; then
+    # Skip partitions that are too small.
+    info "Skipping partition $part_num as the blocksize is too small."
+    return 0
+  fi
+
+  info "Creating FS for partition ${part_num} with format ${fs_format}."
+
+  fs_label=$(get_label ${image_type} ${part_num})
+  fs_uuid=$(get_uuid ${image_type} ${part_num})
+  fs_type=$(get_type ${image_type} ${part_num})
+
+  # Mount at the correct place in the file.
+  offset=$(( $(partoffset "${image_file}" "${part_num}") * 512 ))
+  # Root is needed to mount on loopback device.
+  # sizelimit is used to denote the FS size for mkfs if not specified.
+  local part_dev=$(sudo losetup -f --show --offset=${offset} \
+      --sizelimit=${fs_bytes} "${image_file}")
+  if [ ! -e "${part_dev}" ]; then
+    die "No free loopback device to create partition."
+  fi
+
+  case ${fs_format} in
+  ext[234])
+    sudo mkfs.${fs_format} -F -q -U 00000000-0000-0000-0000-000000000000 \
+        -b ${fs_block_size} "${part_dev}" "$((fs_bytes / fs_block_size))"
+    sudo tune2fs -L "${fs_label}" \
+            -U "${fs_uuid}" \
+            -c 0 \
+            -i 0 \
+            -T 20091119110000 \
+            -m 0 \
+            -r 0 \
+            -e remount-ro \
+            "${part_dev}"
+    ;;
+  fat12|fat16|fat32)
+    sudo mkfs.vfat -F ${fs_format#fat} -n "${fs_label}" "${part_dev}"
+    ;;
+  fat|vfat)
+    sudo mkfs.vfat -n "${fs_label}" "${part_dev}"
+    ;;
+  *)
+    die "Unknown fs format '${fs_format}' for part ${part_num}";;
+  esac
+
+  local mount_dir="$(mktemp -d)"
+  local cmds=(
+    "mount '${part_dev}' '${mount_dir}'"
+    # mke2fs is funky and sets the root dir owner to current uid:gid.
+    "chown 0:0 '${mount_dir}' 2>/dev/null || :"
+  )
+
+  # Prepare partitions with well-known mount points.
+  if [ "${fs_label}" = "STATE" ]; then
+    # These directories are used to mount data from stateful onto the rootfs.
+    cmds+=("sudo mkdir '${mount_dir}/dev_image'"
+           "sudo mkdir '${mount_dir}/var_overlay'"
+    )
+  elif [ "${fs_type}" = "rootfs" ]; then
+    # These rootfs mount points are necessary to mount data from other
+    # partitions onto the rootfs. These are used by both build and run times.
+    cmds+=("sudo mkdir -p '${mount_dir}/mnt/stateful_partition'"
+           "sudo mkdir -p '${mount_dir}/usr/local'"
+           "sudo mkdir -p '${mount_dir}/usr/share/oem'"
+           "sudo mkdir '${mount_dir}/var'"
+    )
+  fi
+  sudo_multi "${cmds[@]}"
+
+  # Deletes associated loopback device as well.
+  sudo umount -d "${mount_dir}"
+  rm -rf "${mount_dir}"
+}
+
+# Creates the gpt image for the given disk layout. In addition to creating
+# the partition layout it creates all the initial filesystems. After this file
+# is created, mount_gpt_image.sh can be used to mount all the filesystems onto
+# directories.
+build_gpt_image() {
   local outdev="$1"
-  local rootfs_img="$2"
-  local stateful_img="$3"
-  local esp_img="$4"
-  local oem_img="$5"
+  local disk_layout="$2"
 
-  get_disk_layout_type
-  run_partition_script "${outdev}" "${rootfs_img}"
+  # Build the partition table. We create a temporary file for this here.
+  local partition_script_path="$(mktemp)"
+  write_partition_script "${disk_layout}" "${partition_script_path}"
+  run_partition_script "${outdev}" "${partition_script_path}"
+  rm "${partition_script_path}"
 
-  local sudo=
-  if [ ! -w "$outdev" ] ; then
-    # use sudo when writing to a block device.
-    sudo=sudo
-  fi
+  # Emit the gpt scripts so we can use them from here on out.
+  emit_gpt_scripts "${outdev}" "$(dirname "${outdev}")"
 
-  # Now populate the partitions.
-  info "Copying stateful partition..."
-  $sudo dd if="$stateful_img" of="$outdev" conv=notrunc bs=512 \
-      seek=$(partoffset ${outdev} 1) status=none
-
-  info "Copying rootfs..."
-  $sudo dd if="$rootfs_img" of="$outdev" conv=notrunc bs=512 \
-      seek=$(partoffset ${outdev} 3) status=none
-
-  if [[ -f "${esp_img}" ]]; then
-    info "Copying EFI system partition..."
-    $sudo dd if="$esp_img" of="$outdev" conv=notrunc bs=512 \
-      seek=$(partoffset ${outdev} 12) status=none
-  else
-    info "Skipping EFI system partition (file not found: ${esp_img})"
-  fi
-
-  if [[ -f "${oem_img}" ]]; then
-    info "Copying OEM partition..."
-    $sudo dd if="$oem_img" of="$outdev" conv=notrunc bs=512 \
-        seek=$(partoffset ${outdev} 8) status=none
-  else
-    info "Skipping OEM partition (file not found: ${oem_img})"
-  fi
+  # Create the filesystem on each partition defined in the layout file.
+  for p in $(get_partitions "${disk_layout}"); do
+    mk_fs "${outdev}" "${disk_layout}" "${p}"
+  done
 
   # Pre-set "sucessful" bit in gpt, so we will never mark-for-death
   # a partition on an SDCard/USB stick.
-  cgpt add -i 2 -S 1 "$outdev"
+  cgpt add -i 2 -S 1 "${outdev}"
 }
 
 round_up_4096() {
diff --git a/build_library/legacy_disk_layout.json b/build_library/legacy_disk_layout.json
index 53db1b3..8aea95c 100644
--- a/build_library/legacy_disk_layout.json
+++ b/build_library/legacy_disk_layout.json
@@ -22,7 +22,6 @@
         "num": 7,
         "label":"ROOT-C",
         "type":"rootfs",
-        "fs_format":"ext2",
         "blocks":"1"
       },
       {
@@ -58,7 +57,8 @@
         "label":"OEM",
         "type":"data",
         "fs_format":"ext4",
-        "blocks":"32768"
+        "blocks":"32768",
+        "uuid": "random"
       },
       {
         "type":"blank",
@@ -69,15 +69,14 @@
         "label":"EFI-SYSTEM",
         "type":"efi",
         "fs_format":"vfat",
-        "blocks":"32768"
+        "blocks":"32768",
+        "uuid": "clear"
       },
       {
         "num": 5,
         "label":"ROOT-B",
         "type":"rootfs",
-        "fs_format":"ext2",
-        "blocks":"4194304",
-        "fs_blocks":"262144"
+        "blocks":"4194304"
       },
       {
         "num": 3,
@@ -85,7 +84,8 @@
         "type":"rootfs",
         "fs_format":"ext2",
         "blocks":"4194304",
-        "fs_blocks":"262144"
+        "fs_blocks":"262144",
+        "uuid": "clear"
       },
       {
         "num": 1,
@@ -93,7 +93,8 @@
         "type":"data",
         "fs_format":"ext4",
         "blocks":"2097152",
-        "features":["expand"]
+        "features":["expand"],
+        "uuid": "random"
       }
     ],
     "usb": [
@@ -164,8 +165,7 @@
       },
       {
         "num": 5,
-        "blocks":"4194304",
-        "fs_blocks":"512000"
+        "blocks":"4194304"
       }
     ],
     "4gb-rootfs": [
diff --git a/common.sh b/common.sh
index 9816854..9577aab 100644
--- a/common.sh
+++ b/common.sh
@@ -683,7 +683,8 @@
   fi
 
   # First try to unmount in one shot to speed things up.
-  if safe_umount -d ${mounts}; then
+  # Hide output since we may have devices mounted within a mount point.
+  if safe_umount -d ${mounts} 2> /dev/null; then
     return 0
   fi
 
diff --git a/mount_gpt_image.sh b/mount_gpt_image.sh
index 9d813c7..aac9e62 100755
--- a/mount_gpt_image.sh
+++ b/mount_gpt_image.sh
@@ -109,6 +109,7 @@
 
   sudo mount ${safe_flag} "${FLAGS_from}3" "${FLAGS_rootfs_mountpt}"
   sudo mount ${ro_flag} "${FLAGS_from}1" "${FLAGS_stateful_mountpt}"
+  sudo mount ${ro_flag} "${FLAGS_from}8" "${FLAGS_rootfs_mountpt}/usr/share/oem"
 
   if [[ -n "${FLAGS_esp_mountpt}" && -e ${FLAGS_from}12 ]]; then
     sudo mount ${ro_flag} "${FLAGS_from}12" "${FLAGS_esp_mountpt}"
@@ -123,6 +124,10 @@
   local ro_flag=""
   local safe_flag=""
 
+  if [ ! -f "${FLAGS_from}/${filename}" ]; then
+    die "Image ${FLAGS_from}/${filename} does not exist."
+  fi
+
   if [ ${FLAGS_read_only} -eq ${FLAGS_TRUE} ]; then
     ro_flag="-o ro"
   fi
@@ -153,6 +158,15 @@
     return 1
   fi
 
+  # Mount the oem partition using a loopback device.
+  offset=$(partoffset "${FLAGS_from}/${filename}" 8)
+  if ! sudo mount ${ro_flag} -o loop,offset=$(( offset * 512 )) \
+      "${FLAGS_from}/${filename}" "${FLAGS_rootfs_mountpt}/usr/share/oem" ; then
+    error "mount failed: options=${safe_flag} offset=$(( offset * 512 ))" \
+        "target=${FLAGS_rootfs_mountpt}/usr/share/oem"
+    return 1
+  fi
+
   # Mount the stateful partition using a loopback device.
   local esp_size
   if [[ -n "${FLAGS_esp_mountpt}" ]]; then
@@ -176,7 +190,6 @@
   if [[ -n "${FLAGS_esp_mountpt}" ]]; then
     mkdir -p "${FLAGS_esp_mountpt}"
   fi
-
   # Get the partitions for the image / device.
   if [ -b ${FLAGS_from} ] ; then
     get_usb_partitions
@@ -187,12 +200,14 @@
   fi
 
   # Mount directories and setup symlinks.
+  sudo mount --bind "${FLAGS_stateful_mountpt}" \
+    "${FLAGS_rootfs_mountpt}/mnt/stateful_partition"
   sudo mount --bind "${FLAGS_stateful_mountpt}/var_overlay" \
     "${FLAGS_rootfs_mountpt}/var"
   sudo mount --bind "${FLAGS_stateful_mountpt}/dev_image" \
     "${FLAGS_rootfs_mountpt}/usr/local"
-  # Setup symlinks in /usr/local so you can emerge packages into /usr/local.
 
+  # Setup symlinks in /usr/local so you can emerge packages into /usr/local.
   if [ ${FLAGS_read_only} -eq ${FLAGS_FALSE} ]; then
     setup_symlinks_on_root "${FLAGS_stateful_mountpt}/dev_image" \
       "${FLAGS_stateful_mountpt}/var_overlay" "${FLAGS_stateful_mountpt}"