2026年1月11日 星期日

在樹莓派1代上架設使用WSS連線的BBS站(MapleBBS-itoc)

想想上一篇熟悉的MapleBBS沒搞出來實在有點可惜
所以在上一次失敗後,還是有慢慢地在試
終於在最近得到了完整的解法
這版本建置過程的完善度真是輸夢之大地太多了,畢竟太舊了
不過舊也有舊的好處,比較熟悉所以感覺好上手多了
兩個版本要選,我是會選這個MapleBBS 3.10 itoc版

以下我會針對這版本遇到的問題儘量簡短一一說明
然後因為要修改的東西太多了
會提供一個可以一口氣修改所有Makefile用的prepare.sh
這檔案把前置工作搞定後
接下來就可以套用原本的安裝程序進行輕鬆且完整的安裝
那麼開始啦


先談一下上篇談到wake上傳的那一版(以下稱2005版)無法註冊的問題
問題其實很簡單,是我的問題
因為沒有建立uid:9999與gid:99的bbs帳號(開帳號沒指定的id從1001開始)
所以在註冊時,權限不符就無法建立檔案
沒辦法寫入檔案,下次再連入時,自然就找不到這個使用者
因為此時也找到了xeonchen備份的2012年itoc版(以下稱2012版)
就沒有回過頭再處理這問題
不然在編譯成功的情況下,這版應該也是能跑的

講到編譯方面,在這兩個版本的架設上,其實權限算最小的問題
編譯上問題可以說才是最大的,不論是修改的項目與數量上都不在一個量級上
畢竟這是台跑ARM的機器,而不是x86,就是要加一些參數編譯後程式才會正常
還記得上次夢之大地在CMakeLists.txt填加兩個編譯選項嗎?
除了加這兩組之外
編譯這麼舊的MapleBBS的另一個麻煩點就是程式碼有big5碼在
不加相關參數去編譯一定失敗
而就算加了下面這兩個big5參數
-finput-charset=big5 -fexec-charset=big5
還是會撞上大名頂頂的「許功蓋」問題
所以搞到後來,除了要一個一個Makefile檔去修改加這些參數外
一開始還得用把所有的.c與.h的big5轉成2進制碼,才能正常編譯
幸好這部分有python可以靠算好解決,請Gemini寫好程式一口氣全轉檔
編譯出來的程式「基本上」能用了
只是2005版就撞上了權限問題無法註冊
接著改用2012版後,則是又撞上了一登入就斷線的狀況
讓我不得不一邊測試一邊考慮再找更新的版本來安裝

在處理登入瞬斷問題的過程中,一開始方向就錯了
自己的直覺是編譯上產生的錯誤造成這個斷線
所以問AI的重點一直在編譯參數上是否有問題
不過也因為這樣,對於原始碼上big5碼問題找到了最好的解決方案
這解決方案是加上--std=gnu89這個參數
強制編譯器以GNU 1989年標準來看程式碼進行編譯
加了這參數,所有有big5的檔案都不用進行轉檔,上面的big5參數也不用了
只要Makefile檔都改寫好,一路就是編譯到完成,這真是太好了
但畢竟是錯誤的方向,登入就斷線的問題當然沒有解決
造成卡關卡到快發瘋,只好轉另外找到持續有更新版本的夢之大地來裝
測試完沒問題,用夢之大地架站過程寫了上一篇

