-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmenu_recovery.sh
More file actions
165 lines (139 loc) · 5.58 KB
/
Copy pathmenu_recovery.sh
File metadata and controls
165 lines (139 loc) · 5.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#!/bin/bash
set -euo pipefail
ui_backend=""
RECOVERY_LOG=()
SCRIPT_SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
COMMON_MENU_LIB=""
for candidate in "${MENU_GUI_COMMON_LIB:-}" "/boot/install/menu_gui_common.sh" "$SCRIPT_SELF_DIR/menu_gui_common.sh"; do
[[ -n "$candidate" && -f "$candidate" ]] || continue
COMMON_MENU_LIB="$candidate"
break
done
if [[ -z "$COMMON_MENU_LIB" ]]; then
echo "Missing common menu library (menu_gui_common.sh)." >&2
exit 1
fi
# shellcheck disable=SC1090
. "$COMMON_MENU_LIB"
recovery_status() {
local message="$1"
RECOVERY_LOG+=("$(date '+%H:%M:%S') $message")
case "$ui_backend" in
whiptail)
whiptail --title "Password Reset" --infobox "$message" 8 80
;;
dialog)
dialog --title "Password Reset" --infobox "$message" 8 80
;;
*)
printf '[Password Reset] %s\n' "$message"
;;
esac
}
recovery_log_text() {
printf '%s\n' "${RECOVERY_LOG[@]}"
}
reset_unraid_password() {
local pool_name="${RECOVERY_BOOT_POOL:-flash}"
local mount_root=""
local dataset_list=""
local config_dir=""
local dataset mountpoint
local mount_failed=0
if ! command -v zpool >/dev/null 2>&1 || ! command -v zfs >/dev/null 2>&1; then
ui_msg "Password Reset" "ZFS tools are not available in this image."
return 1
fi
if zpool list -H -o name "$pool_name" >/dev/null 2>&1; then
ui_msg "Password Reset" "The '$pool_name' boot pool is already imported. Refusing to modify an active pool."
return 1
fi
if ! ui_confirm "Reset Password" "This removes config/passwd and config/shadow from the '$pool_name' boot pool. The next Unraid boot will have no web password. Continue?"; then
return 0
fi
mount_root="$(mktemp -d /mnt/unraid-recovery.XXXXXX)"
recovery_status "Importing ZFS boot pool '$pool_name'..."
if ! zpool import -N -R "$mount_root" "$pool_name"; then
rmdir "$mount_root" 2>/dev/null || true
ui_msg "Password Reset" "Unable to import ZFS boot pool '$pool_name'. Ensure the target boot device is connected and not in use."
return 1
fi
dataset_list="$(mktemp /tmp/unraid-recovery-datasets.XXXXXX)"
recovery_status "Reading datasets from '$pool_name'..."
if ! zfs list -H -o name,mountpoint -r "$pool_name" > "$dataset_list"; then
rm -f "$dataset_list"
zpool export "$pool_name" >/dev/null 2>&1 || true
rmdir "$mount_root" 2>/dev/null || true
ui_msg "Password Reset" "Unable to list datasets in the '$pool_name' boot pool."
return 1
fi
while IFS=$'\t' read -r dataset mountpoint; do
[[ -n "$dataset" ]] || continue
[[ "$mountpoint" == "legacy" || "$mountpoint" == "none" || "$mountpoint" == "-" ]] && continue
recovery_status "Mounting dataset '$dataset'..."
if ! zfs mount "$dataset"; then
mount_failed=1
break
fi
done < "$dataset_list"
rm -f "$dataset_list"
if [[ "$mount_failed" -eq 1 ]]; then
zpool export "$pool_name" >/dev/null 2>&1 || true
rmdir "$mount_root" 2>/dev/null || true
ui_msg "Password Reset" "The '$pool_name' boot dataset could not be mounted."
return 1
fi
recovery_status "Locating the Unraid config directory..."
config_dir="$(find -P "$mount_root" -type d -name config -print -quit 2>/dev/null || true)"
if [[ -z "$config_dir" ]]; then
zpool export "$pool_name" >/dev/null 2>&1 || true
rmdir "$mount_root" 2>/dev/null || true
ui_msg "Password Reset" "No config directory was found on the '$pool_name' boot pool."
return 1
fi
recovery_status "Deleting config/passwd and config/shadow..."
if ! rm -f -- "$config_dir/passwd" "$config_dir/shadow"; then
zpool export "$pool_name" >/dev/null 2>&1 || true
rmdir "$mount_root" 2>/dev/null || true
ui_msg "Password Reset" "Unable to remove the saved password files."
return 1
fi
recovery_status "Verifying password files are absent..."
if [[ -e "$config_dir/passwd" || -e "$config_dir/shadow" ]]; then
zpool export "$pool_name" >/dev/null 2>&1 || true
rmdir "$mount_root" 2>/dev/null || true
ui_msg "Password Reset" "The password files are still present in the config directory."
return 1
fi
recovery_status "Syncing changes to '$pool_name'..."
if ! sync; then
zpool export "$pool_name" >/dev/null 2>&1 || true
rmdir "$mount_root" 2>/dev/null || true
ui_msg "Password Reset" "Unable to sync the password reset changes."
return 1
fi
recovery_status "Exporting ZFS boot pool '$pool_name'..."
if ! zpool export "$pool_name"; then
ui_msg "Password Reset" "Password files were removed, but the '$pool_name' pool could not be exported. Export it before rebooting."
return 1
fi
rmdir "$mount_root" 2>/dev/null || true
recovery_status "Password reset complete."
ui_msg "Password Reset Complete" "$(recovery_log_text)
Password files were removed successfully. You can now boot Unraid and set a new password."
}
recovery_menu() {
local choice=""
if ! choice="$(ui_menu "Recovery" "Select a recovery action" A "Reset password" B "Back")"; then
choice="$(ui_hotkey_select "Recovery" "Select a recovery action" A "Reset password" B "Back")"
fi
choice="${choice//$'\r'/}"
choice="${choice//[[:space:]]/}"
choice="${choice^^}"
case "$choice" in
A) reset_unraid_password ;;
*) ;;
esac
}
detect_ui_backend
recovery_menu