1+ #! /bin/bash
2+
3+ # Bitcoin Knots Settings Backup and Restore Script
4+ # Usage: ./backup-restore.sh [backup|restore] [filename]
5+
6+ set -e
7+
8+ BITCOIN_CLI=" ${BITCOIN_CLI:- bitcoin-cli} "
9+ BACKUP_DIR=" ${BACKUP_DIR:- ./ backups} "
10+ TIMESTAMP=$( date +%Y%m%d_%H%M%S)
11+
12+ show_help () {
13+ cat << EOF
14+ Bitcoin Knots Settings Backup and Restore Tool
15+
16+ Usage:
17+ $0 backup [filename] Create settings backup
18+ $0 restore <filename> Restore settings from backup
19+ $0 list List available backups
20+ $0 compare <file1> <file2> Compare two settings files
21+
22+ Environment Variables:
23+ BITCOIN_CLI Path to bitcoin-cli (default: bitcoin-cli)
24+ BACKUP_DIR Backup directory (default: ./backups)
25+
26+ Examples:
27+ $0 backup # Create timestamped backup
28+ $0 backup my-config # Create named backup
29+ $0 restore backups/config.json # Restore from specific file
30+ $0 list # Show available backups
31+ EOF
32+ }
33+
34+ ensure_backup_dir () {
35+ if [ ! -d " $BACKUP_DIR " ]; then
36+ mkdir -p " $BACKUP_DIR "
37+ echo " Created backup directory: $BACKUP_DIR "
38+ fi
39+ }
40+
41+ test_bitcoin_cli () {
42+ if ! command -v " $BITCOIN_CLI " & > /dev/null; then
43+ echo " Error: bitcoin-cli not found. Set BITCOIN_CLI environment variable."
44+ exit 1
45+ fi
46+
47+ if ! " $BITCOIN_CLI " getblockchaininfo & > /dev/null; then
48+ echo " Error: Cannot connect to Bitcoin Core. Check if bitcoind is running."
49+ exit 1
50+ fi
51+ }
52+
53+ backup_settings () {
54+ local filename=" $1 "
55+
56+ if [ -z " $filename " ]; then
57+ filename=" bitcoin-settings-$TIMESTAMP .json"
58+ elif [[ " $filename " != * .json ]]; then
59+ filename=" ${filename} .json"
60+ fi
61+
62+ local filepath=" $BACKUP_DIR /$filename "
63+
64+ echo " Creating settings backup..."
65+ ensure_backup_dir
66+
67+ if ! " $BITCOIN_CLI " dumpsettings > " $filepath " ; then
68+ echo " Error: Failed to export settings"
69+ exit 1
70+ fi
71+
72+ echo " Settings backed up to: $filepath "
73+
74+ # Create metadata file
75+ cat > " ${filepath} .meta" << EOF
76+ {
77+ "backup_time": "$( date -Iseconds) ",
78+ "bitcoin_version": "$( " $BITCOIN_CLI " getnetworkinfo | jq -r ' .version // "unknown"' ) ",
79+ "hostname": "$( hostname) ",
80+ "file_size": $( stat -f%z " $filepath " 2> /dev/null || stat -c%s " $filepath " 2> /dev/null || echo " unknown" )
81+ }
82+ EOF
83+
84+ echo " Metadata saved to: ${filepath} .meta"
85+ echo " Backup completed successfully!"
86+ }
87+
88+ restore_settings () {
89+ local filepath=" $1 "
90+
91+ if [ -z " $filepath " ]; then
92+ echo " Error: Please specify a backup file to restore"
93+ show_help
94+ exit 1
95+ fi
96+
97+ if [ ! -f " $filepath " ]; then
98+ echo " Error: Backup file not found: $filepath "
99+ exit 1
100+ fi
101+
102+ echo " Restoring settings from: $filepath "
103+
104+ # Validate JSON first
105+ if ! jq . " $filepath " > /dev/null 2>&1 ; then
106+ echo " Error: Invalid JSON in backup file"
107+ exit 1
108+ fi
109+
110+ # Show preview of changes
111+ echo " Settings to be restored:"
112+ jq -r ' .settings | keys[]' " $filepath " | head -10
113+ local total_settings=$( jq -r ' .settings | keys | length' " $filepath " )
114+ echo " Total settings: $total_settings "
115+
116+ if [ " $total_settings " -gt 10 ]; then
117+ echo " ... and $(( $total_settings - 10 )) more"
118+ fi
119+
120+ read -p " Continue with restore? (y/N): " -n 1 -r
121+ echo
122+
123+ if [[ ! $REPLY =~ ^[Yy]$ ]]; then
124+ echo " Restore cancelled"
125+ exit 0
126+ fi
127+
128+ # Extract just the settings object for updatesettings command
129+ local settings_json=$( jq -c ' .settings' " $filepath " )
130+
131+ echo " Applying settings..."
132+ if ! " $BITCOIN_CLI " updatesettings " $settings_json " ; then
133+ echo " Error: Failed to restore settings"
134+ echo " Your Bitcoin Core configuration was not modified"
135+ exit 1
136+ fi
137+
138+ echo " Settings restored successfully!"
139+
140+ # Check if restart is required
141+ local restart_required=$( jq -r ' .metadata.restart_required // [] | length' " $filepath " )
142+ if [ " $restart_required " -gt 0 ]; then
143+ echo " "
144+ echo " WARNING: Some settings require a Bitcoin Core restart to take effect:"
145+ jq -r ' .metadata.restart_required[]?' " $filepath " | sed ' s/^/ - /'
146+ echo " "
147+ echo " Please restart bitcoind when convenient."
148+ fi
149+ }
150+
151+ list_backups () {
152+ ensure_backup_dir
153+
154+ echo " Available backups in $BACKUP_DIR :"
155+ echo " "
156+
157+ if [ ! " $( ls -A " $BACKUP_DIR " /* .json 2> /dev/null) " ]; then
158+ echo " No backups found."
159+ return
160+ fi
161+
162+ for backup in " $BACKUP_DIR " /* .json; do
163+ if [ -f " $backup " ]; then
164+ local basename=$( basename " $backup " )
165+ local size=$( stat -f%z " $backup " 2> /dev/null || stat -c%s " $backup " 2> /dev/null || echo " ?" )
166+ local date=" "
167+
168+ # Try to get date from metadata file
169+ if [ -f " ${backup} .meta" ]; then
170+ date=$( jq -r ' .backup_time // ""' " ${backup} .meta" 2> /dev/null || echo " " )
171+ fi
172+
173+ # Fallback to file modification time
174+ if [ -z " $date " ]; then
175+ date=$( stat -f%Sm -t" %Y-%m-%d %H:%M:%S" " $backup " 2> /dev/null || stat -c%y " $backup " 2> /dev/null | cut -d. -f1 || echo " unknown" )
176+ fi
177+
178+ printf " %-40s %8s bytes %s\n" " $basename " " $size " " $date "
179+ fi
180+ done
181+ }
182+
183+ compare_settings () {
184+ local file1=" $1 "
185+ local file2=" $2 "
186+
187+ if [ -z " $file1 " ] || [ -z " $file2 " ]; then
188+ echo " Error: Please specify two files to compare"
189+ show_help
190+ exit 1
191+ fi
192+
193+ if [ ! -f " $file1 " ] || [ ! -f " $file2 " ]; then
194+ echo " Error: One or both files not found"
195+ exit 1
196+ fi
197+
198+ echo " Comparing settings files:"
199+ echo " File 1: $file1 "
200+ echo " File 2: $file2 "
201+ echo " "
202+
203+ # Extract and compare settings
204+ local temp1=$( mktemp)
205+ local temp2=$( mktemp)
206+
207+ trap ' rm -f "$temp1" "$temp2"' EXIT
208+
209+ jq -S ' .settings' " $file1 " > " $temp1 "
210+ jq -S ' .settings' " $file2 " > " $temp2 "
211+
212+ if diff -u " $temp1 " " $temp2 " ; then
213+ echo " Files are identical."
214+ else
215+ echo " "
216+ echo " Use 'diff -u <(jq .settings \" $file1 \" ) <(jq .settings \" $file2 \" )' for detailed comparison."
217+ fi
218+ }
219+
220+ # Main script logic
221+ case " ${1:- } " in
222+ backup)
223+ test_bitcoin_cli
224+ backup_settings " $2 "
225+ ;;
226+ restore)
227+ test_bitcoin_cli
228+ restore_settings " $2 "
229+ ;;
230+ list)
231+ list_backups
232+ ;;
233+ compare)
234+ compare_settings " $2 " " $3 "
235+ ;;
236+ help|--help|-h)
237+ show_help
238+ ;;
239+ * )
240+ echo " Error: Invalid command"
241+ echo " "
242+ show_help
243+ exit 1
244+ ;;
245+ esac
0 commit comments