Documentation for the script create_overlay_mount.sh

Last Update: 23.06.2025/bs


Contents


  1. Documentation for the script create_overlay_mount.sh
    1. Contents
    2. Introduction
    3. Author
    4. License
    5. History
    6. Details
      1. Usage examples
      2. Environment variables used by the script
    7. Test Environment
    8. Limitations
    9. Trouble Shooting
    10. Downloads
    11. Links



Introduction


Since Android 10 many file systems in the Android OS are only mounted read-only and can no longer be mounted writable even by the root user. This is safe, but extremely unattractive.

One way to circumvent these restrictions is to install Magisk and Magisk modules. Magisk uses bind mounts to change or create files in the read-only file systems. This works very well to create or change binaries in /system/bin, for example. However, when creating the Magisk module you need to know which files are to be added or replaced.

To install new tools directly in Android via “make install”, for example, this does not work

A more flexible solution is the use of overlay mounts. As far as I know, overlay mounts have been supported in Android since Android 10 (at least partially).

For those who have Magisk installed, overlay mounts for the standard read-only directories can be created using the Magisk module

https://github.com/Magisk-Modules-Alt-Repo/magisk_overlayfs

That Magisk module also works in the Android 15.

(see How to create Magisk Modules that install new files in system for Details).


Because overlay mounts are supported by Android out-of-the-box, Magisk is not mandatory to use overlay mounts in Android.

Therefore, I have written a little script to manually create and use overlay mounts in Android on rooted devices:

create_overlay_mount.sh

The usage for the script is:

