From d25d1ac9e53b3333944ef4e18795cf1354c179f0 Mon Sep 17 00:00:00 2001 From: Leonard Kugis Date: Tue, 16 Sep 2025 18:56:22 +0000 Subject: Initial commit --- fstab.sh | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+) create mode 100644 fstab.sh (limited to 'fstab.sh') 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 + -- cgit v1.2.3