aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore100
-rw-r--r--META-INF/com/google/android/update-binary33
-rw-r--r--META-INF/com/google/android/updater-script1
-rw-r--r--README.md23
-rw-r--r--config/fstab.conf4
-rw-r--r--config/main.conf5
-rw-r--r--customize.sh4
-rw-r--r--fstab.sh179
-rw-r--r--module.prop6
-rw-r--r--service.sh53
10 files changed, 408 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..b983ed5
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,100 @@
+release
+# Created by https://www.toptal.com/developers/gitignore/api/linux,windows,macos,vim
+# Edit at https://www.toptal.com/developers/gitignore?templates=linux,windows,macos,vim
+
+### Linux ###
+*~
+
+# temporary files which can be created if a process still has a handle open of a deleted file
+.fuse_hidden*
+
+# KDE directory preferences
+.directory
+
+# Linux trash folder which might appear on any partition or disk
+.Trash-*
+
+# .nfs files are created when an open file is removed but is still being accessed
+.nfs*
+
+### macOS ###
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+### macOS Patch ###
+# iCloud generated files
+*.icloud
+
+### Vim ###
+# Swap
+[._]*.s[a-v][a-z]
+!*.svg # comment out if you don't need vector files
+[._]*.sw[a-p]
+[._]s[a-rt-v][a-z]
+[._]ss[a-gi-z]
+[._]sw[a-p]
+
+# Session
+Session.vim
+Sessionx.vim
+
+# Temporary
+.netrwhist
+# Auto-generated tag files
+tags
+# Persistent undo
+[._]*.un~
+
+### Windows ###
+# Windows thumbnail cache files
+Thumbs.db
+Thumbs.db:encryptable
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+# End of https://www.toptal.com/developers/gitignore/api/linux,windows,macos,vim
+
diff --git a/META-INF/com/google/android/update-binary b/META-INF/com/google/android/update-binary
new file mode 100644
index 0000000..28b48e5
--- /dev/null
+++ b/META-INF/com/google/android/update-binary
@@ -0,0 +1,33 @@
+#!/sbin/sh
+
+#################
+# Initialization
+#################
+
+umask 022
+
+# echo before loading util_functions
+ui_print() { echo "$1"; }
+
+require_new_magisk() {
+ ui_print "*******************************"
+ ui_print " Please install Magisk v20.4+! "
+ ui_print "*******************************"
+ exit 1
+}
+
+#########################
+# Load util_functions.sh
+#########################
+
+OUTFD=$2
+ZIPFILE=$3
+
+mount /data 2>/dev/null
+
+[ -f /data/adb/magisk/util_functions.sh ] || require_new_magisk
+. /data/adb/magisk/util_functions.sh
+[ $MAGISK_VER_CODE -lt 20400 ] && require_new_magisk
+
+install_module
+exit 0
diff --git a/META-INF/com/google/android/updater-script b/META-INF/com/google/android/updater-script
new file mode 100644
index 0000000..11d5c96
--- /dev/null
+++ b/META-INF/com/google/android/updater-script
@@ -0,0 +1 @@
+#MAGISK
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4e82703
--- /dev/null
+++ b/README.md
@@ -0,0 +1,23 @@
+# magisk-fstab
+
+A magisk module to load custom fstab configs on startup.
+
+## Requirements
+
+- Magisk v20.4+
+- Kernel support for filesystems to be mounted
+
+## Installation
+
+Install the release zip in Magisk Manager.
+
+## Usage
+
+1. Adjust the main config in `${MODDIR}/config/main.conf` to your liking. `$MODDIR` is usually `/data/adb/modules/magisk-fstab`.
+2. Place your `fstab` entries in `${MODDIR}/config/fstab.conf`.
+3. Upon every restart, this module will try to perform the actions based on the `fstab` config.
+
+## References
+
+- [Magisk documentation](https://topjohnwu.github.io/Magisk/)
+- [fstab manual](https://man7.org/linux/man-pages/man5/fstab.5.html)
diff --git a/config/fstab.conf b/config/fstab.conf
new file mode 100644
index 0000000..903906d
--- /dev/null
+++ b/config/fstab.conf
@@ -0,0 +1,4 @@
+# Static information about the filesystems.
+# See fstab(5) for details.
+
+# <file system> <dir> <type> <options> <dump> <pass>
diff --git a/config/main.conf b/config/main.conf
new file mode 100644
index 0000000..2acc32f
--- /dev/null
+++ b/config/main.conf
@@ -0,0 +1,5 @@
+# magisk-fstab configuration file
+
+# Options to be injected into `su -c` calls.
+# Typically, `--mount-master` is required for mounts in master namespace.
+su_options="--mount-master"
diff --git a/customize.sh b/customize.sh
new file mode 100644
index 0000000..7e61433
--- /dev/null
+++ b/customize.sh
@@ -0,0 +1,4 @@
+set_perm $MODPATH/service.sh 0 0 0755
+set_perm $MODPATH/fstab.sh 0 0 0755
+set_perm $MODPATH/config/main.conf 0 0 0755
+set_perm $MODPATH/config/fstab.conf 0 0 0755
diff --git a/fstab.sh b/fstab.sh
new file mode 100644
index 0000000..e00dc16
--- /dev/null
+++ b/fstab.sh
@@ -0,0 +1,179 @@
+#!/system/bin/sh
+# fstab.sh
+# Reads an fstab-style config and performs mounts/swapon without touching /etc/fstab.
+# - Messages go to console AND to $LOG_FILE.
+# - Privileged commands (mkdir, mount, swapon) run via: su --mount-master -c "…"
+#
+# Usage: ./fstab.sh path/to/fstab.conf
+# Override log file by exporting LOG_FILE before running.
+
+FSTAB_FILE="$1"
+
+if [ -z "$FSTAB_FILE" ]; then
+ echo "Usage: $0 path/to/fstab.conf"
+ exit 2
+fi
+
+if [ ! -r "$FSTAB_FILE" ]; then
+ echo "File '$FSTAB_FILE' not readable."
+ exit 2
+fi
+
+# Ensure 'su' exists
+if ! command -v su >/dev/null 2>&1; then
+ echo "ERROR: 'su' not found. Cannot perform privileged operations."
+ exit 2
+fi
+
+error_count=0
+line_no=0
+
+# --- logging helpers (both console and file) ---
+log() { echo "$*" | tee -a "$LOG_FILE"; }
+warn() { echo "WARN: $*" | tee -a "$LOG_FILE"; }
+err() { echo "ERROR: $*" | tee -a "$LOG_FILE"; error_count=`expr $error_count + 1`; }
+
+# --- safe single-quoting for building a command string for su -c ---
+shell_quote() {
+ # Output a single-quoted representation of $1, handling internal single quotes
+ # 'abc'd' -> 'abc'"'"'d'
+ printf "'%s'" "$(printf "%s" "$1" | sed "s/'/'\"'\"'/g")"
+}
+
+# --- run a command as root via su --mount-master -c "..." preserving args safely ---
+# Usage: run_root CMD ARG1 ARG2 ...
+run_root() {
+ cmd="$1"; shift
+ # Build a single string: CMD 'ARG1' 'ARG2' ...
+ cmdline=$(shell_quote "$cmd")
+ for a in "$@"; do
+ cmdline="$cmdline $(shell_quote "$a")"
+ done
+ log "RUN (as root): $cmd $*"
+ # Execute
+ su $su_options -c "$cmdline"
+ rc=$?
+ [ $rc -ne 0 ] && err "Command failed (exit $rc): $cmd $*"
+ return $rc
+}
+
+# --- check if a mountpoint is already mounted (no root needed) ---
+is_mounted() {
+ mp="$1"
+ if command -v mountpoint >/dev/null 2>&1; then
+ mountpoint -q "$mp"
+ return $?
+ fi
+ grep -qs " $mp " /proc/mounts
+ return $?
+}
+
+# --- check if swap device is already active (no root needed) ---
+is_swap_active() {
+ spec="$1"
+ if command -v swapon >/dev/null 2>&1; then
+ # Prefer swapon --show if available
+ run_root swapon --show=NAME --noheadings 2>/dev/null | grep -Fxq "$spec" && return 0
+ basename_spec=`basename "$spec"`
+ run_root swapon --show=NAME --noheadings 2>/dev/null | awk -F/ '{print $NF}' | grep -Fxq "$basename_spec" && return 0
+ return 1
+ fi
+ grep -qs "^$spec[[:space:]]" /proc/swaps
+ return $?
+}
+
+# --- process each fstab line ---
+while IFS= read -r rawline || [ -n "$rawline" ]; do
+ line_no=`expr $line_no + 1`
+ line=`echo "$rawline" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'`
+
+ case "$line" in
+ ""|\#*) continue ;;
+ esac
+
+ # spec file vfstype mntops dump pass (default 0 for last two if missing)
+ set -- `echo "$line" | awk '{print $1, $2, $3, $4, ($5? $5:0), ($6? $6:0)}'`
+ fs_spec=$1
+ fs_file=$2
+ fs_vfstype=$3
+ fs_mntops=$4
+ fs_freq=$5
+ fs_pass=$6
+
+ if [ -z "$fs_spec" ] || [ -z "$fs_file" ] || [ -z "$fs_vfstype" ]; then
+ warn "Line $line_no: Invalid entry, skipped."
+ continue
+ fi
+
+ echo "$fs_mntops" | grep -qw noauto && {
+ log "Line $line_no: 'noauto' found, skipping $fs_spec -> $fs_file."
+ continue
+ }
+
+ # --- swap handling ---
+ if [ "$fs_vfstype" = "swap" ]; then
+ if is_swap_active "$fs_spec"; then
+ log "Line $line_no: Swap '$fs_spec' already active — skipped."
+ continue
+ fi
+ if command -v swapon >/dev/null 2>&1; then
+ log "Line $line_no: Activating swap: $fs_spec"
+ if [ "$fs_mntops" = "-" ]; then
+ run_root swapon "$fs_spec" || true
+ else
+ run_root swapon -o "$fs_mntops" "$fs_spec" || true
+ fi
+ else
+ err "Line $line_no: swapon not available."
+ fi
+ continue
+ fi
+
+ # --- bind / rbind mounts ---
+ echo "$fs_mntops" | grep -q bind && {
+ if is_mounted "$fs_file"; then
+ log "Line $line_no: $fs_file already mounted — skipped."
+ continue
+ fi
+ if [ ! -e "$fs_file" ]; then
+ log "Line $line_no: Creating mountpoint $fs_file"
+ run_root mkdir -p "$fs_file" || { err "Line $line_no: mkdir failed for $fs_file"; continue; }
+ fi
+ if echo "$fs_mntops" | grep -qw rbind; then
+ log "Line $line_no: rbind mount: $fs_spec -> $fs_file"
+ run_root mount --rbind "$fs_spec" "$fs_file" || true
+ else
+ log "Line $line_no: bind mount: $fs_spec -> $fs_file"
+ run_root mount --bind "$fs_spec" "$fs_file" || true
+ fi
+ continue
+ }
+
+ # --- regular filesystem mounts ---
+ if is_mounted "$fs_file"; then
+ log "Line $line_no: $fs_file already mounted — skipped."
+ continue
+ fi
+
+ if [ ! -e "$fs_file" ]; then
+ log "Line $line_no: Creating mountpoint $fs_file"
+ run_root mkdir -p "$fs_file" || { err "Line $line_no: mkdir failed"; continue; }
+ fi
+
+ if [ "$fs_mntops" = "-" ]; then
+ log "Line $line_no: Mounting $fs_spec -> $fs_file (type=$fs_vfstype)"
+ run_root mount -t "$fs_vfstype" "$fs_spec" "$fs_file" || true
+ else
+ log "Line $line_no: Mounting $fs_spec -> $fs_file (type=$fs_vfstype, opts=$fs_mntops)"
+ run_root mount -t "$fs_vfstype" -o "$fs_mntops" "$fs_spec" "$fs_file" || true
+ fi
+done < "$FSTAB_FILE"
+
+if [ $error_count -gt 0 ]; then
+ echo "Done: $error_count errors occurred." | tee -a "$LOG_FILE"
+ exit 1
+else
+ echo "Done: all entries processed successfully." | tee -a "$LOG_FILE"
+ exit 0
+fi
+
diff --git a/module.prop b/module.prop
new file mode 100644
index 0000000..068ea02
--- /dev/null
+++ b/module.prop
@@ -0,0 +1,6 @@
+id=magisk-fstab
+name=FSTAB loader
+version=v1.0.0
+versionCode=1
+author=lionheart1810
+description=Loads custom fstab file and performs corresponding actions
diff --git a/service.sh b/service.sh
new file mode 100644
index 0000000..37f50dd
--- /dev/null
+++ b/service.sh
@@ -0,0 +1,53 @@
+#!/system/bin/sh
+# Do NOT assume where your module will be located.
+# ALWAYS use $MODDIR if you need to know where this script and module is placed.
+# This will make sure your module will still work if Magisk changes its mount point in the future
+MODDIR=${0%/*}
+
+export LOG_FILE="${MODDIR}/magisk-fstab.log"
+LOG_MAX_LINES=1000
+
+BOOTWAIT_MAX_COUNT=20
+BOOTWAIT_COUNT_INTERVAL=15s
+
+CONF_MAIN="${MODDIR}/config/main.conf"
+CONF_FSTAB="${MODDIR}/config/fstab.conf"
+
+# Check if configs are readable
+
+if [ ! -r "$CONF_MAIN" ]; then
+ echo "File '$CONF_MAIN' not readable."
+ exit 2
+fi
+
+if [ ! -r "$CONF_FSTAB" ]; then
+ echo "File '$CONF_FSTAB' not readable."
+ exit 2
+fi
+
+# Read main config
+. "${CONF_MAIN}" >> "${LOG_FILE}" 2>&1
+
+# wait for system boot to complete
+bootwait_count=0
+until [[ $(getprop sys.boot_completed) || ${bootwait_count} -ge ${BOOTWAIT_MAX_COUNT} ]]; do
+ sleep ${BOOTWAIT_COUNT_INTERVAL}
+ bootwait_count=$((bootwait_count+1))
+done
+if [ ${bootwait_count} -ge ${BOOTWAIT_MAX_COUNT} ]; then
+ exit 1
+fi
+
+# prevent log file from growing too large
+tail -n "${LOG_MAX_LINES}" "${LOG_FILE}" > "${LOGFILE}.tmp"
+mv "${LOGFILE}.tmp" "${LOG_FILE}"
+
+echo "=== $(date) ===" >> "${LOG_FILE}" 2>&1
+
+if [ -f "${CONF}" ]
+ "${MODDIR}/fstab.sh" "${CONF_FSTAB}" &
+else
+ echo "${CONF} not found." >> "${LOG_FILE}" 2>&1
+fi
+
+wait