กล่อง Batocera ของคุณมีดิสก์ที่สักวันจะเต็ม NAS ของคุณมีที่ว่าง คู่มือนี้ย้ายระบบที่คุณเลือกไปไว้บนแชร์ในเครือข่าย แล้วทำ symlink กลับมาที่เดิม Batocera จึงไม่รู้ถึงความต่าง — และครอบคลุมสองเรื่องที่พังเป็นประจำ: สิทธิ์ไฟล์ที่ทำให้เซฟพังแบบเงียบ ๆ และ boot hook ที่เปลี่ยนไประหว่างเวอร์ชัน
Batocera วาง /userdata ทั้งหมดไว้บนแชร์เครือข่ายได้ แต่นั่นคือการตัดสินใจแบบทั้งหมดหรือไม่มีเลย ซึ่งทำให้คอนฟิก เซฟ และภาพปกที่ดึงมาไปอยู่หลังเครือข่ายด้วย การทำ symlink ทีละโฟลเดอร์ระบบยืดหยุ่นกว่า: ระบบใหญ่ที่กินพื้นที่หลายร้อยกิกะไบต์อยู่บน NAS ส่วนระบบเล็กที่ไวต่อความหน่วงอยู่บนดิสก์ในเครื่อง และกล่องยังบูตและเล่นได้แม้ NAS ปิดอยู่
หลักง่าย ๆ: ระบบที่ใช้แผ่นอยู่บน NAS — PS2, GameCube, Wii, Dreamcast, PSX, PS3 — เพราะใหญ่มาก และอ่านข้อมูลก้อนใหญ่ต่อเนื่องซึ่งเครือข่ายกิกะบิตรับได้สบาย ระบบยุคตลับอยู่ในเครื่อง — NES, SNES, Mega Drive, Game Boy, อาร์เคด — เพราะเล็กจนไม่มีผล และตอนดึงภาพปกจะโหลดไฟล์จิ๋วนับพัน ซึ่งเป็นงานที่เครือข่ายทำได้แย่ที่สุดพอดี
nfs-kernel-serverroot รหัสผ่านเริ่มต้นคือ linux ถ้าคุณยังไม่ได้เปลี่ยน ทุกอย่างด้านล่างรันผ่าน SSH/media และอ่านหมายเหตุเรื่องนี้ในขั้นที่ 6 ก่อนจะเลือกอะไรแปลก ๆบน NAS ที่เป็น Linux ธรรมดา สร้างโฟลเดอร์แล้วเพิ่มบรรทัด export
mkdir -p /srv/batocera
echo "/srv/batocera 192.168.1.20(rw,sync,no_subtree_check,no_root_squash,insecure)" >> /etc/exports
exportfs -ra
exportfs -vno_root_squash คือตัวเลือกที่สำคัญ Batocera รันทุกอย่างเป็น root ตามค่าเริ่มต้น NFS จะแปลงผู้ใช้ root จากระยะไกลเป็น nobody — ROM จึงอ่านได้ปกติแต่การเขียนจะล้มเหลว ถ้าคุณย้ายเซฟมาไว้บนแชร์ทีหลัง มันจะหยุดบันทึกแบบเงียบ ๆ โฟลเดอร์ ROM แบบอ่านอย่างเดียวรอดจากการ squash แต่อะไรที่ต้องเขียนไม่รอด
บน NAS ที่มีหน้าเว็บ ให้หาค่าตั้งที่เทียบเท่าแทนการแก้ไฟล์ด้วยมือ — Unraid เรียกว่า NFS rule ใต้ Share Settings, Synology มีดรอปดาวน์ "Squash" ที่ต้องตั้งเป็น No mapping และ TrueNAS มีฟิลด์ "Maproot User" ที่ต้องตั้งเป็น root
exportfs -v บน NAS ที่แสดงสิ่งที่เคอร์เนลบังคับใช้จริง ตรวจตอนนี้ และตรวจอีกครั้งหลังเปลี่ยนค่าตั้งของแชร์ทุกครั้งในอนาคตอย่าทำการเมานต์ให้อัตโนมัติก่อนที่คุณจะเคยทำมันด้วยมือ
mkdir -p /media/nas
mount -t nfs -o rw,soft,timeo=150,retrans=2 192.168.1.10:/srv/batocera /media/nas
mount | grep /media/nasคุณควรได้บรรทัดที่แสดงการเมานต์และตัวเลือกที่ตกลงกันได้ ถ้าการเมานต์ถูกปฏิเสธด้วยข้อผิดพลาดเรื่องโปรโตคอลหรือสิทธิ์ ให้เพิ่ม nfsvers=3 ในตัวเลือก — NAS บางรุ่น export เฉพาะ v3 และบางรุ่นวาง export ของ v4 ไว้ใต้ pseudo-root ซึ่งทำให้พาธเปลี่ยน
เกี่ยวกับตัวเลือกเหล่านั้น soft หมายความว่าคำขอที่ค้างจะคืนข้อผิดพลาดในที่สุดแทนการค้างตลอดไป บนเครื่องเล่นเกมนั่นคือสิ่งที่คุณต้องการ เพราะการเมานต์แบบ hard จะทำให้หน้าจอค้างไปเรื่อย ๆ ถ้า NAS หายไป timeo มีหน่วยเป็นหนึ่งในสิบวินาที timeo=150 จึงเท่ากับ 15 วินาที — กับ retrans=2 คำขอที่ล้มเหลวจะยอมแพ้หลังราว 30 วินาที
ใช้เวลาสิบวินาที และจับการตั้งค่าผิดที่พบบ่อยที่สุดได้
touch /media/nas/.writetest && echo WRITE-OK || echo WRITE-FAILED
stat -c '%U:%G %a' /media/nas/.writetest
rm /media/nas/.writetesttouch ที่สำเร็จไม่ได้พิสูจน์ว่าคุณไม่ถูก squash ถ้าโฟลเดอร์แม่เขียนได้ทุกคน การเขียนก็สำเร็จอยู่ดี — แล้วทุกไฟล์ที่อีมูเลเตอร์สร้างจะเป็นของ nobody ซึ่งพังแบบสับสนในภายหลัง ผลของ stat ต้องเป็น root:root ถ้าเป็น nobody ให้กลับไปขั้นที่ 1 แปลว่า no_root_squash ไม่ได้ถูกใช้งานคัดลอก ตรวจสอบ แล้วจึงลบต้นฉบับ
rsync -aH --info=progress2 /userdata/roms/ps2/ /media/nas/ps2/
du -sh /userdata/roms/ps2 /media/nas/ps2เครื่องหมายทับท้ายพาธสำคัญ — /ps2/ ทั้งสองฝั่งคัดลอกเนื้อในไปยังปลายทาง แทนการซ้อนโฟลเดอร์ไว้ข้างใน การเทียบ du ควรได้ยอดรวมที่ตรงกัน
สำหรับคลังขนาดใหญ่ ให้รันการคัดลอกภายใต้ nohup เพื่อให้รอดแม้เซสชัน SSH หลุด Batocera ไม่มี tmux หรือ screen มาให้
nohup rsync -aH --partial --info=progress2 /userdata/roms/ps2/ /media/nas/ps2/ > /userdata/romcopy.log 2>&1 &
tail -c 300 /userdata/romcopy.log
pgrep -a rsync || echo FINISHEDเปลี่ยนชื่อแทนการลบ เพื่อให้ย้อนกลับได้ด้วยคำสั่งเดียว
for SYS in ps2 gamecube wii dreamcast psx; do
[ -d "/media/nas/$SYS" ] || continue
mv "/userdata/roms/$SYS" "/userdata/roms/$SYS.local-backup"
ln -s "/media/nas/$SYS" "/userdata/roms/$SYS"
done
ls -la /userdata/roms | grep media/nasโฟลเดอร์ของแต่ละระบบตอนนี้เป็น symlink เข้าไปในแชร์ EmulationStation ตามมันไปโดยไม่รู้และไม่สนใจ เมื่อคุณบูตและยืนยันว่าเกมครบแล้ว ให้ลบโฟลเดอร์ .local-backup เพื่อเอาพื้นที่คืน
ตรวจหา symlink ที่ปลายทางชี้ไม่ถึง — โฟลเดอร์ที่คัดลอกไม่สำเร็จจะโผล่ตรงนี้ แทนที่จะเป็นระบบที่ว่างเปล่าอย่างลึกลับในหน้าจอ:
for d in /userdata/roms/*; do [ -L "$d" ] && [ ! -e "$d" ] && echo "BROKEN: $d"; doneเคล็ดลับเดียวกันใช้กับ /userdata/saves ได้ ซึ่งสะดวกถ้าคุณเล่นเกมเดียวกันบนหลายเครื่อง แต่ก็เพิ่มเดิมพันขึ้นมาก: เซฟถูกเขียนตลอดเวลา จึงสมเหตุสมผลเฉพาะเมื่อขั้นที่ 3 ผ่านอย่างสะอาด และการเมานต์ตอนบูตในขั้นที่ 6 เชื่อถือได้แล้ว
mkdir -p /media/nas/saves
rsync -aH /userdata/saves/ /media/nas/saves/
mv /userdata/saves /userdata/saves.local-backup
ln -s /media/nas/saves /userdata/saves/media/nas ก็ยังมีอยู่เป็นโฟลเดอร์ว่าง symlink จึงชี้ไปยังพาธว่างที่ดูถูกต้อง เกมจะเขียนเซฟลงพื้นที่ในเครื่อง และคุณจะมีเซฟสองชุดที่แยกทางกัน อีมูเลเตอร์แบบแยกบางตัว — รวมถึง RPCS3 และ Dolphin — ไปไกลกว่านั้นโดยสร้างคอนฟิกเปล่าทับลงไป นี่คือเหตุผลที่สคริปต์บูตในขั้นถัดไปลองซ้ำ แทนการพยายามเมานต์ครั้งเดียวส่วนที่คู่มือส่วนใหญ่ทำผิด เพราะ Batocera เปลี่ยนมัน
ระบบไฟล์รูทของ Batocera เป็นอิมเมจ squashfs แบบอ่านอย่างเดียวที่มี overlay ชั่วคราวอยู่ด้านบน อะไรที่เขียนนอก /userdata และ /boot จะถูกทิ้งตอนรีบูต /etc/fstab จึงใช้ไม่ได้ — มันไม่รอด Batocera มีฮุกของตัวเองให้แทน และฮุกที่คุณใช้ขึ้นกับเวอร์ชันของคุณ
| ฮุก | ทำงานเมื่อ | ใช้กับการเมานต์เครือข่ายได้ไหม? |
|---|---|---|
| /boot/boot-custom.sh v32+ | เป็นอย่างแรกหลัง init.d เริ่มทำงาน | ไม่ได้ — ระบบเครือข่ายยังไม่พร้อม |
| /boot/postshare.sh v35+ | หลัง /userdata ถูกเมานต์ ก่อนวิดีโอเปิดตัวและ EmulationStation | ได้ — นี่คือตัวที่ถูกต้อง |
| /userdata/system/custom.sh เลิกใช้ตั้งแต่ v38 | หลังจาก EmulationStation เปิดไปแล้ว | ไม่ได้ — เลิกใช้แล้ว และช้าเกินไปอยู่ดี |
| /userdata/system/services/<name> แนะนำตั้งแต่ v43 | จาก S99userservices หลัง EmulationStation เปิดแล้ว | ใช้เป็นทางสำรองเท่านั้น — ดูด้านล่าง |
custom.sh นั่นน่าจะเป็นเหตุผลที่แชร์ของคุณไม่เมานต์ มันถูกเลิกใช้ตั้งแต่ v38 และบน v43 เราพบว่ามันไม่เคยทำงานเลย — ไฟล์อยู่ตรงนั้น ถูกต้องและรันได้ แต่ไม่เคยถูกเรียก ไม่มีข้อความแจ้งข้อผิดพลาด ระบบ services มาแทนมัน แต่ services เริ่มหลังจาก EmulationStation สแกนโฟลเดอร์ ROM แล้ว แชร์ที่เมานต์ตรงนั้นจึงมาช้าเกินไป และทุกระบบบนเครือข่ายจะแสดงว่างจนกว่าคุณจะรีสตาร์ตหน้าจอ postshare.sh ทำงานก่อนการสแกน ซึ่งคือสิ่งที่คุณต้องการจริง ๆ/boot ถูกเมานต์แบบอ่านอย่างเดียว จึงต้องเมานต์ใหม่ให้เขียนได้ก่อน — และตั้งกลับหลังจากนั้น
mount -o remount,rw /boot
cat > /boot/postshare.sh <<'EOF'
#!/bin/sh
MNT=/media/nas
SRV=192.168.1.10:/srv/batocera
mkdir -p "$MNT"
n=0
while [ $n -lt 15 ]; do
grep -q " $MNT nfs" /proc/mounts && exit 0
mount -t nfs -o rw,soft,timeo=150,retrans=2 "$SRV" "$MNT" 2>/dev/null && exit 0
n=$((n+1))
sleep 2
done
mkdir -p /userdata/system/logs
echo "$(date) NAS mount FAILED" >> /userdata/system/logs/nas-mount.log
EOF
mount -o remount,ro /bootpostshare.sh ทำงาน แต่นี่คือฮุกเดียวของ Batocera ที่ไม่ทำงานเบื้องหลัง — การบูตจะรอมัน ลูป while true ที่ไม่จำกัดตรงนี้ไม่ได้ลองซ้ำอย่างสุภาพ แต่จะทำให้เครื่องค้างตลอดไป สูงสุดสามสิบวินาที แล้วยอมแพ้และบูตต่อ/proc/mounts ไม่ใช่ mountpoint BusyBox ของ Batocera ไม่มีคำสั่ง mountpoint ตัวกันที่เขียนด้วยคำสั่งนี้จะไม่มีวันสำเร็จ ลูปจึงวิ่งครบเวลาทุกครั้งที่บูตแม้การเมานต์จะได้ผล/media เป็นระบบไฟล์ชั่วคราว — ทุกอย่างข้างใต้หายไปหลังรีบูต ถ้าจุดเมานต์ของคุณหายไป นั่นเป็นเรื่องปกติที่คาดไว้แล้ว ไม่ใช่มีอะไรมาลบมันlogger จึงอาจหายไป ไฟล์ใต้ /userdata รอดเสมอ การที่มันไม่มีอยู่คือสัญญาณว่าสำเร็จchmod postshare.sh ถูกส่งตรงให้ตัวแปลภาษา bash บิตรันได้จึงไม่มีผล — ซึ่งก็ดีแล้ว เพราะ /boot มักเป็น FAT และเก็บบิตนั้นไม่ได้ถ้า postshare.sh ไม่ทำงานบนเวอร์ชันของคุณ ให้ใช้ service แทน ชื่อไฟล์ต้องไม่มีนามสกุล และมีเฉพาะตัวอักษร ตัวเลข และขีดล่าง เพราะ services เริ่มหลัง EmulationStation ให้เพิ่มการรีสตาร์ตหน้าจอไว้ท้าย หรือยอมรีสตาร์ตด้วยมือครั้งหนึ่งหลังบูต
mkdir -p /userdata/system/services
cat > /userdata/system/services/nasmount <<'EOF'
#!/bin/bash
MNT=/media/nas
SRV=192.168.1.10:/srv/batocera
case "$1" in
start)
mkdir -p "$MNT"
grep -q " $MNT nfs" /proc/mounts || \
mount -t nfs -o rw,soft,timeo=150,retrans=2 "$SRV" "$MNT"
;;
stop)
umount -l "$MNT" 2>/dev/null
;;
esac
EOF
chmod +x /userdata/system/services/nasmount
batocera-services enable nasmount
batocera-services list userตรวจจากบรรทัดคำสั่งก่อนจะแตะหน้าจอ
mount | grep /media/nas
cat /userdata/system/logs/nas-mount.log 2>/dev/null
ls /userdata/roms/ps2 | headบรรทัดการเมานต์ ไม่มีไฟล์ล็อก และรายการเกม คือผลที่สะอาด ถ้ามีไฟล์ล็อก แปลว่าสคริปต์ทำงานแต่การเมานต์ล้มเหลว — ตรวจว่า NAS ตื่นอยู่ และกล่อง Batocera ยังมีที่อยู่ IP ตรงกับกฎ export ของคุณ
จากนั้นปล่อยให้ EmulationStation โหลด แล้วยืนยันว่าระบบบนเครือข่ายแสดงเกม ระบบที่แสดงว่างทั้งที่โฟลเดอร์แสดงรายการได้ถูกต้อง คือแคชรายการเกมที่ค้าง ไม่ใช่ปัญหาการเมานต์ — อัปเดตรายการเกมของระบบนั้นจากหน้าจอ
| อาการ | สาเหตุที่น่าจะเป็น |
|---|---|
| แชร์หายไปหลังรีบูตทุกครั้ง แต่เมานต์ด้วยมือได้ปกติ | ใช้ boot hook ผิดสำหรับเวอร์ชันของคุณ — แทบแน่นอนว่าคุณใช้ custom.sh ย้ายไปใช้ postshare.sh |
| โฟลเดอร์จุดเมานต์ไม่มีอยู่หลังรีบูต | ปกติ /media เป็นระบบไฟล์ชั่วคราว สคริปต์บูตต้องสร้างมันใหม่ |
| เกมโหลดได้ แต่เซฟไม่ถูกเก็บแบบเงียบ ๆ | การ squash ของ root ตรวจด้วย exportfs -v บน NAS และการทดสอบ stat ในขั้นที่ 3 |
| การบูตค้างที่จอดำหลังเพิ่มสคริปต์ | ลูปลองซ้ำที่ไม่จำกัดใน postshare.sh มันไม่ได้ทำงานเบื้องหลัง — การบูตรอมัน |
| สคริปต์ไม่เคยทำงานและไม่แสดงข้อผิดพลาด | ท้ายบรรทัดแบบ CRLF ของ Windows หรือชื่อไฟล์ผิด ทั้งสองล้มเหลวแบบเงียบ ๆ |
mount.nfs: access denied by server | กฎ export ไม่ตรงกับ IP ปัจจุบันของกล่อง หรือ NAS ของคุณต้องใช้ nfsvers=3 |
| หน้าจอค้างขณะเลื่อนดูระบบบนเครือข่าย | ส่วนใหญ่คือการโหลดภาพปกผ่านเครือข่าย ถ้ายังเป็นอยู่ ให้ตรวจ dmesg บนกล่อง Batocera — ความผิดพลาดของไดรฟ์ USB ในเครื่องแสดงอาการเหมือนกันทุกอย่าง และโทษแชร์ผิดได้ง่าย |
| ทุกอย่างทำงานจนกว่า NAS จะรีบูต แล้วค้าง | คุณใช้การเมานต์แบบ hard ใช้ soft พร้อม timeo ที่มีขอบเขต |
ไม่มีอะไรที่นี่ที่ย้อนกลับไม่ได้
SYS=ps2
rm /userdata/roms/$SYS
mv /userdata/roms/$SYS.local-backup /userdata/roms/$SYSลบ /boot/postshare.sh ด้วยวิธีเดียวกับที่สร้าง — เมานต์ /boot ใหม่ให้เขียนได้ ลบ แล้วเมานต์กลับเป็นอ่านอย่างเดียว ROM บน NAS ไม่ถูกแตะต้องจากขั้นตอนใดเลย
man 5 exports บน Linux เครื่องใดก็ได้ ยังคงเป็นคำอธิบายเรื่อง squash ที่ชัดที่สุด