Last active
September 27, 2025 06:15
-
-
Save doshiraki/3d3a89993d25b3a9122e1eca72841a53 to your computer and use it in GitHub Desktop.
bash for remount when adb remount fails because permission or read-only.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/system_ext/bin/bash | |
| pwd=$(dirname $0) | |
| cd ${pwd} 2> /dev/null | |
| # toggle_mount.sh: Toggles specified Device Mapper device(s) between read-only (ro) and read-write (rw) on Pixel 7a (LineageOS) | |
| # Usage: | |
| # Single device: toggle_mount <device> <ro|rw> (e.g., toggle_mount system_a rw) | |
| # All system/product/vendor: toggle_mount --all rw | |
| # Features: Compares dmctl table before/after; avoids lsblk; converts multiple devices to rw | |
| # Disclaimer: Feel free to use it at your own discretion and responsibility. | |
| # Move to a safe directory | |
| cd /storage/self/primary || { echo "Error: Cannot access /storage/self/primary"; exit 1; } | |
| # Function to toggle mount mode for a single device | |
| toggle_mount() { | |
| local device="$1" | |
| local mode="$2" | |
| # Validate inputs | |
| [[ -z "$device" ]] && { echo "Error: Device name required"; return 1; } | |
| [[ "$mode" != "ro" && "$mode" != "rw" ]] && { echo "Error: Mode must be 'ro' or 'rw'"; return 1; } | |
| echo "Processing $device (mode: $mode)" | |
| # Get initial table and access info | |
| table_before=$(dmctl table "$device" | tr '\n' ' ') | |
| [[ -z "$table_before" ]] && { echo "Error: No table for $device"; return 1; } | |
| echo " Check: Table: $table_before" | |
| # Check for multiple targets | |
| if [[ $(echo "$table_before" | grep -c "linear") -gt 1 ]]; then | |
| echo " Error: Multiple targets detected for $device" | |
| echo " Table: $table_before" | |
| return 1 | |
| fi | |
| # Parse table | |
| pattern="^.* for ${device}: ([0-9]+)-([0-9]+): (linear), ([0-9]+:[0-9]+) ([0-9]+)" | |
| if echo "$table_before" | grep -qE "${pattern}"; then | |
| table_info=$(echo "$table_before" | sed -E "s/${pattern}/\1 \2 \3 \4 \5/") | |
| read start end target maj_min offset <<< "$table_info" | |
| sectors=$((end - start)) | |
| # Verify sector count | |
| if [[ $sectors -le 0 ]]; then | |
| echo " Error: Invalid sector count ($sectors) for $device" | |
| return 1 | |
| fi | |
| # Use maj:min directly | |
| block_device="$maj_min" | |
| # Build dmctl replace command | |
| cmd="dmctl replace $device" | |
| [[ "$mode" == "ro" ]] && cmd="$cmd -ro" | |
| cmd="$cmd $target $start $sectors $block_device $offset" | |
| echo " Running: $cmd" | |
| # Get mount path | |
| mount_path=$(dmctl getpath "$device") | |
| [[ -z "$mount_path" ]] && { echo "Error: No mount path for $device"; return 1; } | |
| # Show mount status | |
| mount | grep -e "$mount_path " | sed -e "s/$/ -> $cmd/" | |
| # Replace table | |
| $cmd || { echo " Error: Failed to replace table for $device"; return 1; } | |
| # Remount | |
| mount -o "$mode,remount" "$mount_path" || { echo "Error: Failed to remount $mount_path"; return 1; } | |
| # Get table and access info after | |
| table_after=$(dmctl table "$device" | tr '\n' ' ') | |
| # echo " After: Table: $table_after" | |
| # Compare table and access | |
| if [[ "$table_before" == "$table_after" ]]; then | |
| echo " Success: $device is now $mode" | |
| else | |
| echo " Warning: Table changed unexpectedly" | |
| echo " Before: $table_before" | |
| echo " After: $table_after" | |
| return 1 | |
| fi | |
| else | |
| echo "Error: Invalid table format for $device: $table_before" | |
| return 1 | |
| fi | |
| } | |
| # Function to convert all system/product/vendor devices to rw | |
| convert_all_to_rw() { | |
| echo "Converting all system, product, vendor devices to read-write" | |
| local devices | |
| devices=$(dmctl list devices | grep -E 'system|product|vendor' | awk '{print $1}' | grep -v "<empty>") | |
| if [[ -z "$devices" ]]; then | |
| echo "Error: No system, product, or vendor devices found" | |
| return 1 | |
| fi | |
| local success_count=0 | |
| local fail_count=0 | |
| for device in $devices; do | |
| echo -n ">>>" | |
| toggle_mount "$device" "rw" | |
| if [[ $? -eq 0 ]]; then | |
| ((success_count++)) | |
| else | |
| ((fail_count++)) | |
| fi | |
| done | |
| echo "Summary: $success_count devices succeeded, $fail_count devices failed" | |
| [[ $fail_count -eq 0 ]] | |
| } | |
| # Check arguments | |
| if [[ $# -eq 1 && "$1" == "--all" ]]; then | |
| convert_all_to_rw | |
| elif [[ $# -eq 2 ]]; then | |
| toggle_mount "$1" "$2" | |
| else | |
| echo "Usage:" | |
| echo " Single device: $0 <device> <ro|rw> (e.g., $0 system_a rw)" | |
| echo " All devices: $0 --all" | |
| exit 1 | |
| fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://android.stackexchange.com/a/260267/588577
The error "/dev/block/dm-0 is read-only" when attempting to remount /system as read-write (RW) on Android O (e.g., with
mount -o rw,remount /system) occurs because the partition is managed by Device Mapper (dmctl) and locked as read-only due to dm-verity and A/B partitioning. This is common on devices like the Pixel 7a running LineageOS.Cause
Android uses Device Mapper to create virtual block devices (e.g., /dev/block/dm-0 for /system).
dm-verity enforces read-only mounts to ensure system integrity.
Commands like
adb remountormount -o rw,remountfail because the Device Mapper table is set to read-only.Solution
Use
dmctl replaceto Enable Read-WriteThe
dmctltool can modify the Device Mapper table to allow RW access. Below are steps to remount /system (or other partitions like product, vendor) as RW.Prerequisites
Caution: Modifying system partitions is risky. Use at your own risk. Changes revert on reboot.
Steps for a Single Partition
Enter a root shell:
Check the Device Mapper table for the partition (e.g., system_a for /):
Example output:
This shows the start sector (0), size (2410336), target type (linear), block device (259:14), and offset (2048).
Run
dmctl replaceto redefine the partition without the read-only flag:Remount the partition as RW:
Verify the mount is RW:
Expected output includes rw:
Automating for Multiple Partitions
To remount all system-related partitions (system, product, vendor, etc.), use this Bash script:
Usage
Push the script to the device:
Run it:
This processes all system, product, and vendor partitions, making them RW.
Notes