94 lines
4.4 KiB
PowerShell
94 lines
4.4 KiB
PowerShell
# Run this script in an Administrator PowerShell prompt to inspect the Linux ext4
|
|
# superblock on Partition 2 and patch H:\cmdline.txt with 'fsck.repair=yes ro'.
|
|
|
|
$ErrorActionPreference = "Continue"
|
|
|
|
$part1 = Get-Partition -DriveLetter H -ErrorAction SilentlyContinue
|
|
if (-not $part1) {
|
|
Write-Error "Drive H: not found! Make sure the SD card / SSD is inserted and mounted at H:."
|
|
exit 1
|
|
}
|
|
|
|
$diskNum = $part1.DiskNumber
|
|
$disk = Get-Disk -Number $diskNum
|
|
$part2 = Get-Partition -DiskNumber $diskNum -PartitionNumber 2 -ErrorAction SilentlyContinue
|
|
$physDrive = "\\.\PhysicalDrive$diskNum"
|
|
|
|
Write-Host "=== 1. Disk & Partition Summary ===" -ForegroundColor Cyan
|
|
Write-Host ("Disk {0}: {1} ({2}, Bus={3}, Size={4:N2} GB)" -f $diskNum, $disk.FriendlyName, $disk.HealthStatus, $disk.BusType, ($disk.Size / 1GB))
|
|
if ($part2) {
|
|
Write-Host ("Partition 2 (Linux ext4): Offset={0}, Size={1:N2} GB" -f $part2.Offset, ($part2.Size / 1GB))
|
|
|
|
Write-Host "`n=== 2. Reading Partition 2 Ext4 Superblock (Read-Only) ===" -ForegroundColor Cyan
|
|
$pyCode = @"
|
|
import struct, datetime
|
|
p = r'$physDrive'
|
|
offset = $($part2.Offset)
|
|
with open(p, 'rb') as f:
|
|
mbr = f.read(512)
|
|
sig = struct.unpack('<I', mbr[0x1b8:0x1bc])[0]
|
|
f.seek(offset + 1024)
|
|
sb = f.read(1024)
|
|
magic, state, errors = struct.unpack('<HHH', sb[0x38:0x3e])
|
|
mnt_cnt, max_mnt = struct.unpack('<Hh', sb[0x34:0x38])
|
|
last_mnt, last_wrt = struct.unpack('<II', sb[0x2c:0x34])
|
|
last_chk = struct.unpack('<I', sb[0x40:0x44])[0]
|
|
incompat = struct.unpack('<I', sb[0x60:0x64])[0]
|
|
err_cnt = struct.unpack('<I', sb[0x194:0x198])[0]
|
|
first_err_time = struct.unpack('<I', sb[0x198:0x19c])[0]
|
|
last_err_time = struct.unpack('<I', sb[0x1c8:0x1cc])[0]
|
|
fmt = lambda ts: datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') if ts else 'Never'
|
|
print(f' MBR Disk Signature : {sig:08x} (PARTUUID={sig:08x}-02)')
|
|
print(f' Ext4 Magic : 0x{magic:04x} (Valid={magic == 0xef53})')
|
|
print(f' Filesystem State : {state} (1=Clean, 2=ERRORS_DETECTED, 4=Orphan_Recovery)')
|
|
print(f' Journal Dirty Bit : {bool(incompat & 0x4)} (INCOMPAT_RECOVER)')
|
|
print(f' Recorded FS Errors : {err_cnt} (First: {fmt(first_err_time)}, Last: {fmt(last_err_time)})')
|
|
print(f' Errors Behavior : {errors} (1=Continue, 2=Remount-RO, 3=Panic)')
|
|
print(f' Mount Count : {mnt_cnt} / {max_mnt}')
|
|
print(f' Last Mount Time : {fmt(last_mnt)}')
|
|
print(f' Last Write Time : {fmt(last_wrt)}')
|
|
print(f' Last Fsck Time : {fmt(last_chk)}')
|
|
"@
|
|
python -c $pyCode
|
|
}
|
|
|
|
Write-Host "`n=== 3. Verifying & Patching H:\cmdline.txt with 'fsck.repair=yes ro' ===" -ForegroundColor Cyan
|
|
$cmdlinePath = "H:\cmdline.txt"
|
|
if (Test-Path $cmdlinePath) {
|
|
$orig = (Get-Content $cmdlinePath -Raw).Trim()
|
|
Write-Host " Current H:\cmdline.txt: $orig"
|
|
$tokens = [System.Collections.Generic.List[string]]($orig -split '\s+')
|
|
$changed = $false
|
|
if ($tokens.Contains("rw")) {
|
|
$null = $tokens.Remove("rw")
|
|
$changed = $true
|
|
}
|
|
if (-not $tokens.Contains("fsck.repair=yes")) {
|
|
$idx = $tokens.FindIndex({ param($t) $t.StartsWith("rootfstype=") })
|
|
if ($idx -ge 0) { $tokens.Insert($idx + 1, "fsck.repair=yes") } else { $tokens.Add("fsck.repair=yes") }
|
|
$changed = $true
|
|
}
|
|
if (-not $tokens.Contains("fsck.mode=force")) {
|
|
$idx = $tokens.IndexOf("fsck.repair=yes")
|
|
if ($idx -ge 0) { $tokens.Insert($idx + 1, "fsck.mode=force") } else { $tokens.Add("fsck.mode=force") }
|
|
$changed = $true
|
|
}
|
|
if (-not $tokens.Contains("ro")) {
|
|
$idx = $tokens.IndexOf("rootwait")
|
|
if ($idx -ge 0) { $tokens.Insert($idx, "ro") } else { $tokens.Add("ro") }
|
|
$changed = $true
|
|
}
|
|
if ($changed) {
|
|
Copy-Item $cmdlinePath "H:\cmdline.txt.bak" -Force
|
|
$newCmdline = ($tokens -join " ") + "`n"
|
|
[System.IO.File]::WriteAllText($cmdlinePath, $newCmdline, (New-Object System.Text.UTF8Encoding($false)))
|
|
Write-Host " Patched H:\cmdline.txt: $($newCmdline.Trim())" -ForegroundColor Green
|
|
} else {
|
|
Write-Host " Verified H:\cmdline.txt already has 'fsck.repair=yes' and 'ro'." -ForegroundColor Green
|
|
}
|
|
}
|
|
|
|
Write-Host "`n=== Ready! Safe to eject H: and boot the Raspberry Pi. ===" -ForegroundColor Green
|
|
Write-Host "With 'fsck.repair=yes ro' in H:\cmdline.txt, the Pi kernel mounts / read-only first,"
|
|
Write-Host "runs 'fsck.ext4 -y' on Partition 2 automatically during boot, and then remounts / read-write."
|