ASUS_I006D:/data/local/tmp # ./create_overlay_mount.sh -h

 create_overlay_mount.sh v1.1.0 - create one or more overlay mounts on a device running a rooted Android OS

 Usage:  create_overlay_mount.sh [-h|--help] [--version] [--verbose|-v] [--noselinux] [--selinux] [--initdisk|--format] [--details] [--short] [--active] [var=value]
                                 [help] [vars] [list] [test] [get] [undo] [diff] [get] [restore] [clean] [mount_only] [mount] [umount] [remount] [directory0] [... directory#] [default]

ASUS_I006D:/data/local/tmp #


The parameter can be entered in any order.


To view the detailed usage help use the parameter -v -h or help:


./create_overlay_mount.sh help
ASUS_I006D:/data/local/tmp $ ./create_overlay_mount.sh  help

 create_overlay_mount.sh v1.1.0 - create one or more overlay mounts on a device running a rooted Android OS

 Usage:  create_overlay_mount.sh [-h|--help] [--version] [--verbose|-v] [--noselinux] [--selinux] [--initdisk|--format] [--details] [--short] [--active] [var=value]
                                 [help] [vars] [list] [test] [get] [undo] [diff] [get] [restore] [clean] [mount_only] [mount] [umount] [remount] [directory0] [... directory#] [default]

 The parameter that neither start with a "-" or "/" nor contain a "=" are the action parameter that determine what is to be done.
 Only one action parameter for a run is allowed.

 Without an action parameter the script prints the short usage help. If one more directories are found in the parameter the default action is "mount".

 All parameter starting with a "/" are considered to be a filename or directory name.
 The parameter with the directory names are optional.

 The default directory list for the actions "mount", "diff", "get" and "undo" is the list of directories in the environment variable DIRS_TO_OVERLAY.
 The default directory list for the actions "test", "umount", and "remount" is the list of directories currently mounted to an overlay filesystem.

 There are no default values for the action "restore"; the actions "mount_only" and "list" ignore directory parameter.

 The actions "vars" and "help" only print help messages.

 If the variable DIRS_TO_OVERLAY is empty the script uses the hardcoded default value for this variable; that is: /system_ext /vendor /product  /odm  /system

 "directory#" must be either "default", "none", or the fully qualified directory name of a directory.
 The value "none" deletes the current list of directories in the variable DIRS_TO_OVERLAY; the value "default" adds the default directories to the list
 of directories.. The parameter can be used more than once.
 
 The known option parameter are:
 
 --version    print the script version and exit
 --verbose    print more messages
 --noselinux  disable SELinux at start of the script (SELinux is NOT enabled again by the script)
 --selinux    enable SELinux at start of the script (SELinux is NOT disabled again by the script)
 --initdisk   format the virtual disk before creating the overlay mounts; this will undo all previous changes in the filesystems
              Without this option the script never formats an existing virtual disk.
 --details    print more details
 --short      print only the important information
 --active     the tasks diff, get, and undo should work only on the currently mounted overlay filesystesm

 The known action parameter are:

 help         print verbose usage help
 vars         print only the list of supported environment variables
 list         list directories mounted on overlay filesystems
 test         test write access to directories mounted on overlay filesystems;
              default is: test write access to all directories currently mounted on an overlay filesystems
 get          print the name of the backend used for a file or directory mounted on an overlay filesystem
 undo         delete all changes done in a directory with an overlay mount
              default is: delete all changes done for all directories in the environment variable DIRS_TO_OVERLAY (regardless of the mount status)
 diff         list the file changes for directories with overlay mounts
              default is: list the changes done for all directories in the environment variable DIRS_TO_OVERLAY (regardless of the mount status)
 restore      restore a file or directory mounted on an overlay filesystem

 mount_only   mount the virtual disk and exit

 mount        mount the overlays for the directories
 umount       umount the overlays for the directories; default is to umount all overlays
 remount      remount the overlay mounts

 clean        umount all overlay mounts and umount the virtual disk

 Other supported parameter:

 var=value sets the variable "var" to the value "value"

 Notes
 
 Set the variable TRACE to any value before starting script execute it with "set -x"

 The detailed documentation for the script can be found here:

     http://bnsmb.de/android/Documentation_for_the_script_create_overlay_mount.sh.html


Supported environment variables:

Name                   Default Value
----                   -------------
IMAGE_FILE             /data/local/tmp/image001
BASEDIR                /dev/ov
DIRS_TO_OVERLAY        /system_ext /product /odm /system
FILESYSTEM_TO_USE      ext4
FILESYSTEM_SIZE        100m
MKFS_OPTIONS          
MOUNT_OPTIONS         
SELINUX_CONTEXT        u:object_r:system_file:s0
UMOUNT_WAIT_TIME       0
MOUNT                  /system/bin/mount
UMOUNT                 /system/bin/umount
LOSETUP                /system/bin/losetup
MKFS                  
DD                     /system/bin/dd

ASUS_I006D:/data/local/tmp #


Note:

The default for the MKFS binary is created dynamically based on the filesystem to use:  mkfs.${FILESYSTEM_TO_USE}
----


The script create_overlay_mount.sh can be used to mount or umount an overlay filesystem for directories like /system , /system_ext, etc.
Overlay mounts for sub directories only like /system/priv-app or /system/priv-app/Shell are also possible.

For directories mounted to an overlay mount the script can be used

- to test the write access (script parameter "test")

- to list the files and directories changed or deleted (script parameter "diff")

- to undo all changes at once (script parameter "undo")

- to restore changed files or deleted files or directories (script parameter "restore")

- to print the current backend for each file or directory (script parameter "get")

- to remove all overlay mounts and the loop device (script parameter "clean")


See the details below for the usage examples of the script.


The script only requires binaries that are part of the standard Android OS (e.g. mount, umount, df, losetup)

Since there might be a "problem" using the umount binary and the sh binary in Android to umount the system directories (see here), I created a statically linked umount binary and a statically linked bash binary -- see the Downloads section below.



Author


Bernd Schemmer (Bernd.Schemmer@gmx.de)



License


License
                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.



----


History


ChangeLog

22.06.2025 /bs

Initial release

23.06.2025 /bs

corrected the infos about how to use the virtual disk from the Magisk Module with overlayfs 
added the hint about "lost" files in mounted sub directories 
added infos about overlay mounts for /vendor
the directory /vendor is not in the default list with directories for overlay mounts anymore.

24.06.2025 /bs

default mount point is now /dev/ov

----


Details


The script must be executed by the root user to create the overlay mounts. In addition, root access is necessary to create or change files or directories in the system directories mounted to overlay mounts.

The filesystem type used for the filesystem mounted on /data does not support overlay mounts. Therefore, the script creates a file, configures that file as virtual disk, formats the virtual disk with the ext4 filesystem and mounts the virtual disk. The filesystem on the virtual disks is than used as backend for the overlay mounts. If the virtual disk already exists, the script uses it again without formating the virtual disk.

All changes in the directories mounted via overlay mounts are saved on the virtual disk. Therefore, the changes in the directories that are mounted via the overlay file system are persistent as long as the virtual disk used as the backend for the overlay mounts exists.

Overlay mounts can be created for most of the directories, except for directories in filesystems that do not support overlay mounts (like /data) and some directories with special meaning (like /dev, /sys, /proc detc.) or directories with a special SELinux context like /oem.

To find out whether an overlay mount can be created for a directory, simply test it with the script. If it does not work, the script simply fails, but does not break anything.


If the script is executed without a parameter, the script prints the short usage help.

If there are one or more directories in the parameter but no action parameter, the default action is mount .

If the script is executed with an action parameter and one or more directories or files in the parameter, the requested action is done only for the directories or files in the parameter.

If the script is executed with an action parameter but without a directory, the action is done for the directories in the default directory list.

The default directory list used by the different actions are:

Action
Default directories
Comment
mount
directories listed in the environment variable DIRS_TO_OVERLAY

diff
directories listed in the environment variable DIRS_TO_OVERLAY
the action is done regardless of the mount status of the directories

use the option --active to process only the mounted overlay filesystems
undo
directories listed in the environment variable DIRS_TO_OVERLAY
the action is done regardless of the mount status of the directories

use the option --active to process only the mounted overlay filesystems



test
directories currently mounted with an overlay filesystem

umount
directories currently mounted with an overlay filesystem
remount
directories currently mounted with an overlay filesystem
get
directories listed in the environment variable DIRS_TO_OVERLAY use the option --active to process only the mounted overlay filesystems

This action can also be used for files.



restore
n/a
there are no default files or directories for this action

This action can also be used for files.
list
n/a
This action always lists all directories currently mounted with an overlay filesystem

Use the option --details to also list the backend directory and backend disk for each overlay mount



mount_only
n/a



To explicitly request one of the actions only for the directories listed in the variable DIRS_TO_OVERLAY, use the parameter default.


The default value for the variable DIRS_TO_OVERLAY hard-coded in the script is:

/system_ext
/product
/odm
/system
  

 

Usage examples




Note

Most of the examples below were executed in the OmniROM - the directories may look different in other Android distributions



To create the overlay mounts, use the script parameter mount.

Example output of executing the script with the parameter mount the first time:


/data/local/tmp/create_overlay_mount.sh mount

ASUS_I006D:/data/local/tmp # ./create_overlay_mount.sh mount                                                                                                                                                                   
Creating the image file "/data/local/tmp/image001" with the size 100m ...
1+0 records in
1+0 records out
104857600 bytes (100 M) copied, 0.084 s, 1.1 G/s
Creating a "ext4" filesystem on the image file "/data/local/tmp/image001" now ...
mke2fs 1.46.6 (1-Feb-2023)
128-byte inodes cannot handle dates beyond 2038 and are deprecated
Discarding device blocks: done                           
Creating filesystem with 102400 1k blocks and 25688 inodes
Filesystem UUID: e3d7cc86-e3e7-4824-a0fc-af07fd3d6023
Superblock backups stored on blocks:
    8193, 24577, 40961, 57345, 73729

Allocating group tables: done                           
Writing inode tables: done                           
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

Mounting the imagefile "/data/local/tmp/image001" to "/data/local/tmp/ov" ...
Creating the directory "/data/local/tmp/ov/upper" ...
Creating the directory "/data/local/tmp/ov/merged" ...
Creating the directory "/data/local/tmp/ov/work" ...

Creating and mounting the directories for the overlay mount for "/system_ext" ...
Creating the directory "/data/local/tmp/ov/upper/system_ext" ...
Creating the directory "/data/local/tmp/ov/merged/system_ext" ...
Creating the directory "/data/local/tmp/ov/work/system_ext" ...
Creating the overlay mount for "/system_ext" ...
Creating the bind mount "/system_ext"...
Checking the overlay mount for "/system_ext" ...

Creating and mounting the directories for the overlay mount for "/product" ...
Creating the directory "/data/local/tmp/ov/upper/product" ...
Creating the directory "/data/local/tmp/ov/merged/product" ...
Creating the directory "/data/local/tmp/ov/work/product" ...
Creating the overlay mount for "/product" ...
Creating the bind mount "/product"...
Checking the overlay mount for "/product" ...

Creating and mounting the directories for the overlay mount for "/odm" ...
Creating the directory "/data/local/tmp/ov/upper/odm" ...
Creating the directory "/data/local/tmp/ov/merged/odm" ...
Creating the directory "/data/local/tmp/ov/work/odm" ...
Creating the overlay mount for "/odm" ...
Creating the bind mount "/odm"...
Checking the overlay mount for "/odm" ...

Creating and mounting the directories for the overlay mount for "/system" ...
Creating the directory "/data/local/tmp/ov/upper/system" ...
Creating the directory "/data/local/tmp/ov/merged/system" ...
Creating the directory "/data/local/tmp/ov/work/system" ...
Creating the overlay mount for "/system" ...
Creating the bind mount "/system"...
Checking the overlay mount for "/system" ...

Summary:
--------

4 overlay mount(s) created:

  /system_ext
  /product
  /odm
  /system

ASUS_I006D:/data/local/tmp #

----


To only create an overlay mount for the directory /odm_dlkm the script usage is

/data/local/tmp/create_overlay_mount.sh mount /odm_dlkm

or

/data/local/tmp/create_overlay_mount.sh /odm_dlkm

e.g. (in this example the file used as virtual disk already exists):

/data/local/tmp/create_overlay_mount.sh /odm_dlkm
ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh /odm_dlkm
The image file "/data/local/tmp/image001" already exists - there should already be a filesystem

Creating and mounting the directories for the overlay mount for "/odm_dlkm" ...
Creating the directory "/data/local/tmp/ov/upper/odm_dlkm" ...
Creating the directory "/data/local/tmp/ov/merged/odm_dlkm" ...
Creating the directory "/data/local/tmp/ov/work/odm_dlkm" ...
Creating the overlay mount for "/odm_dlkm" ...
Creating the bind mount "/odm_dlkm"...
Checking the overlay mount for "/odm_dlkm" ...

Summary:
--------

1 overlay mount(s) created:

  /odm_dlkm

ASUS_I006D:/ #

----


To create an overlay mount for an additional directory, execute the script again, e.g. to create an additional overlay mount for the directory /vendor/etc:

/data/local/tmp/create_overlay_mount.sh /vendor/etc
130|ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh /vendor/etc
The image file "/data/local/tmp/image001" already exists - there should already be a filesystem

Creating and mounting the directories for the overlay mount for "/vendor/etc" ...
Creating the directory "/data/local/tmp/ov/upper/vendor#etc" ...
Creating the directory "/data/local/tmp/ov/merged/vendor#etc" ...
Creating the directory "/data/local/tmp/ov/work/vendor#etc" ...
Creating the overlay mount for "/vendor/etc" ...
Creating the bind mount "/vendor/etc"...
Checking the overlay mount for "/vendor/etc" ...

Summary:
--------

1 overlay mount(s) created:

  /vendor/etc

ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh list
Directories mounted on an overlay filesystem

/system_ext
/product
/odm
/system
/vendor/etc


ASUS_I006D:/data/local/tmp # 


----


Directory parameters for the script overwrite the variable DIRS_TO_OVERLAY. To create an overlay mount for the default directories and additional directories, use the parameter default, e.g.: to create overlay mounts for the default directories and the directories /vendor/app and /vendor/bin, execute:

/data/local/tmp/create_overlay_mount.sh default /vendor/app /vendor/bin
ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh default /vendor/app /vendor/bin
The image file "/data/local/tmp/image001" already exists - there should already be a filesystem

Creating and mounting the directories for the overlay mount for "/system_ext" ...
Creating the overlay mount for "/system_ext" ...
Creating the bind mount "/system_ext"...
Checking the overlay mount for "/system_ext" ...

Creating and mounting the directories for the overlay mount for "/product" ...
Creating the overlay mount for "/product" ...
Creating the bind mount "/product"...
Checking the overlay mount for "/product" ...

Creating and mounting the directories for the overlay mount for "/odm" ...
Creating the overlay mount for "/odm" ...
Creating the bind mount "/odm"...
Checking the overlay mount for "/odm" ...

Creating and mounting the directories for the overlay mount for "/system" ...
Creating the overlay mount for "/system" ...
Creating the bind mount "/system"...
Checking the overlay mount for "/system" ...

Creating and mounting the directories for the overlay mount for "/vendor/app" ...
Creating the directory "/data/local/tmp/ov/upper/vendor#app" ...
Creating the directory "/data/local/tmp/ov/merged/vendor#app" ...
Creating the directory "/data/local/tmp/ov/work/vendor#app" ...
Creating the overlay mount for "/vendor/app" ...
Creating the bind mount "/vendor/app"...
Checking the overlay mount for "/vendor/app" ...

Creating and mounting the directories for the overlay mount for "/vendor/bin" ...
Creating the directory "/data/local/tmp/ov/upper/vendor#bin" ...
Creating the directory "/data/local/tmp/ov/merged/vendor#bin" ...
Creating the directory "/data/local/tmp/ov/work/vendor#bin" ...
Creating the overlay mount for "/vendor/bin" ...
Creating the bind mount "/vendor/bin"...
Checking the overlay mount for "/vendor/bin" ...

Summary:
--------

6 overlay mount(s) created:

  /system_ext
  /product
  /odm
  /system
  /vendor/app
  /vendor/bin

ASUS_I006D:/data/local/tmp #

----


Note that it is not possible to create an overlay mount for a subdirectory if there is already an overlay mount for the parent directory using the script.

For example, if there is an overlay mount for /system in place, you cannot create an overlay mount for /system/etc.

Creating overlay mounts in the opposite direction using the script works, but is not recommended!




To list the overlay mounts created by the script use the parameter list :

/data/local/tmp/create_overlay_mount.sh list

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh list
Directories mounted on an overlay filesystem

/system_ext
/product
/odm
/system
/odm_dlkm


ASUS_I006D:/ #
 
# Use the option parameter --details to print more details:

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh  list --details
Directories mounted on an overlay filesystem

Directory        Backend Directory
---------        -----------------
/system_ext      /data/local/tmp/ov (Virtual disk: /data/local/tmp/image001)
/vendor          /data/local/tmp/ov (Virtual disk: /data/local/tmp/image001)
/product         /data/local/tmp/ov (Virtual disk: /data/local/tmp/image001)
/odm             /data/local/tmp/ov (Virtual disk: /data/local/tmp/image001)
/system          /data/local/tmp/ov (Virtual disk: /data/local/tmp/image001)

ASUS_I006D:/ #

----


To get the directories used for new files for the current active overlay mounts use the parameter get with the option --active:

/data/local/tmp/create_overlay_mount.sh get --active
ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get --active
/data/local/tmp/ov/upper/system_ext # /system_ext
/data/local/tmp/ov/upper/product # /product
/data/local/tmp/ov/upper/odm # /odm
/data/local/tmp/ov/upper/system # /system

ASUS_I006D:/ #

# or only for specific directories:

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get --active /system
/data/local/tmp/ov/upper/system # /system

ASUS_I006D:/ #

----



To test the write access in the directories with overlay mounts use the parameter test:

/data/local/tmp/create_overlay_mount.sh test
ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh test
Testing the write access for directories mounted on overlay filesystems ...


Testing write access for the directory "/system_ext" ...
  OK, the write access to the directory "/system_ext" works

Testing write access for the directory "/product" ...
  OK, the write access to the directory "/product" works

Testing write access for the directory "/odm" ...
  OK, the write access to the directory "/odm" works

Testing write access for the directory "/system" ...
  OK, the write access to the directory "/system" works

Testing write access for the directory "/odm_dlkm" ...
  OK, the write access to the directory "/odm_dlkm" works

ASUS_I006D:/ #

----



To list the backend used for a file or directory use the parameter get

The format of the output of the action get is

backend_file # original_file # comment

e.g.

/data/local/tmp/ov/upper/system_ext/etc/passwd # /system_ext/etc/passwd # the file was changed


Entries for deleted files may be files, directories, or anything else. As long as the overlay mount and the bind mount is in place, this info is not available (see below for a workaround for this problem).




Example output of the script with the parameter get:

/data/local/tmp/create_overlay_mount.sh  get  /system_ext/priv-app/OmniControl/testdir

----
commands to create the test environment
# instructions to create the test env
#
cd /system_ext/
mkdir -p ./priv-app/OmniControl/testdir/testdir2
touch ./priv-app/OmniControl/testdir/testdir2/testfile3
touch  ./priv-app/OmniControl/testdir/testfile2
touch ./priv-app/OmniControl/testfile1
rm ./priv-app/OmniControl/oat/arm64/OmniControl.odex
rm ./priv-app/OmniControl/oat/arm64/OmniControl.vdex                                                                                                                                                                       
----

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh diff /system_ext
List the changes in the directories ...

 ----------------------------------------------------------------------
List the changes in the directory "/system_ext" ...
There is currently an overlay mounted for the directory "/system_ext"
File changes in the directory "/system_ext" :

./priv-app
./priv-app/OmniControl
./priv-app/OmniControl/testdir
./priv-app/OmniControl/testdir/testdir2
./priv-app/OmniControl/testdir/testdir2/testfile3
./priv-app/OmniControl/testdir/testfile2
./priv-app/OmniControl/testfile1

Files or directories deleted in the directory "/system_ext" :

./priv-app/OmniControl/oat/arm64/OmniControl.odex 
./priv-app/OmniControl/oat/arm64/OmniControl.vdex


ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get /system_ext/priv-app/OmniControl/testdir
/data/local/tmp/ov/upper/system_ext/priv-app/OmniControl/testdir # /system_ext/priv-app/OmniControl/testdir

ASUS_I006D:/ #

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get /system_ext/priv-app/OmniControl/testdir/testdir2
/data/local/tmp/ov/upper/system_ext/priv-app/OmniControl/testdir/testdir2 # /system_ext/priv-app/OmniControl/testdir/testdir2

ASUS_I006D:/ #

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get /system_ext/priv-app/OmniControl/testdir/testdir2/testfile3
/data/local/tmp/ov/upper/system_ext/priv-app/OmniControl/testdir/testdir2/testfile3 # /system_ext/priv-app/OmniControl/testdir/testdir2/testfile3 # the file was changed

ASUS_I006D:/ #

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get /system_ext/priv-app/OmniControl/testdir/testfile2
/data/local/tmp/ov/upper/system_ext/priv-app/OmniControl/testdir/testfile2 # /system_ext/priv-app/OmniControl/testdir/testfile2 # the file was changed

ASUS_I006D:/ #

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get /system_ext/priv-app/OmniControl/testfile1
/data/local/tmp/ov/upper/system_ext/priv-app/OmniControl/testfile1 # /system_ext/priv-app/OmniControl/testfile1 # the file was changed

ASUS_I006D:/ #

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get /system_ext/priv-app/OmniControl/testfile5
/data/local/tmp/ov/upper/system_ext/priv-app/OmniControl/testfile5 # /system_ext/priv-app/OmniControl/testfile5 # the file was not yet changed or deleted

ASUS_I006D:/ #

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get /system_ext/priv-app/OmniControl/oat/arm64/OmniControl.odex
/data/local/tmp/ov/upper/system_ext/priv-app/OmniControl/oat/arm64/OmniControl.odex # /system_ext/priv-app/OmniControl/oat/arm64/OmniControl.odex # the file/directory was deleted

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get /system_ext/priv-app/OmniControl/oat/arm64/OmniControl.vdex 
/data/local/tmp/ov/upper/system_ext/priv-app/OmniControl/oat/arm64/OmniControl.vdex # /system_ext/priv-app/OmniControl/oat/arm64/OmniControl.vdex # the file/directory was deleted


ASUS_I006D:/ #

----


The options --short and --details can be used to change the information printed by the action get:



Other example for the action get
----
commands to create the test environments
# instructions to create the test env
#
/data/local/tmp/create_overlay_mount.sh umount /odm
/data/local/tmp/create_overlay_mount.sh /odm/etc /vendor

touch /odm/etc/passwd
touch /odm/etc/selinux/precompiled_sepolicy
rm /odm/etc/group
touch /vendor/etc/vmmgr.conf

----

ASUS_I006D:/data/local/tmp # ./create_overlay_mount.sh  list
Directories mounted on an overlay filesystem

/odm/etc
/vendor


ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  diff /odm/etc /vendor
List the changes in the directories ...

 ----------------------------------------------------------------------
List the changes in the directory "/odm/etc" ...
There is currently an overlay mounted for the directory "/odm/etc"
File changes in the directory "/odm/etc" :

./passwd
./selinux
./selinux/precompiled_sepolicy

Files or directories deleted in the directory "/odm/etc" :

./group


 ----------------------------------------------------------------------
List the changes in the directory "/vendor" ...
There is currently an overlay mounted for the directory "/vendor"
File changes in the directory "/vendor" :

./etc
./etc/vmmgr.conf

Files or directories deleted in the directory "/vendor" :


ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  get /vendor /vendor/etc /vendor/etc/vmmgr.conf  /odm /odm/etc /odm/etc/passwd  /odm/etc/group  /vendor/etc/ueventd.rc /odm/etc/build.prop
/data/local/tmp/ov/upper/vendor # /vendor
/data/local/tmp/ov/upper/vendor/etc # /vendor/etc
/data/local/tmp/ov/upper/vendor/etc/vmmgr.conf # /vendor/etc/vmmgr.conf # the file was changed
# There is no overlay mount active for "/odm" in the backend "/data/local/tmp/ov"
/data/local/tmp/ov/upper/odm#etc # /odm/etc
/data/local/tmp/ov/upper/odm#etc/passwd # /odm/etc/passwd # the file was changed
/data/local/tmp/ov/upper/odm#etc/group # /odm/etc/group # the file/directory was deleted
/data/local/tmp/ov/upper/vendor/etc/ueventd.rc # /vendor/etc/ueventd.rc # the file was not yet changed or deleted
/data/local/tmp/ov/upper/odm#etc/build.prop # /odm/etc/build.prop # the file was not yet changed or deleted

ASUS_I006D:/system_ext #



ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  get /vendor /vendor/etc /vendor/etc/vmmgr.conf  /odm /odm/etc /odm/etc/passwd  /odm/etc/group  /vendor/etc/ueventd.rc /odm/etc/build.prop    --short
/data/local/tmp/ov/upper/vendor
/data/local/tmp/ov/upper/vendor/etc
/data/local/tmp/ov/upper/vendor/etc/vmmgr.conf
# There is no overlay mount active for "/odm" in the backend "/data/local/tmp/ov"
/data/local/tmp/ov/upper/odm#etc
/data/local/tmp/ov/upper/odm#etc/passwd
/data/local/tmp/ov/upper/odm#etc/group
/data/local/tmp/ov/upper/vendor/etc/ueventd.rc
/data/local/tmp/ov/upper/odm#etc/build.prop

ASUS_I006D:/system_ext #


ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  get /vendor /vendor/etc /vendor/etc/vmmgr.conf  /odm /odm/etc /odm/etc/passwd  /odm/etc/group  /vendor/etc/ueventd.rc /odm/etc/build.prop    --details
drwxr-xr-x 3 root shell u:object_r:vendor_file:s0  1024 2025-06-18 15:28 /data/local/tmp/ov/upper/vendor # /vendor
drwxr-xr-x 2 root shell u:object_r:vendor_configs_file:s0  1024 2025-06-18 15:01 /data/local/tmp/ov/upper/vendor/etc # /vendor/etc
-rw-r--r-- 1 root root u:object_r:vendor_configs_file:s0  25 2025-06-18 15:27 /data/local/tmp/ov/upper/vendor/etc/vmmgr.conf # /vendor/etc/vmmgr.conf # the file was changed
# There is no overlay mount active for "/odm" in the backend "/data/local/tmp/ov"
drwxr-xr-x 3 root root u:object_r:vendor_configs_file:s0  1024 2025-06-18 15:33 /data/local/tmp/ov/upper/odm#etc # /odm/etc
-rw-r--r-- 1 root root u:object_r:vendor_configs_file:s0  0 2025-06-18 15:33 /data/local/tmp/ov/upper/odm#etc/passwd # /odm/etc/passwd # the file was changed
c--------- 1 root root u:object_r:vendor_configs_file:s0  0,   0 2025-06-18 15:33 /data/local/tmp/ov/upper/odm#etc/group # /odm/etc/group # the file/directory was deleted
/data/local/tmp/ov/upper/vendor/etc/ueventd.rc # /vendor/etc/ueventd.rc # the file was not yet changed or deleted
/data/local/tmp/ov/upper/odm#etc/build.prop # /odm/etc/build.prop # the file was not yet changed or deleted

ASUS_I006D:/system_ext #



ASUS_I006D:/data/local/tmp # /data/local/tmpo/create_overlay_mount.sh  get /vendor /vendor/etc /vendor/etc/vmmgr.conf  /odm /odm/etc /odm/etc/passwd  /odm/etc/group  /vendor/etc/ueventd.rc /odm/etc/build.prop    --details --short 
drwxr-xr-x 3 root shell u:object_r:vendor_file:s0  1024 2025-06-18 15:28 /data/local/tmp/ov/upper/vendor
drwxr-xr-x 2 root shell u:object_r:vendor_configs_file:s0  1024 2025-06-18 15:01 /data/local/tmp/ov/upper/vendor/etc
-rw-r--r-- 1 root root u:object_r:vendor_configs_file:s0  25 2025-06-18 15:27 /data/local/tmp/ov/upper/vendor/etc/vmmgr.conf
# There is no overlay mount active for "/odm" in the backend "/data/local/tmp/ov"
drwxr-xr-x 3 root root u:object_r:vendor_configs_file:s0  1024 2025-06-18 15:33 /data/local/tmp/ov/upper/odm#etc
-rw-r--r-- 1 root root u:object_r:vendor_configs_file:s0  0 2025-06-18 15:33 /data/local/tmp/ov/upper/odm#etc/passwd
c--------- 1 root root u:object_r:vendor_configs_file:s0  0,   0 2025-06-18 15:33 /data/local/tmp/ov/upper/odm#etc/group
/data/local/tmp/ov/upper/vendor/etc/ueventd.rc
/data/local/tmp/ov/upper/odm#etc/build.prop

ASUS_I006D:/system_ext #


----



To umount all overlay mounts created by the script use the parameter umount

/data/local/tmp/create_overlay_mount.sh umount
ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh umount
Umounting the bind mounts ...
Umounting "/system_ext" ...
Umounting "/vendor" ...
Umounting "/product" ...
Umounting "/odm" ...
Umounting "/system" ...
 ... done
Umounting the overlay mounts ...
Umounting "/data/local/tmp/ov/merged/system_ext" ...
Umounting "/data/local/tmp/ov/merged/vendor" ...
Umounting "/data/local/tmp/ov/merged/product" ...
Umounting "/data/local/tmp/ov/merged/odm" ...
Umounting "/data/local/tmp/ov/merged/system" ...
 ... done

ASUS_I006D:/ #

----

Note that umounting /system may fail -- see below for a workaround for this problem.


To umount only the overlays of the directories /product and /odm use this command:

/data/local/tmp/create_overlay_mount.sh  umount /product /odm
ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh /odm /product umount
Umounting the bind mounts ...
Umounting "/odm" ...
Umounting "/product" ...
 ... done
Umounting the overlay mounts ...
Umounting "/data/local/tmp/ov/merged/odm" ...
Umounting "/data/local/tmp/ov/merged/product" ...
 ... done

ASUS_I006D:/data/local/tmp #


----




To check the contents of the virtual disk used as backend without creating the overlay mounts use the parameter mount_only:

/data/local/tmp/create_overlay_mount.sh mount_only
# create some test files

ASUS_I006D:/ # for i in /system /system_ext /vendor /product /odm/ /vendor_dlkm/etc ; do touch $i/test.$$ ; ls -l $i/test.$$ ; done
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /system/test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /system_ext/test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /vendor/test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /product/test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /odm//test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /vendor_dlkm/etc/test.5491

# and reboot the phone

ASUS_I006D:/ # reboot
...

# execute in an adb shell after the reboot

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh mount_only
Creating the loop device for the file "/data/local/tmp/image001" ....
The image file already exists - there should already be a filesystem
Mounting the loop device "/dev/block/loop31" to "/data/local/tmp/ov" ...

The virtual disk is mounted to "/data/local/tmp/ov"

ASUS_I006D:/ #

The new files are in the sub directory ./upper:

ASUS_I006D:/ # ls -l /data/local/tmp/ov/upper/*/*
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /data/local/tmp/ov/upper/odm/test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /data/local/tmp/ov/upper/product/test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /data/local/tmp/ov/upper/system/test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /data/local/tmp/ov/upper/system_ext/test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /data/local/tmp/ov/upper/vendor/test.5491
-rw-r--r-- 1 root root 0 2025-03-15 21:01 /data/local/tmp/ov/upper/vendor_dlkm#etc/test.5491
ASUS_I006D:/ #


----



To create a new virtual disk /data/local/tmp/image001_ext3 with 50 MB and ext3 filesystem without creating any overlay filesystem use this command:

/data/local/tmp/create_overlay_mount.sh IMAGE_FILE=/data/local/tmp/image001_ext3 FILESYSTEM_TO_USE=ext3 FILESYSTEM_SIZE=50m BASEDIR=/data/local/tmp/ovtest mount_only

ASUS_I006D:/ #  /data/local/tmp/create_overlay_mount.sh IMAGE_FILE=/data/local/tmp/image001_ext3 FILESYSTEM_TO_USE=ext3 FILESYSTEM_SIZE=50m BASEDIR=/data/local/tmp/ovtest mount_only
Creating the image file "/data/local/tmp/image001_ext3" with the size 50m ...
1+0 records in
1+0 records out
52428800 bytes (50 M) copied, 0.056713 s, 882 M/s
Creating a "ext3" filesystem on the image file "/data/local/tmp/image001_ext3" now ...
mke2fs 1.46.2 (28-Feb-2021)
Discarding device blocks: done                           
Creating filesystem with 51200 1k blocks and 12824 inodes
Filesystem UUID: e5433d8e-da14-4ca5-bae1-1c7a7b13382c
Superblock backups stored on blocks:
    8193, 24577, 40961

Allocating group tables: done                           
Writing inode tables: done                           
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

Creating the directory "/data/local/tmp/ovtest" ...
Mounting the imagefile "/data/local/tmp/image001_ext3" to "/data/local/tmp/ovtest" ...

The virtual disk is mounted to "/data/local/tmp/ovtest"

ASUS_I006D:/ #


----


To use the file /data/local/tmp/image001_ext3 for overlay mounts later use:

/data/local/tmp/create_overlay_mount.sh IMAGE_FILE=/data/local/tmp/image001_ext3  BASEDIR=/data/local/tmp/ovtest  /odm /odm_dlkm
ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh IMAGE_FILE=/data/local/tmp/image001_ext3  BASEDIR=/data/local/tmp/ovtest  /odm /odm_dlkm
The image file "/data/local/tmp/image001_ext3" already exists - there should already be a filesystem
Creating the directory "/data/local/tmp/ovtest/upper" ...
Creating the directory "/data/local/tmp/ovtest/merged" ...
Creating the directory "/data/local/tmp/ovtest/work" ...

Creating and mounting the directories for the overlay mount for "/odm" ...
Creating the directory "/data/local/tmp/ovtest/upper/odm" ...
Creating the directory "/data/local/tmp/ovtest/merged/odm" ...
Creating the directory "/data/local/tmp/ovtest/work/odm" ...
Creating the overlay mount for "/odm" ...
Creating the bind mount "/odm"...
Checking the overlay mount for "/odm" ...

Creating and mounting the directories for the overlay mount for "/odm_dlkm" ...
Creating the directory "/data/local/tmp/ovtest/upper/odm_dlkm" ...
Creating the directory "/data/local/tmp/ovtest/merged/odm_dlkm" ...
Creating the directory "/data/local/tmp/ovtest/work/odm_dlkm" ...
Creating the overlay mount for "/odm_dlkm" ...
Creating the bind mount "/odm_dlkm"...
Checking the overlay mount for "/odm_dlkm" ...

Summary:
--------

2 overlay mount(s) created:

  /odm
  /odm_dlkm

ASUS_I006D:/data/local/tmp #


----



To use different virtual disks in parallel the variable BASEDIR must also be different:

Example for using multiple virtual disks
ASUS_I006D:/data/local/tmp #  IMAGE_FILE=/data/local/tmp/virtualdisk001 BASEDIR=/data/local/tmp/virtualfs001 ./create_overlay_mount.sh /vendor /vendor_dlkm
Creating the image file "/data/local/tmp/virtualdisk001" with the size 100m ...
1+0 records in
1+0 records out
104857600 bytes (100 M) copied, 0.084065 s, 1.1 G/s
Creating a "ext4" filesystem on the image file "/data/local/tmp/virtualdisk001" now ...
mke2fs 1.46.2 (28-Feb-2021)
Discarding device blocks: done                           
Creating filesystem with 102400 1k blocks and 25688 inodes
Filesystem UUID: 6bf0e517-3da8-4813-b463-b49b63eaedfd
Superblock backups stored on blocks:
    8193, 24577, 40961, 57345, 73729

Allocating group tables: done                           
Writing inode tables: done                           
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

Creating the directory "/data/local/tmp/virtualfs001" ...
Mounting the imagefile "/data/local/tmp/virtualdisk001" to "/data/local/tmp/virtualfs001" ...
Creating the directory "/data/local/tmp/virtualfs001/upper" ...
Creating the directory "/data/local/tmp/virtualfs001/merged" ...
Creating the directory "/data/local/tmp/virtualfs001/work" ...

Creating and mounting the directories for the overlay mount for "/vendor" ...
Creating the directory "/data/local/tmp/virtualfs001/upper/vendor" ...
Creating the directory "/data/local/tmp/virtualfs001/merged/vendor" ...
Creating the directory "/data/local/tmp/virtualfs001/work/vendor" ...
Creating the overlay mount for "/vendor" ...
Creating the bind mount "/vendor"...
Checking the overlay mount for "/vendor" ...

Creating and mounting the directories for the overlay mount for "/vendor_dlkm" ...
Creating the directory "/data/local/tmp/virtualfs001/upper/vendor_dlkm" ...
Creating the directory "/data/local/tmp/virtualfs001/merged/vendor_dlkm" ...
Creating the directory "/data/local/tmp/virtualfs001/work/vendor_dlkm" ...
Creating the overlay mount for "/vendor_dlkm" ...
Creating the bind mount "/vendor_dlkm"...
Checking the overlay mount for "/vendor_dlkm" ...

Summary:
--------

2 overlay mount(s) created:

  /vendor
  /vendor_dlkm

ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp #  IMAGE_FILE=/data/local/tmp/virtualdisk002 BASEDIR=/data/local/tmp/virtualfs002 ./create_overlay_mount.sh /odm /odm_dlkm
Creating the image file "/data/local/tmp/virtualdisk002" with the size 100m ...
1+0 records in
1+0 records out
104857600 bytes (100 M) copied, 0.083999 s, 1.1 G/s
Creating a "ext4" filesystem on the image file "/data/local/tmp/virtualdisk002" now ...
mke2fs 1.46.2 (28-Feb-2021)
Discarding device blocks: done                           
Creating filesystem with 102400 1k blocks and 25688 inodes
Filesystem UUID: 891ce037-082c-49a8-9828-4f26f9b8dba2
Superblock backups stored on blocks:
    8193, 24577, 40961, 57345, 73729

Allocating group tables: done                           
Writing inode tables: done                           
Creating journal (4096 blocks): done
Writing superblocks and filesystem accounting information: done

Creating the directory "/data/local/tmp/virtualfs002" ...
Mounting the imagefile "/data/local/tmp/virtualdisk002" to "/data/local/tmp/virtualfs002" ...
Creating the directory "/data/local/tmp/virtualfs002/upper" ...
Creating the directory "/data/local/tmp/virtualfs002/merged" ...
Creating the directory "/data/local/tmp/virtualfs002/work" ...

Creating and mounting the directories for the overlay mount for "/odm" ...
Creating the directory "/data/local/tmp/virtualfs002/upper/odm" ...
Creating the directory "/data/local/tmp/virtualfs002/merged/odm" ...
Creating the directory "/data/local/tmp/virtualfs002/work/odm" ...
Creating the overlay mount for "/odm" ...
Creating the bind mount "/odm"...
Checking the overlay mount for "/odm" ...

Creating and mounting the directories for the overlay mount for "/odm_dlkm" ...
Creating the directory "/data/local/tmp/virtualfs002/upper/odm_dlkm" ...
Creating the directory "/data/local/tmp/virtualfs002/merged/odm_dlkm" ...
Creating the directory "/data/local/tmp/virtualfs002/work/odm_dlkm" ...
Creating the overlay mount for "/odm_dlkm" ...
Creating the bind mount "/odm_dlkm"...
Checking the overlay mount for "/odm_dlkm" ...

Summary:
--------

2 overlay mount(s) created:

  /odm
  /odm_dlkm

ASUS_I006D:/data/local/tmp #
ASUS_I006D:/data/local/tmp #
ASUS_I006D:/data/local/tmp # ./create_overlay_mount.sh list --details
Directories mounted on an overlay filesystem

Directory         Backend Directory
---------         -----------------
/vendor           /data/local/tmp/virtualfs001 (Virtual disk: /data/local/tmp/virtualdisk001)
/vendor_dlkm      /data/local/tmp/virtualfs001 (Virtual disk: /data/local/tmp/virtualdisk001)
/odm              /data/local/tmp/virtualfs002 (Virtual disk: /data/local/tmp/virtualdisk002)
/odm_dlkm         /data/local/tmp/virtualfs002 (Virtual disk: /data/local/tmp/virtualdisk002)

ASUS_I006D:/data/local/tmp #

----

 
Note that in this case you must always use BASEDIR=<base_directory> and, for some commands IMAGE_FILE=<image_file>, to process the overlay mounts (e.g. for the actions undo, umount, diff, etc). Therefore it's recommended to create different wrapper scripts for using multiple virtual disks.

This feature can be used, for example, to create different test environments.


The script can also be used to create overlay mounts for sub directories, e.g. to create overlay filesystems for the directories /*/etc and the directory /system_ext/framework do

/data/local/tmp/create_overlay_mount.sh /*/etc /system_ext/framework
ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  /*/etc /system_ext/framework
The image file "/data/local/tmp/image001" already exists - there should already be a filesystem
Mounting the imagefile "/data/local/tmp/image001" to "/data/local/tmp/ov" ...

Creating and mounting the directories for the overlay mount for "/odm/etc" ...
Creating the directory "/data/local/tmp/ov/upper/odm#etc" ...
Creating the directory "/data/local/tmp/ov/merged/odm#etc" ...
Creating the directory "/data/local/tmp/ov/work/odm#etc" ...
Creating the overlay mount for "/odm/etc" ...
Creating the bind mount "/odm/etc"...
Checking the overlay mount for "/odm/etc" ...

Creating and mounting the directories for the overlay mount for "/odm_dlkm/etc" ...
ERROR: The directory "/odm_dlkm/etc" does NOT exist -- ignored

Creating and mounting the directories for the overlay mount for "/product/etc" ...
Creating the directory "/data/local/tmp/ov/upper/product#etc" ...
Creating the directory "/data/local/tmp/ov/merged/product#etc" ...
Creating the directory "/data/local/tmp/ov/work/product#etc" ...
Creating the overlay mount for "/product/etc" ...
Creating the bind mount "/product/etc"...
Checking the overlay mount for "/product/etc" ...

Creating and mounting the directories for the overlay mount for "/system/etc" ...
Creating the directory "/data/local/tmp/ov/upper/system#etc" ...
Creating the directory "/data/local/tmp/ov/merged/system#etc" ...
Creating the directory "/data/local/tmp/ov/work/system#etc" ...
Creating the overlay mount for "/system/etc" ...
Creating the bind mount "/system/etc"...
Checking the overlay mount for "/system/etc" ...
WARNING: Seems like the overlay mount for "/system/etc" works only partial -- please check the directory contents

Creating and mounting the directories for the overlay mount for "/system_ext/etc" ...
Creating the directory "/data/local/tmp/ov/upper/system_ext#etc" ...
Creating the directory "/data/local/tmp/ov/merged/system_ext#etc" ...
Creating the directory "/data/local/tmp/ov/work/system_ext#etc" ...
Creating the overlay mount for "/system_ext/etc" ...
Creating the bind mount "/system_ext/etc"...
Checking the overlay mount for "/system_ext/etc" ...

Creating and mounting the directories for the overlay mount for "/vendor/etc" ...
Creating the directory "/data/local/tmp/ov/upper/vendor#etc" ...
Creating the directory "/data/local/tmp/ov/merged/vendor#etc" ...
Creating the directory "/data/local/tmp/ov/work/vendor#etc" ...
Creating the overlay mount for "/vendor/etc" ...
Creating the bind mount "/vendor/etc"...
Checking the overlay mount for "/vendor/etc" ...

Creating and mounting the directories for the overlay mount for "/vendor_dlkm/etc" ...
Creating the overlay mount for "/vendor_dlkm/etc" ...
Creating the bind mount "/vendor_dlkm/etc"...
Checking the overlay mount for "/vendor_dlkm/etc" ...

Creating and mounting the directories for the overlay mount for "/system_ext/framework" ...
Creating the directory "/data/local/tmp/ov/upper/system_ext#framework" ...
Creating the directory "/data/local/tmp/ov/merged/system_ext#framework" ...
Creating the directory "/data/local/tmp/ov/work/system_ext#framework" ...
Creating the overlay mount for "/system_ext/framework" ...
Creating the bind mount "/system_ext/framework"...
Checking the overlay mount for "/system_ext/framework" ...

Summary:
--------

7 overlay mount(s) created:

  /odm/etc
  /product/etc
  /system/etc
  /system_ext/etc
  /vendor/etc
  /vendor_dlkm/etc
  /system_ext/framework

1 directory(s) missing:

  /odm_dlkm/etc

ASUS_I006D:/data/local/tmp #

see below for the reason for the warning message: WARNING: Seems like the overlay mount for "/system/etc" works only partial -- please check the directory contents
----


 


To list the file changes for a directory with overlay mount use the parameter diff, e.g. to list all changes for the directories /odm_dlkm and /system:

/data/local/tmp/create_overlay_mount.sh diff /odm_dlkm /system

----
commands to create the test environment
# instructions to create the test env
#
 mkdir /odm_dlkm/testdir
 touch /odm_dlkm/testdir/testfile1
 touch /odm_dlkm/testdir/testfile2
 touch /odm_dlkm/testfile0
 rm  /odm_dlkm/etc
----

ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  diff /odm_dlkm /system
List the changes in the directories ...

 ----------------------------------------------------------------------
List the changes in the directory "/odm_dlkm" ...
There is currently an overlay mounted for the directory "/odm_dlkm"
File changes in the directory "/odm_dlkm" :

./testdir
./testdir/testfile1
./testdir/testfile2
./testfile0

Files or directories deleted in the directory "/odm_dlkm" :

./etc


 ----------------------------------------------------------------------
List the changes in the directory "/system" ...
There is currently no overlay mounted for the directory "/system"
File changes in the directory "/system" :

./bin
./bin/0001logcatboot
./bin/configure_microg.sh
./bin/correct_dev_pn553.sh
./bin/disable_intent_filter_verification.sh
./bin/enable_microg.sh
./bin/enable_wifi.sh
./bin/enable_wireless_adb.sh
./bin/install_apk.sh
./bin/install_mm.sh
./bin/list_bind_mounts.sh
./bin/list_logical_device_backends.sh
./bin/list_logical_device_usage.sh
./bin/list_magisk_root_permissions.sh
./bin/list_magisk_settings.sh
./bin/lmm
./bin/myldd
./bin/rcbm.sh
./bin/recreate_bind_mount.sh
./bin/remount_dynamic_partitions.sh
./bin/remove_screenlock.sh
./bin/rename_apk.sh
./bin/search_magisk_package.sh
./bin/setpath.sh
./bin/sudo
./bin/switch_adb_via_wifi.sh

Files or directories deleted in the directory "/system" :



ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  diff /odm_dlkm /system --details
SELinux is currently enabled
List the changes in the directories ...

 ----------------------------------------------------------------------
List the changes in the directory "/odm_dlkm" ...
There is currently an overlay mounted for the directory "/odm_dlkm"
File changes in the directory "/odm_dlkm" :

drwxr-xr-x 3 root root u:object_r:vendor_file:s0  1024 2025-06-17 08:59 ./testdir
-rw-r--r-- 1 root root u:object_r:vendor_file:s0     0 2025-06-17 08:59 ./testdir/testfile1
drwxr-xr-x 2 root root u:object_r:vendor_file:s0  1024 2025-06-17 09:00 ./testdir/testfile2
-rw-r--r-- 1 root root u:object_r:vendor_file:s0     0 2025-06-17 09:00 ./testfile0

Files or directories deleted in the directory "/odm_dlkm" :

./etc


 ----------------------------------------------------------------------
List the changes in the directory "/system" ...
There is currently no overlay mounted for the directory "/system"
File changes in the directory "/system" :

drwxr-x--x 2 root shell u:object_r:system_file:s0   1024 2025-06-16 21:04 ./bin
-rwxr-xr-x 1 root root  u:object_r:system_file:s0    156 2025-06-16 21:04 ./bin/0001logcatboot
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   2919 2025-06-16 21:04 ./bin/configure_microg.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0    354 2025-06-16 21:04 ./bin/correct_dev_pn553.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0     51 2025-06-16 21:04 ./bin/disable_intent_filter_verification.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0    146 2025-06-16 21:04 ./bin/enable_microg.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   2956 2025-06-16 21:04 ./bin/enable_wifi.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0  22230 2025-06-16 21:04 ./bin/enable_wireless_adb.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0  10108 2025-06-16 21:04 ./bin/install_apk.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0  16046 2025-06-16 21:04 ./bin/install_mm.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   4432 2025-06-16 21:04 ./bin/list_bind_mounts.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   7271 2025-06-16 21:04 ./bin/list_logical_device_backends.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   9463 2025-06-16 21:04 ./bin/list_logical_device_usage.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0    223 2025-06-16 21:04 ./bin/list_magisk_root_permissions.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0    449 2025-06-16 21:04 ./bin/list_magisk_settings.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0  19701 2025-06-16 21:04 ./bin/lmm
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   1038 2025-06-16 21:04 ./bin/myldd
lrwxrwxrwx 1 root root  u:object_r:system_file:s0     24 2025-06-16 21:04 ./bin/rcbm.sh -> ./recreate_bind_mount.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   3774 2025-06-16 21:04 ./bin/recreate_bind_mount.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0  16866 2025-06-16 21:04 ./bin/remount_dynamic_partitions.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0     69 2025-06-16 21:04 ./bin/remove_screenlock.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   2708 2025-06-16 21:04 ./bin/rename_apk.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   1434 2025-06-16 21:04 ./bin/search_magisk_package.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0     42 2025-06-16 21:04 ./bin/setpath.sh
-rwxr-xr-x 1 root root  u:object_r:system_file:s0     13 2025-06-16 21:04 ./bin/sudo
-rwxr-xr-x 1 root root  u:object_r:system_file:s0   5273 2025-06-16 21:04 ./bin/switch_adb_via_wifi.sh

Files or directories deleted in the directory "/system" :



ASUS_I006D:/data/local/tmp #



----

The default directory list for the action diff is the list of directories in the variable DIRS_TO_OVERLAY.  Use the options --active to list only the changes in all mounted overlay filesystems:


/data/local/tmp/create_overlay_mount.sh  diff --active
ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  list
Directories mounted on an overlay filesystem

/odm/etc
/vendor


ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  diff --active
List the changes in the directories ...

 ----------------------------------------------------------------------
List the changes in the directory "/odm/etc" ...
There is currently an overlay mounted for the directory "/odm/etc"
File changes in the directory "/odm/etc" :

./passwd
./selinux

Files or directories deleted in the directory "/odm/etc" :

./group


 ----------------------------------------------------------------------
List the changes in the directory "/vendor" ...
There is currently an overlay mounted for the directory "/vendor"
File changes in the directory "/vendor" :

./etc
./etc/vmmgr.conf

Files or directories deleted in the directory "/vendor" :



ASUS_I006D:/data/local/tmp #

----




To undo all changes for a directory with an overlay mount use the parameter undo, e.g. to undo all changes in the directory /system execute:

/data/local/tmp/create_overlay_mount.sh undo /system
ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  undo /system
Undoing the change in the directories ...
Undoing the changes for the directory "/system" ...

ASUS_I006D:/data/local/tmp #

----


To undo all the changes for all directories currently mounted on overlay filesystems do:

/data/local/tmp/create_overlay_mount.sh  undo
ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh  undo
Undoing the change in the directories ...
Undoing the changes for the directory "/system_ext" ...
Undoing the changes for the directory "/product" ...
Undoing the changes for the directory "/odm" ...
Undoing the changes for the directory "/system" ...

ASUS_I006D:/data/local/tmp #

----

Note that there is no redo.




To undo the changes only for specific files use the parameter restore:

/data/local/tmp/create_overlay_mount.sh restore /system/etc/hosts
ASUS_I006D:/data/local/tmp # cat /system/etc/hosts
127.0.0.1       localhost
::1             ip6-localhost
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # echo "1.1.1.1 dnsserver" >>/system/etc/hosts
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # cat /system/etc/hosts                                                                                                                                                 
127.0.0.1       localhost
::1             ip6-localhost
1.1.1.1 dnsserver
ASUS_I006D:/data/local/tmp #


ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh restore /system/etc/hosts
Deleting the files "/data/local/tmp/ov/upper/system/etc/hosts" and "/data/local/tmp/ov/merged/system/etc/hosts" ...
Restoring the file "/system/etc/hosts" ...

ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # cat /system/etc/hosts
127.0.0.1       localhost
::1             ip6-localhost
ASUS_I006D:/data/local/tmp #



----


To restore a deleted file on a filesystem mount with overlays use the parameter restore :

/data/local/tmp/create_overlay_mount.sh restore /odm/etc/build.prop
ASUS_I006D:/data/local/tmp # ls -l /odm/etc/build.prop
-rw------- 1 root root 999 2009-01-01 01:00 /odm/etc/build.prop
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # rm /odm/etc/build.prop
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # ls -l /odm/etc/build.prop
ls: /odm/etc/build.prop: No such file or directory
1|ASUS_I006D:/data/local/tmp #

1|ASUS_I006D:/data/local/tmp # /data/local/tmp//create_overlay_mount.sh restore /odm/etc/build.prop
Restoring the file "/odm/etc/build.prop" ...

ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # ls -l /odm/etc/build.prop
-rw------- 1 root root 999 2009-01-01 01:00 /odm/etc/build.prop
ASUS_I006D:/data/local/tmp #



----


Other examples for the action restore
commands to create the test environment
/data/local/tmp/create_overlay_mount.sh mount /system/app/EasterEgg

----


ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh diff /system/app/EasterEgg
List the changes in the directories ...

 ----------------------------------------------------------------------
List the changes in the directory "/system/app/EasterEgg" ...
There is currently an overlay mounted for the directory "/system/app/EasterEgg"
File changes in the directory "/system/app/EasterEgg" :


Files or directories deleted in the directory "/system/app/EasterEgg" :



ASUS_I006D:/ #


ASUS_I006D:/ # ls -ld $( find /system/app/EasterEgg )
drwxr-xr-x 1 root root    1024 2025-06-22 13:35 /system/app/EasterEgg
-rw-r--r-- 1 root root 2139850 2009-01-01 01:00 /system/app/EasterEgg/EasterEgg.apk
drwxr-xr-x 3 root root    4096 2009-01-01 01:00 /system/app/EasterEgg/oat
drwxr-xr-x 2 root root    4096 2009-01-01 01:00 /system/app/EasterEgg/oat/arm64
-rw-r--r-- 1 root root   41904 2009-01-01 01:00 /system/app/EasterEgg/oat/arm64/EasterEgg.odex
-rw-r--r-- 1 root root   56904 2009-01-01 01:00 /system/app/EasterEgg/oat/arm64/EasterEgg.vdex
ASUS_I006D:/ #


# delete some files


ASUS_I006D:/ # rm /system/app/EasterEgg/EasterEgg.apk
ASUS_I006D:/ # rm /system/app/EasterEgg/oat/arm64/EasterEgg.odex
ASUS_I006D:/ # rm /system/app/EasterEgg/oat/arm64/EasterEgg.vdex                                                                                                   
ASUS_I006D:/ #

ASUS_I006D:/ # ls -ld $( find /system/app/EasterEgg )                                                                                                                
drwxr-xr-x 1 root root 1024 2025-06-22 13:41 /system/app/EasterEgg
drwxr-xr-x 1 root root 1024 2009-01-01 01:00 /system/app/EasterEgg/oat
drwxr-xr-x 1 root root 1024 2025-06-22 13:41 /system/app/EasterEgg/oat/arm64
ASUS_I006D:/ #


# restore a file

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh restore /system/app/EasterEgg/EasterEgg.apk
Restoring the file "/system/app/EasterEgg/EasterEgg.apk" ...

ASUS_I006D:/ #

ASUS_I006D:/ # ls -ld $( find /system/app/EasterEgg )                                                                                                                
drwxr-xr-x 1 root root    1024 2025-06-22 13:42 /system/app/EasterEgg
-rw-r--r-- 1 root root 2139850 2009-01-01 01:00 /system/app/EasterEgg/EasterEgg.apk
drwxr-xr-x 1 root root    1024 2009-01-01 01:00 /system/app/EasterEgg/oat
drwxr-xr-x 1 root root    1024 2025-06-22 13:41 /system/app/EasterEgg/oat/arm64
ASUS_I006D:/ #


# restore all  files in a directory

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh restore /system/app/EasterEgg/oat
Restoring the directory "/system/app/EasterEgg/oat" ...

ASUS_I006D:/ #

ASUS_I006D:/ # ls -ld $( find /system/app/EasterEgg )                                                                                                                
drwxr-xr-x 1 root root    1024 2025-06-22 13:43 /system/app/EasterEgg
-rw-r--r-- 1 root root 2139850 2009-01-01 01:00 /system/app/EasterEgg/EasterEgg.apk
drwxr-xr-x 3 root root    4096 2009-01-01 01:00 /system/app/EasterEgg/oat
drwxr-xr-x 2 root root    4096 2009-01-01 01:00 /system/app/EasterEgg/oat/arm64
-rw-r--r-- 1 root root   41904 2009-01-01 01:00 /system/app/EasterEgg/oat/arm64/EasterEgg.odex
-rw-r--r-- 1 root root   56904 2009-01-01 01:00 /system/app/EasterEgg/oat/arm64/EasterEgg.vdex
ASUS_I006D:/ #


ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh diff /system/app/EasterEgg
List the changes in the directories ...

 ----------------------------------------------------------------------
List the changes in the directory "/system/app/EasterEgg" ...
There is currently an overlay mounted for the directory "/system/app/EasterEgg"
File changes in the directory "/system/app/EasterEgg" :


Files or directories deleted in the directory "/system/app/EasterEgg" :



ASUS_I006D:/ #

# change a file

ASUS_I006D:/ # echo >/system/app/EasterEgg/EasterEgg.apk
ASUS_I006D:/ #

ASUS_I006D:/ # ls -l /system/app/EasterEgg/EasterEgg.apk
-rw-r--r-- 1 root root 1 2025-06-22 13:49 /system/app/EasterEgg/EasterEgg.apk
ASUS_I006D:/ #


ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh restore /system/app/EasterEgg/
"/system/app/EasterEgg" is a directory with an overlay mount -- use the parameter "undo /system/app/EasterEgg" to undo all changes for this directory

ASUS_I006D:/ #

ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh restore /system/app/EasterEgg/EasterEgg.apk
Restoring the file "/system/app/EasterEgg/EasterEgg.apk" ...

ASUS_I006D:/ # ls -l /system/app/EasterEgg/EasterEgg.apk
-rw-r--r-- 1 root root 2139850 2009-01-01 01:00 /system/app/EasterEgg/EasterEgg.apk
ASUS_I006D:/ #

----



In case of an error in a directory with an overlay you may remount the directory using the script parameter remount:

 /data/local/tmp/create_overlay_mount.sh remount /system_ext

ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh remount /system_ext
Remounting the overlay mounts ...
Remounting "/system_ext" ...
 ... done

ASUS_I006D:/data/local/tmp #




----



Environment variables used by the script



The script uses these environment variables:


Variable
Usage
Default value
Comment
IMAGE_FILE file used for the virtual disk
/data/local/tmp/image001

BASEDIR the mount point for the virtual disk /dev/ov

DIRS_TO_OVERLAY the directories for which the script creates an overlay mount /system_ext
/product
/odm
/system

FILESYSTEM_TO_USE the filesystem used on the virtual disk
ext4
must be a filesystem known by the running Android that supports overlay mounts (e.g. ext4 or ext3)

The parameter is only used when creating a new filesystem on the virtual disk.
 
FILESYSTEM_SIZE the size of the virtual disk 100m
the value can be any value that is known by the binary dd for the parameter bs (see the output of "dd --help")

The variable is only used when the virtual disk is created.
MKFS_OPTIONS additional options for the mkfs* command to create the filesysten on the loop device
The variable is only used when the virtual disk is created.
MOUNT_OPTIONS additional options for the mount command to mount the filesystem on the loop device

SELINUX_CONTEXT the SELinux context used for new directories if the script can not read the SELinux context of an existing directory u:object_r:system_file:s0





MOUNT
mount binary to use
$( which mount )

UMOUNT
umount binary to use $( which umount )
LOSETUP
losetup binary to use $( which losetup )
MKFS
mkfs binary to use $( which mkfs.${FILESYSTEM_TO_USE} )
DD
dd binary to use $( which dd )




UMOUNT_WAIT_TIME
time in seconds to wait between umounting the bind mounts and umounting the overlay mounts
0
in some Android versions it's necessary to wait some time between umounting the bind mount andumounting the overlay mount. Set this variable to the number of seconds the script should wait between these umounts.


To change one or more of these variables use either a command like this

IMAGE_FILE="/data/local/tmp/image002" BASEDIR="/data/local/tmp/ov2" create_overlay_mount.sh

or this

create_overlay_mount.sh IMAGE_FILE="/data/local/tmp/image002" BASEDIR="/data/local/tmp/ov2"


Note:

Use

create_overlay_mount.sh vars

to only print the current list of supported environment variables with default values.





The new files created in the directories with overlay mounts can be found in the directory

${BASEDIR}/upper/${DIR_NAME}

e.g.

ASUS_I006D:/data/local/tmp # df -h /odm
Filesystem      Size Used Avail Use% Mounted on
overlay          93M  71K   93M   1% /odm
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # touch /odm/testfile.$$
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # ls -l /odm/testfile.$$                                                                                   
-rw-r--r-- 1 root root 0 2025-06-14 14:13 /odm/testfile.7172
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # ls -l /data/local/tmp/ov/upper/odm/testfile.7172
-rw-r--r-- 1 root root 0 2025-06-14 14:13 /data/local/tmp/ov/upper/odm/testfile.7172
ASUS_I006D:/data/local/tmp #



For sub directories with overlay mounts the directory name in the directory ${BASEDIR}/upper is in the format subir1#subdir2#....#subdirN,

For an overlay mount for /vendor/etc the directory name is vendor#etc:

ASUS_I006D:/data/local/tmp # df -h /vendor
Filesystem      Size Used Avail Use% Mounted on
/dev/block/dm-4 0.9G 983M   29M  98% /vendor
ASUS_I006D:/data/local/tmp #                                                                                                          

ASUS_I006D:/data/local/tmp # df -h /vendor/etc
Filesystem      Size Used Avail Use% Mounted on
overlay          93M  76K   93M   1% /vendor/etc
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # touch /vendor/etc/testfile.$$
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # ls -l /vendor/etc/testfile.$$                                                                            
-rw-r--r-- 1 root root 0 2025-06-14 14:15 /vendor/etc/testfile.7172
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # ls -l /data/local/tmp/ov/upper/vendor\#etc/testfile.7172                                                 
-rw-r--r-- 1 root root 0 2025-06-14 14:15 /data/local/tmp/ov/upper/vendor#etc/testfile.7172
ASUS_I006D:/data/local/tmp #

 

For deleted files or directories a character device with major 0 and minor 0 is created in the directory ./upper, e.g:

ASUS_I006D:/data/local/tmp # rm /vendor/etc/ueventd.rc                                                                                
ASUS_I006D:/data/local/tmp #

ASUS_I006D:/data/local/tmp # ls -l /vendor/etc/ueventd.rc                                                                             
ls: /vendor/etc/ueventd.rc: No such file or directory

1|ASUS_I006D:/data/local/tmp #

1|ASUS_I006D:/data/local/tmp # ls -l /data/local/tmp/ov/upper/vendor\#etc/ueventd.rc                                                  
c--------- 1 root root 0,   0 2025-06-14 14:17 /data/local/tmp/ov/upper/vendor#etc/ueventd.rc
ASUS_I006D:/data/local/tmp #




ext3 and ext4 filesystems can be increased while mounted:

Instructions to increase the virtual disk used as backend
# Note: only the commands in bold are necessary to increase the virtual disk

ASUS_I006D:/ # ls -lh /data/local/tmp/image001
-rw-r--r-- 1 root root 10M 2025-03-15 20:36 /data/local/tmp/image001
ASUS_I006D:/ #

# -> the size of the file used as virtual disk is 10 MB

ASUS_I006D:/ # df -h /data/local/tmp/ov
Filesystem        Size Used Avail Use% Mounted on
/dev/block/loop31 8.6M  39K  8.6M   1% /data/local/tmp/ov
ASUS_I006D:/ #

# increase the size of the file /data/local/tmp/image001 by 50M

ASUS_I006D:/ # dd if=/dev/zero count=1 bs=50m >>/data/local/tmp/image001
1+0 records in
1+0 records out
52428800 bytes (50 M) copied, 0.058147 s, 860 M/s
ASUS_I006D:/ #

ASUS_I006D:/ # ls -lh /data/local/tmp/image001
-rw-r--r-- 1 root root 60M 2025-03-15 20:38 /data/local/tmp/image001
ASUS_I006D:/ #


# -> the size of the file used as virtual disk is now 60 MB

# update the loop device
#
ASUS_I006D:/ # losetup -j /data/local/tmp/image001 -c
ASUS_I006D:/ #

# resize the filesystem on the virtual disk
#
ASUS_I006D:/ # resize2fs /dev/block/loop31
resize2fs 1.46.2 (28-Feb-2021)
Filesystem at /dev/block/loop31 is mounted on /data/local/tmp/ov; on-line resizing required
old_desc_blocks = 1, new_desc_blocks = 1
The filesystem on /dev/block/loop31 is now 61440 (1k) blocks long.

ASUS_I006D:/ #

ASUS_I006D:/ # df -h /data/local/tmp/ov
Filesystem        Size Used Avail Use% Mounted on
/dev/block/loop31  58M  39K   58M   1% /data/local/tmp/ov
ASUS_I006D:/ #



Note:

ext4 filesystem can also be decreased when the filesystem is not mounted but it is not that easy to shrink the file used for the virtual disk.




 
Notes


Run the script only in an adb session as root user -- do not execute it via "su - -c ...." (after creating an overlay mount for /system, the binary su is not available anymore!)


For first tests, I strongly recommend NOT to create an overlay mount for the directory /system:

If something fails when creating an overlay for /system, there is no access to any of the executables and files in /system anymore and a reboot via Android GUI is required to fix that


The script does not support directory names with a hash "#" in the name.


To check, if overlay filesystems are supported in the Android OS use the command:

grep overlay /proc/filesystems

The output should look like this:

ASUS_I006D:/data/local/tmp #  grep overlay /proc/filesystems
nodev    overlay
ASUS_I006D:/data/local/tmp #


Please note that files created with Magisk modules, e.g. in /system/bin, are no longer visible after configuring an overlay mount for /system using the script create_overlay_mount.sh. That's also true for the executable "su" necessary to become root user if Magisk is installed. Therefore, either open enough adb sessions with root access before doing the overlay mount for /system or use a CustomROM with enabled root access.


You can copy the files from the Magisk module to /system after creating an overlay mount for that directory, example:

Copy the files from the Magisk module myscripts to /system:
 
cp -r /data/adb/modules/myscripts/system/* /system 



Another way to work around the problem of the missing su command is to start the sshd as root user on the phone before creating the overlay mount for /system.


Or use a Magisk Module to start the adb daemon as root user (see here or https://xdaforums.com/t/how-to-automatically-start-adbd-as-root-user-after-starting-the-phone.4682701/)


If Magisk is installed, I recommend using the Magisk module for the implementation of overlay mounts, as the overlay mounts are created very early in the boot process in the Magisk module. The overlay mounts created by the Magisk module also do not overwrite bind mounts created by other Magisk modules and "su" via Magisk is still possible in adb sessions when using this Magisk module.


Do not use the Magisk module for the implementation of overlay mounts and the script create_overlay_mount.sh in parallel.



The virtual disk used by the Magisk Module for overlay mounts, /data/adb/overlay, can also be used with the script create_overlay_mount.sh:

IMAGE_FILE=/data/adb/overlay  ./create_overlay_mount.sh  default /vendor_dlkm /odm_dlkm



The script can also run early in the boot process if Magisk (or a similar tool) is installed. E.g. with installed Magisk do:

Copy the script to /data/adb/create_overlay_mount.sh into the directory /data/adb and create a start script in the directory /data/adb/post-fs-data.d:

cat <<EOT >/data/adb/post-fs-data.d/configure_overlay_mounts.sh
exec 2>/cache/confiure_overlay.log 1>&2
/data/adb/create_overlay_mount.sh mount
EOT
chmod 755 /data/adb/post-fs-data.d/configure_overlay_mounts.sh

In this case, the restrictions described above regarding the command "su" and the installed Magisk modules do not apply.

But there maybe other problems using the script this way and therefore it's not recommended (use the Magisk Module for overlay mounts for this purpose)



See here for instructions to manually create an overlay mount in Android.


 

Test Environment



ASUS Zenfone 8 with

/e/ 3.0 (= Android 13)
LineageOS 20 (= Android 13)
LineageOS 21 (= Android 14)
StatixOS v7.10 (= Android 14)
OmniROM 14 (= Android 14)
OmniROM 15 (= Android 15)

Note:

According to ChatGPT the overlay mount functionality does not work on all Android versions (but ChatGTP is sometimes also a great liar ...)



Limitations



Mounts to subdirectories as /vendor/dsp are currently lost after an overlay mount for that directory:

E.g in the OmniROM the contents of these directories in the directory /vendor are temporary "lost" after an overlay mount for /vendor.

ASUS_I006D:/data/local/tmp # df -h | grep " /vendor/"                                                                                                                
/dev/block/sde4   220M 173M   47M  79% /vendor/firmware_mnt
/dev/block/sde9    59M  41M   18M  70% /vendor/dsp
/dev/block/sde5    64M 1.0M   63M   2% /vendor/bt_firmware
/dev/block/sda17  496M 404K  496M   1% /vendor/xrom
ASUS_I006D:/data/local/tmp #


To create overlay mounts for directories with mounted subdirectdories like in /vendor you should create overlay mounts for the subdirectories,e.g.:

/data/local/tmp/create_overlay_mount.sh /vendor/app /vendor/lib64 /vendor/bin


Note:


This restriction does not exist in the Magisk Module for overlay mounts (... but I do not know yet, how it's implemented in that module)




The filesystems vfat and f2fs do not support overlay mounts; there maybe other filesystems also not supporting overlay mounts.



Trouble Shooting




An overlay mount for sub directories like /system_ext/bin or /system/etc may or may not work.

If it does not work, the files in the sub directory with overlay mount do not have any permission, example:

ASUS_I006D:/data/local/tmp # ls -ldZ /system_ext/bin/*
---------- 1 root root  u:object_r:unlabeled:s0   0 1970-01-04 04:35 /system_ext/bin/adb_root
lrwxrwxrwx 1 root root  u:object_r:unlabeled:s0  16 1970-01-04 04:35 /system_ext/bin/bash -> /system/bin/bash
---------- 1 root root  u:object_r:unlabeled:s0   0 1970-01-04 04:35 /system_ext/bin/dpmd
lrwxrwxrwx 1 root root  u:object_r:unlabeled:s0   3 1970-01-04 04:35 /system_ext/bin/eview -> vim
lrwxrwxrwx 1 root root  u:object_r:unlabeled:s0   3 1970-01-04 04:35 /system_ext/bin/evim -> vim
lrwxrwxrwx 1 root root  u:object_r:unlabeled:s0   3 1970-01-04 04:35 /system_ext/bin/ex -> vim
lrwxrwxrwx 1 root root  u:object_r:unlabeled:s0   3 1970-01-04 04:35 /system_ext/bin/gview -> vim
lrwxrwxrwx 1 root root  u:object_r:unlabeled:s0   3 1970-01-04 04:35 /system_ext/bin/gvim -> vim
lrwxrwxrwx 1 root root  u:object_r:unlabeled:s0   3 1970-01-04 04:35 /system_ext/bin/gvimdiff -> vim
---------- 1 root root  u:object_r:unlabeled:s0   0 1970-01-04 04:35 /system_ext/bin/htop
---------- 1 root root  u:object_r:unlabeled:s0   0 1970-01-04 04:35 /system_ext/bin/nano
...

create_overlay_mount.sh prints a warning in this case, example:

WARNING: Seems like the overlay mount for "/system_ext/bin" works only partial -- please check the directory contents


To work around this problem, create an overlay mount for the upper directory (e.g. /system or /system_ext) -- at least in my tests, overlay mounts for these directories have always worked.

In my tests on the different Android versions there were always such errors, but not for the same subdirectories. There is no error message in logcat or dmesg, so I don't know the reason for this error yet.




Umounting /system will fail in most cases due to open files, as the umount command uses libraries from /system/lib64. To "fix" this error, use a statically linked umount binary.

A statically linked umount binary for arm64 CPUs is available here: umount

Either add the statically linked umount binary to a directory in the PATH before /system/bin or set the environment variable UMOUNT before starting the script, e.g:

copy the statically linked umount to /data/local/tmp and execute:


UMOUNT=/data/local/tmp/umount  /data/local/tmp/create_overlay_mount.sh umount /system

or

/data/local/tmp/create_overlay_mount.sh umount /system UMOUNT=/data/local/tmp/umount


If the umount of /system still fails, use a statically linked shell instead of sh.
A statically linked bash binary for arm64 CPUs is available here: bash-static-stripped

Copy the statically linked bash binary to /data/local/tmp and use this command to umount /system:

UMOUNT=/data/local/tmp/umount /data/local/tmp/bash-static-stripped /data/local/tmp/create_overlay_mount.s umount /system


Example

ASUS_I006D:/ # UMOUNT=/data/local/tmp/umount  /data/local/tmp/bash-static-stripped   /data/local/tmp/create_overlay_mount.sh umount /system
Umounting the bind mounts ...
Umounting "/system" ...
 ... done

ASUS_I006D:/ #


It's recommended to change the shebang in the first line in the script create_overlay_mount.sh to use the statically linked bash binary, e.g

ASUS_I006D:/data/local/tmp # diff ./create_overlay_mount.sh.or  ./create_overlay_mount.sh.original
create_overlay_mount.sh.org          create_overlay_mount.sh.original
ASUS_I006D:/data/local/tmp # diff ./create_overlay_mount.sh.original   ./create_overlay_mount.sh                                                                                                                               
--- ./create_overlay_mount.sh.original    2025-06-23 14:38:23.000000000 +0200
+++ ./create_overlay_mount.sh    2025-06-23 14:59:15.979999758 +0200
@@ -1,4 +1,4 @@
-#!/system/bin/sh
+#!/data/local/tmp/bin/bash-static-stripped
 #
 #h#
 #h# create_overlay_mount.sh <VERSION> - create one or more overlay mounts on a device running a rooted Android OS
1|ASUS_I006D:/data/local/tmp #





Use the script parameter -v or --verbose to print more messages


Set the variable TRACE to any string before executing the script to run it with "set -x"



Most problems with overlay mounts are caused by missing or invalid SELinux contexts for the files and directories for which an overlay mount is configured. It is therefore recommended to
temporarily disable SELinux either by using the command

setenforce 0

or use the script parameter "--noselinux"

Start a parallel adb session with the command

logcat | grep denied

or, on the PC, :

adb logcat | grep denied

while testing the overlay mounts.



To access the original files while an overlay mount is in place without umount the overlay mount this approch can be used.

Example:

Read the original /system/etc/hosts after changing the file via overlay mount:


ASUS_I006D:/ # /data/local/tmp/create_overlay_mount.sh get /system
/data/local/tmp/ov/upper/system # /system

ASUS_I006D:/ #

ASUS_I006D:/ # cat /system/etc/hosts
127.0.0.1       localhost
::1             ip6-localhost
ASUS_I006D:/ #

ASUS_I006D:/ # echo "1.1.1.1 dnsserver" >>/system/etc/hosts
ASUS_I006D:/ #

ASUS_I006D:/ # cat /system/etc/hosts
127.0.0.1       localhost
::1             ip6-localhost
1.1.1.1 dnsserver
ASUS_I006D:/ #


# Create a temporary bind mount for / to access the original files

#
ASUS_I006D:/ # mkdir -p /mnt/root
ASUS_I006D:/ #

ASUS_I006D:/ # mount -o bind / /mnt/root
ASUS_I006D:/ #

ASUS_I006D:/ # cat /mnt/root/system/etc/hosts
127.0.0.1       localhost
::1             ip6-localhost
ASUS_I006D:/ #




If the contents of a directory with overlay mount look weird, remount the overlay directory using the script with the parameter "remount" and check the directory contents again.

Example

ASUS_I006D:/data/local/tmp # /data/local/tmp/create_overlay_mount.sh remount system                                                                                                              
Remounting the overlay mounts ...
Remounting "/system" ...
 ... done

ASUS_I006D:/data/local/tmp #


and check again.



Downloads



create_overlay_mount.sh

Statically linked binaries for arm64 CPUs:

umount
bash-static-stripped

mount
losetup

The binaries are also available in an github repository: 

https://github.com/bnsmb/binaries-for-Android




Links

 

The Linux Kernel - overlay filesystems

How to use Overlay FS?

My HowTos for Android



Back to top