-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathscript.sh
More file actions
347 lines (287 loc) · 10.7 KB
/
script.sh
File metadata and controls
347 lines (287 loc) · 10.7 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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
#!/bin/bash
VERSION="0.5.3"
# --- COLORS & STYLING ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
RESET='\033[0m'
# --- LOGGING HELPERS ---
header() { echo -e "\n${BOLD}${CYAN}=== $1 ===${RESET}"; }
info() { echo -e "${BLUE}[INFO]${RESET} $1"; }
success() { echo -e "${GREEN}[OK]${RESET} $1"; }
warn() { echo -e "${YELLOW}[WARN]${RESET} $1"; }
error() { echo -e "${RED}[ERROR]${RESET} $1"; exit 1; }
# --- UTILS ---
CONFIG_FILE="/opt/dsf/conf/config.json"
BACKUP_DIR="/tmp/dsf_backup"
WORK_DIR="/tmp/dsf_overwrite"
get_current_dsf_version() {
local deps_file="/opt/dsf/bin/DuetControlServer.deps.json"
if [ -f "$deps_file" ]; then
local ver=$(grep -o '"DuetControlServer/[^"]*"' "$deps_file" | head -n 1 | cut -d'/' -f2 | tr -d '"')
echo "${ver:-Unknown}"
else
echo "Not Installed"
fi
}
cleanup() {
if [ -d "$WORK_DIR" ]; then rm -rf "$WORK_DIR"; fi
if [ -d "$BACKUP_DIR" ]; then rm -rf "$BACKUP_DIR"; fi
}
trap cleanup EXIT
backup_config() {
if [ -f "$CONFIG_FILE" ]; then
info "Backing up board configuration..."
mkdir -p "$BACKUP_DIR"
cp "$CONFIG_FILE" "$BACKUP_DIR/config.json"
else
warn "No existing configuration found at $CONFIG_FILE"
fi
}
restore_config() {
if [ -f "$BACKUP_DIR/config.json" ]; then
info "Restoring board configuration..."
mkdir -p "$(dirname "$CONFIG_FILE")"
cp "$BACKUP_DIR/config.json" "$CONFIG_FILE"
if id "dsf" &>/dev/null; then chown dsf:dsf "$CONFIG_FILE" 2>/dev/null; fi
fi
}
check_health() {
header "Service Health Check"
info "Waiting for services to settle..."
sleep 3
if systemctl is-active --quiet duetcontrolserver; then
success "DuetControlServer is running."
else
echo -e "${RED}${BOLD}!!! DuetControlServer Failed to Start !!!${RESET}"
echo -e "${YELLOW}Last 20 lines of service log:${RESET}"
echo "---------------------------------------------------"
systemctl status duetcontrolserver -n 20 --no-pager
echo "---------------------------------------------------"
error "Update completed but service failed to start."
fi
}
# --- SELF-UPDATE ---
SCRIPT_URL="https://raw.githubusercontent.com/TeamGloomy/Fly-FastOS-DSF-Update/main/script.sh"
SCRIPT_LOCATION="${BASH_SOURCE[@]}"
SELF_UPDATER_SCRIPT="/tmp/fly_fastos_selfupdater.sh"
self_update() {
rm -f "$SELF_UPDATER_SCRIPT"
TMP_FILE=$(mktemp -p "" "XXXXX.sh")
# Download new script with cache buster
if wget -q "${SCRIPT_URL}?t=$(date +%s)" -O "$TMP_FILE"; then
# Check integrity
if ! head -n 1 "$TMP_FILE" | grep -q "^#!/bin/bash"; then
warn "Downloaded update is not a valid script. Skipping update."
rm -f "$TMP_FILE"
return
fi
# Extract new version
NEW_VER=$(grep "^VERSION=" "$TMP_FILE" | head -n 1 | cut -d'"' -f2 | tr -d '\r')
if [ -z "$NEW_VER" ]; then
warn "Could not detect version in remote script. Skipping update."
rm -f "$TMP_FILE"
return
fi
ABS_SCRIPT_PATH=$(readlink -f "$SCRIPT_LOCATION")
# Check if up-to-date
if [ "$VERSION" == "$NEW_VER" ]; then
rm -f "$TMP_FILE"
return
fi
# Compare versions
if [[ "$VERSION" < "$NEW_VER" ]]; then
echo -e "${BOLD}${YELLOW}Update Available:${RESET} ${RED}$VERSION${RESET} -> ${GREEN}$NEW_VER${RESET}"
info "Updating script..."
echo "#!/bin/bash" > "$SELF_UPDATER_SCRIPT"
echo "cp \"$TMP_FILE\" \"$ABS_SCRIPT_PATH\"" >> "$SELF_UPDATER_SCRIPT"
echo "rm -f \"$TMP_FILE\"" >> "$SELF_UPDATER_SCRIPT"
echo "echo -e '${GREEN}[OK] Script updated. Restarting...${RESET}'" >> "$SELF_UPDATER_SCRIPT"
echo "exec \"$ABS_SCRIPT_PATH\" \"\$@\"" >> "$SELF_UPDATER_SCRIPT"
chmod +x "$SELF_UPDATER_SCRIPT"
chmod +x "$TMP_FILE"
exec "$SELF_UPDATER_SCRIPT"
else
rm -f "$TMP_FILE"
fi
else
warn "Failed to check for updates (network issue?). Continuing..."
rm -f "$TMP_FILE"
fi
}
self_update "$@"
# --- BANNER ---
CURRENT_DSF_VER=$(get_current_dsf_version)
clear
echo -e "${CYAN}"
echo " ______ _ ______ _ ____ _____ "
echo " | ____| | | ____| | | / __ \ / ____|"
echo " | |__ | |_ _ | |__ __ _ ___| |_| | | | (___ "
echo " | __| | | | | | ______ | __/ _\` / __| __| | | |\___ \ "
echo " | | | | |_| | |______| | | | (_| \__ \ |_| |__| |____) |"
echo " |_| |_|\__, | |_| \__,_|___/\__|\____/|_____/ "
echo " __/ | "
echo " |___/ DSF Update Utility v${VERSION}"
echo -e " Installed DSF: ${GREEN}${CURRENT_DSF_VER}${CYAN}"
echo -e "${RESET}"
echo ""
# --- CONFIGURATION IMPORTS ---
PACKAGES_FILE="Packages"
if [ "$EUID" -ne 0 ]; then error "Please run as root (sudo)."; fi
# --- USER SELECTION ---
header "Configuration"
echo -e "Select Release Channel:"
echo -e " 1) ${GREEN}Stable${RESET} (Recommended)"
echo -e " 2) ${YELLOW}Unstable${RESET} (Bleeding Edge)"
echo -e " 3) Restart Services"
echo -e " 4) Exit"
echo ""
while true; do
read -p "Enter choice [1-4]: " choice
case $choice in
1)
CHANNEL="Stable"
TARGET_URL="https://pkg.duet3d.com/dists/stable/armv7/binary-arm64/"
break;;
2)
CHANNEL="Unstable"
TARGET_URL="https://pkg.duet3d.com/dists/unstable/armv7/binary-arm64/"
break;;
3)
header "Restarting Services"
info "Restarting DuetControlServer..."
systemctl restart duetcontrolserver duetwebserver duetpluginservice
check_health
exit 0
;;
4)
info "Exiting..."
exit 0
;;
*) echo -e "${RED}Invalid selection.${RESET}";;
esac
done
info "Channel: ${BOLD}$CHANNEL${RESET}"
info "URL: $TARGET_URL"
info "URL: $TARGET_URL"
# --- 2. FETCH PACKAGE INDEX ---
header "Fetching Packages"
rm -rf "$WORK_DIR"
mkdir -p "$WORK_DIR" && cd "$WORK_DIR" || error "Could not create temp dir."
info "Downloading package index..."
if wget -q "${TARGET_URL}${PACKAGES_FILE}.gz" -O Packages.gz; then
info "Downloaded Packages.gz. Decompressing..."
gunzip Packages.gz
elif wget -q "${TARGET_URL}${PACKAGES_FILE}" -O Packages; then
info "Downloaded plain Packages file."
else
error "Failed to download package list. URL might be 404."
fi
if [ ! -s Packages ]; then error "The 'Packages' file is empty."; fi
# --- 3. PARSE VERSIONS ---
# Get all versions associated with duetcontrolserver
VERSIONS=($(grep -A 10 "Package: duetcontrolserver" Packages | grep "Version:" | awk '{print $2}' | sort -V -r))
if [ ${#VERSIONS[@]} -eq 0 ]; then
warn "Parser Warning: Could not find 'duetcontrolserver' block."
warn "Trying to find ANY version strings..."
VERSIONS=($(grep "Version:" Packages | awk '{print $2}' | sort -V -r | uniq))
fi
if [ ${#VERSIONS[@]} -eq 0 ]; then error "No versions found in file."; fi
header "Select Version"
i=1
for val in "${VERSIONS[@]}"; do
echo -e " $i) $val"
((i++))
done
echo -e " x) Exit"
echo ""
while true; do
read -p "Select version to install [1-${#VERSIONS[@]} or x]: " v_choice
if [[ "$v_choice" =~ ^[xX]$ ]]; then
info "Exiting..."
exit 0
elif [[ "$v_choice" =~ ^[0-9]+$ ]] && [ "$v_choice" -ge 1 ] && [ "$v_choice" -le "${#VERSIONS[@]}" ]; then
TARGET_VER="${VERSIONS[$((v_choice-1))]}"
break
else
echo -e "${RED}Invalid selection.${RESET}"
fi
done
info "Selected Version: ${BOLD}$TARGET_VER${RESET}"
# --- 4. IDENTIFY PACKAGES ---
declare -A INSTALL_LIST
while read -r line; do
if [[ "$line" =~ ^Package:\ (.*) ]]; then CURRENT_PKG="${BASH_REMATCH[1]}"; fi
if [[ "$line" =~ ^Version:\ (.*) ]]; then CURRENT_VER="${BASH_REMATCH[1]}"; fi
if [[ "$line" =~ ^Filename:\ (.*) ]]; then CURRENT_FILE="${BASH_REMATCH[1]}";
if [[ "$CURRENT_VER" == "$TARGET_VER" ]]; then
if [[ "$CURRENT_PKG" != "reprapfirmware" && -n "$CURRENT_PKG" ]]; then
INSTALL_LIST["$CURRENT_PKG"]="$CURRENT_FILE"
fi
fi
fi
done < Packages
if [ ${#INSTALL_LIST[@]} -eq 0 ]; then error "No packages found for version $TARGET_VER"; fi
info "Found ${#INSTALL_LIST[@]} packages to overwrite."
read -p "Proceed with overwrite? [y/N to Exit] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
info "Update cancelled by user."
exit 0
fi
# --- 1. SYSTEM PREP ---
header "System Preparation"
# BACKUP CONFIGURATION BEFORE STOPPING SERVICES
backup_config
info "Stopping services..."
systemctl stop duetcontrolserver duetwebserver duetpluginservice duetruntime 2>/dev/null
info "Reloading Daemon..."
systemctl daemon-reload
info "Remounting Filesystem as Read/Write..."
mount -o remount,rw / || error "Failed to remount / as RW. Cannot proceed."
# --- 5. EXECUTION ---
header "Installing Updates"
for pkg in "${!INSTALL_LIST[@]}"; do
FILE_PATH="${INSTALL_LIST[$pkg]}"
if [[ "$FILE_PATH" == pool/* ]] || [[ "$FILE_PATH" == dists/* ]]; then
FULL_URL="https://pkg.duet3d.com/${FILE_PATH}"
else
CLEAN_PATH="${FILE_PATH#./}"
FULL_URL="${TARGET_URL}${CLEAN_PATH}"
fi
DEB_NAME="$(basename "$FILE_PATH")"
info "Downloading $pkg..."
wget -q --show-progress "$FULL_URL" -O "$DEB_NAME" || error "Failed download."
info "Extracting & Overwriting..."
if command -v ar &> /dev/null; then
ar x "$DEB_NAME" data.tar.xz 2>/dev/null || ar x "$DEB_NAME" data.tar.gz 2>/dev/null
else
busybox ar x "$DEB_NAME" data.tar.xz 2>/dev/null || busybox ar x "$DEB_NAME" data.tar.gz 2>/dev/null
fi
if [ -f "data.tar.xz" ]; then ARCHIVE="data.tar.xz";
elif [ -f "data.tar.gz" ]; then ARCHIVE="data.tar.gz";
else error "Bad .deb format (no data.tar)"; fi
# OVERWRITE DIRECTLY TO /
# Suppress permission/ownership errors as requested
tar -xf "$ARCHIVE" -C / --no-same-owner -m 2>/dev/null
rm -f "$DEB_NAME" "$ARCHIVE" control.tar.* debian-binary
success "Installed $pkg"
done
# --- 6. FINISH ---
header "Finalizing"
# RESTORE CONFIGURATION
restore_config
info "Fixing Permissions..."
if id "dsf" &>/dev/null; then chown -R dsf:dsf /opt/dsf; fi
chmod +x /opt/dsf/bin/* 2>/dev/null
info "Syncing filesystem..."
sync
info "Restarting Services..."
systemctl start duetcontrolserver duetwebserver duetpluginservice
# HEALTH CHECK
check_health
header "Complete"
success "Fly-FastOS DSF Update Finished Successfully!"