寫完上一篇後,如開頭所說,還是不死心地繼續找登入瞬斷的答案
奮戰好一陣子後,總算靠著Gemini分析原始碼與登入記錄檔找到問題所在
關鍵:在/home/bbs下少了.BRD這個檔案
這個錯誤始於使用2005版時,因為說明書(README.md)實在看不懂
把github網址丟給Gemini求救安裝方法後,AI給的複製指令出了問題
流程是正確的,就是先下載原始碼到source_repo這資料夾
再複製必要資料到/home/bbs下,畢竟檔案權限只有在bbs這資料夾下
但使用的複製指令不會複製.BRD這個檔案
只用ls查也看不到有缺,所以自己檢查後也以為正常
2012版時,雖然有README.md,可是我也是這樣餵給Gemini
也給了我一樣有問題的指令
那個使用的指令是
cp -r /home/bbs/source_repo/bbs/* .
正確應該改成
cp -r /home/bbs/source_repo/bbs/. .
這樣登入後,程式才會依.BRD去找看版資料,找得到才會繼續顯示
否則因為不知道要跑哪個步驟去,只能斷線
結案

少了這檔案會無法登入,為什麼上一篇有提到,2012版曾經成功過呢?
回想了一下,在第一次試裝夢之大地版成功後,我有移除了它要再挑戰2012版
在沒有完全移除整個/home/bbs資料夾的情況下重編2012版
應該是有留下夢之大地的.BRD檔
同屬MapleBBS系統自然也可以使用,所以就登進去了
回想起來,登入後討論區版面確實怪怪的,但太高興就沒在意了
可是解決了這關,還卡了一關
真的是...果然沒這麼簡單(笑)
上一篇也提過,2012版最高進度是可以進站,但站長選單的功能都不能用
為了搞定這個問題,一路查出這段程式在maple/menu.c裡
程式是在呼叫admutil.so這件事上出了問題,但是沒有錯誤碼與Log
於是Gemini建議我加Log,再餵回去給它,得到的答案是
產生so檔時,因為樹莓派的ARMv6少了硬體除法器,所以編譯正常但執行時會錯
必須補上-lgcc_s這個參數,將軟體除法器弄好
可惜第一次加上後,編譯還是失敗,因為ld無法找到這參數,必須由gcc直接來
所以原本的ld -s -lgcc_s要改成$(CC) -s -lgcc_s才行
這樣編譯完成後的檔案執行下去,成功了
站長可以開新版,審核註冊單,編輯權限
功能全開啦!

到這裡重新整理一下這一版的架站的大概流程好了
跟夢之大地基本上大同小異
一樣是先建個uid:9999與gid:99的使用者與群組叫bbs
接下來登入bbs使用者,並開始下載原始碼到預備的位置,我決定命名為itoc
然後取出itoc裡的資料配置在/home/bbs底下
進入src資料夾中,修改底下的所有Makefile
利用linux的編譯參數複製修改成樹莓派專用的raspi,並在裡面加入下面的編譯參數
-fsigned-char -fcommon -std=gnu89
(少了-fPIC是在過程中發現不用加也可以編譯成功)
並在有編譯成so的地方修改ld成為$(CC),修改-G為-shared,並加入-lgcc_s
修改完Makefile後,回到/home/bin下
以big5編碼打開install.sh
修改想要變更的名詞與目標OS後存檔
接著執行install.sh就會執行檔案修改,並開始編譯整個專案
最後它會自己跑bbsd
camera與account
這時就可以連上來好好玩一玩了

只是中間從網路下載原始碼到修改所有的Makefile增加raspi作業系統的部分
講真的蠻複雜的,尤其是Makefile的修改要遍歷
daemon, game, innbbsd, lib, maple, pip, so, util, util/backup, util/tran, util/uno
這些資料夾下的Makefile通通都要修改,包含src下的Makefile主檔也要
所以我把它弄成prepare.sh如下

#!/bin/sh # 使用此 script 前,請先確認已經登入bbs這個帳號 #列出所有要修改的Makefile filelist="src/daemon/Makefile \ src/game/Makefile src/innbbsd/Makefile \ src/lib/Makefile src/maple/Makefile \ src/pip/Makefile src/so/Makefile \ src/util/Makefile src/util/backup/Makefile \ src/util/tran/Makefile src/util/uno/Makefile \ src/Makefile " echo "開始下載BBS原始碼" git clone https://github.com/xeonchen/maplebbs-itoc/ itoc echo "開始配置資料到該放的位置" cp -r /home/bbs/itoc/bbs/. . echo "完成基本資料複製" cp -r /home/bbs/itoc/gem/ . echo "補上更完整精華區" cp -r /home/bbs/itoc/ktv/. ./gem/ktv/ echo "完成KTV歌單的資料複製" echo "開始修改Makefile加入raspi部分" #檔案遍歷從1開始 count=1 for i in $filelist do sed -i '/[ \t]*ld -s -G/{ s/ld /$(CC) / s/-G/-shared/ s/$/ $(EXFLAG)/ }' "$i" sed -i '/[ \t]*make cygwin :/{ a\ \t@echo " make raspi : for Raspiberry Pi" }' "$i" case $count in 1) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-DLINUX -O2 -pipe -I../include -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -fsigned-char -fcommon -std=gnu89" LDFLAGS="-s -L../lib -ldao -lcrypt -lresolv" $(EXE) }' "$i" ;; 2) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-DLINUX -O2 -pipe -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -I../include -fcommon -fsigned-char -std=gnu89" EXFLAG="-lgcc_s" $(SO) }' "$i" ;; 3) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -fcommon -fsigned-char -std=gnu89" LDFLAGS="-s -L../lib -ldao" $(EXE) }' "$i" ;; 4) sed -i '/^[ \t]*all*:/{ n; a\ raspi: CFLAGS += -fcommon -fsigned-char -std=gnu89\nraspi: libdao.a\n }' "$i" ;; 5) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-DLINUX -O2 -pipe -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -I../include -fcommon -fsigned-char -std=gnu89" LDFLAGS="-s -L../lib -ldao -lcrypt -lresolv -ldl -rdynamic" $(EXE) }' "$i" ;; 6) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-DLINUX -O2 -pipe -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -I../include -fcommon -fsigned-char -std=gnu89" EXFLAG="-lgcc_s" $(SO) }' "$i" ;; 7) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-DLINUX -O2 -pipe -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -I../include -fcommon -fsigned-char -std=gnu89" EXFLAG="-lgcc_s" $(SO) }' "$i" ;; 8) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-O2 -pipe -I../include -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -fcommon -fsigned-char -std=gnu89" LDFLAGS="-s -L../lib -ldao" $(EXE) }' "$i" ;; 9) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -fcommon -fsigned-char -std=gnu89" LDFLAGS="-s -L../../lib -ldao" $(EXE) }' "$i" ;; 10) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -fcommon -fsigned-char -std=gnu89" LDFLAGS="-s -L../../lib -ldao" $(EXE) }' "$i" ;; 11) sed -i '/^[ \t]*cygwin.*:/{ n;n; a\ raspi:\n\t@$(MAKE) CFLAGS="-O2 -pipe -I../../include -fomit-frame-pointer -Wunused -Wno-unused-result -Wno-parentheses -fcommon -fsigned-char -std=gnu89" LDFLAGS="-s -L../../lib -ldao" $(EXE) }' "$i" ;; 12) sed -i '/^[ \t]*@cd util\/uno; make cygwin/{ a \ raspi:\n\t@cd lib; make raspi\n\t@cd daemon; make raspi\n\t@cd innbbsd; make raspi\n\t@cd maple; make raspi\n\t@cd so; make raspi\n\t@cd game; make raspi\n\t@cd pip; make raspi\n\t@cd util; make raspi\n\t@cd util/backup; make raspi\n\t@cd util/tran; make raspi\n\t@cd util/uno; make raspi }' "$i" ;; esac echo "$i 檔案修改完成" count=$((count + 1)) done echo "全部檔案配置修改完成,請進入bin中修改install.sh"

所以安裝MapleBBS itoc 2012版
詳細流程與指令整理如下:

1.安裝系統套件

與前一篇夢之大地的需求相較
少了cmake的需求
所以如果是重新開始的,一樣先跑更新
sudo apt update  
然後進行下面這幾個套件的安裝
sudo apt install git gcc make vim libncurses-dev  
一樣不安裝openbsd-inetd,靠systemd就行了

2.建立BBS帳號

一樣是先建個uid:9999與gid:99的使用者與群組叫bbs
sudo groupadd -gid 99 bbs
sudo adduser -uid 9999 -gid 99 --disabled-password --gecos "BBS Administrator" bbs
這次我加入了這帳號的註解,如同README中使用vipw輸入的一樣

3.下載、佈署與修改原始碼

接下來從原本使用的帳號改登入bbs使用者
sudo su bbs
然後進到/home/bbs資料夾中
cd 
接著建立上面的prepare.sh在/home/bbs下
vi  prepare.sh
請注意,在進到vi的畫面下,請先執行:set paste
這樣貼上的格式才不會亂掉,否則會被vi擅自加上不該有的跳格,然後Makefile就掛了
貼上存檔後再執行prepare.sh進行下載程式碼,佈署資料與修改Makefile
sh prepare.sh

4.編輯install.sh內容與編譯

輸入
cd /home/bbs/bin
回到bin下
以big5編碼打開install.sh
vi -c "e ++enc=big5" install.sh
修改想要變更的名詞
這次範例跟上次差不多
學校改為社區大學,站名就BBS小站,站長還是站長,IP拿掉
網域改成bbs.example.com顯示
然後OS請從freebsd改成raspi,因為我在Makefile另建了樹莓派專用編譯參數
bbsd port我改成上次的3023
註解掉telnet,因為我沒裝
存檔後執行install.sh
漫長的編譯就開始啦

5.實際執行畫面

執行後編譯正常的話,用pcman連上telnet://xxx.xxx.xxx.xxx:3023
就可以準備登入了
看這連線後,進站畫面正常多了

登錄當然是先註冊sysop

一樣剛註冊後是沒有權限的


要登出後再登入才有

可以看使用者資料


也可以審核使用者的註冊單不用靠電子信箱就取得完整權限
(上次夢之大地這裡沒有架設完全,所以使用者的權限測起來是受阻的)


主程式看來運作正常
就可以開始進行常駐服務模式的設定
首先就是加入Routine的crontab運作
這次的crontab檔在doc資料夾下
執行
crontab /home/bbs/doc/crontab
就可以了

重開機後的自動執行背景運作的部分使用systemd
仿照上次夢之大地
這次設三個檔案,設定bbsd、startbbs與xchatd三個檔
然後這些檔案內容如下

[Unit]
Description=MapleBBS Telnet server
After=syslog.target network.target remote-fs.target nss-lookup.target startbbs.service
Requires=startbbs.service
Wants=xchatd.service

[Service]
Type=forking
PIDFile=/home/bbs/run/bbs.pid
ExecStart=/home/bbs/bin/bbsd 23
ExecStop=/bin/kill -s TERM $MAINPID
Restart=on-failure
RestartSec=42s
KillMode=process
PrivateTmp=true

[Install]
WantedBy=multi-user.target
[Unit]
Description=Start MapleBBS Telnet server
After=syslog.target network.target remote-fs.target nss-lookup.target

[Service]
User=bbs
Group=bbs
Type=oneshot
## if set User and Group as bbs, then we don't need sudo commands
ExecStart=/home/bbs/bin/camera
ExecStart=/home/bbs/bin/account
PrivateTmp=true

[Install]
WantedBy=multi-user.target
[Unit]
Description=MapleBBS Chatroom Daemon
After=syslog.target network.target remote-fs.target nss-lookup.target startbbs.service
Requires=startbbs.service

[Service]
User=bbs
Group=bbs
Type=forking
PIDFile=/home/bbs/run/chat.pid
ExecStart=/home/bbs/bin/xchatd
ExecStop=/bin/kill -s QUIT $MAINPID
Restart=on-failure
RestartSec=42s
PrivateTmp=true

[Install]
WantedBy=multi-user.target

修改完成後存檔在/home/bbs/doc/中
!!!注意!!!
這邊一樣請離開bbs使用者
回到原本能使用sudo的帳號執行,不要開啟bbs的sudo功能
然後輸入
cp /home/bbs/doc/bbsd.service /etc/systemd/system
cp /home/bbs/doc/startbbs.service /etc/systemd/system
cp /home/bbs/doc/xchatd.service /etc/systemd/system

接著再輸入
sudo systemctl enable bbsd
將bbsd的服務正式打開
!!!注意!!!

完成後重新開機去啟動設定
好了,更老派更熟悉的BBS站完成
這樣總算有個真的很懷舊的成果出現

=========BBS與 WSS分隔線=========

那麼WSS的部分,就請參考前一篇吧
是的,就這樣 XD
只是因為想統一標題,所以前面還是留有WSS
請參考前篇用python寫的ws-proxy.py
還有ws-proxy.service的設定檔要設定
這程式兩邊都是可以共用

只是...(苦笑)
每次都這樣,正以為全部都搞定時,還是又出問題了
好好地把玩之後,發現了一個不是最重要,卻也蠻重要的事
我沒辦法用站長權限產生新的分組討論區分類
我可以在BBS這個分類中建立新看板讓它屬於這分類
卻無法建一個新的,假設命名為Personal的分類來放個人板
本來想說是不是漏了什麼,可是找遍裡面的說明文件
又再花了時間研究原始碼後,很明顯原始程式就不具有這功能
所以,可能這版在改版過程中,不小心弄掉了這個功能吧
只不要是架新站就根本用不到這功能啊

好吧,看來全功能就差這一步了
還是再花點時間搞定它吧!
不過下篇再繼續吧,一時之間要弄到好,實在也沒辦法
等弄好之後,再來寫一篇吧。

沒有留言: