commit 92936a6e1199ea05bbccbd2d46208d71edc31f43 Author: dajoho Date: Sun Dec 10 21:17:35 2023 +0100 Initial commit diff --git a/.project b/.project new file mode 100644 index 0000000..021ee76 --- /dev/null +++ b/.project @@ -0,0 +1,11 @@ + + + pandory500-pandash + + + + + + + + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..dd01641 --- /dev/null +++ b/Makefile @@ -0,0 +1,13 @@ +all: clean pandash +CXX = /opt/armv8-teampandory_a500mini_gcc12-linux-gnueabihf/bin/armv8-teampandory_a500mini_gcc12-linux-gnueabihf-g++ +STRIP = /opt/armv8-teampandory_a500mini_gcc12-linux-gnueabihf/bin/armv8-teampandory_a500mini_gcc12-linux-gnueabihf-strip +INCLUDES = -Isrc +CFLAGS = -Os -s + +pandash: $(OBJS) + $(CXX) $(CFLAGS) $(INCLUDES) src/main.cpp src/CommandLine/CommandLineArguments.cpp src/Fs/Fs.cpp -o $@ + $(STRIP) pandash + upx -9 -f pandash + +clean: + rm -f pandash 2>/dev/null || true diff --git a/make.sh b/make.sh new file mode 100755 index 0000000..e4becc4 --- /dev/null +++ b/make.sh @@ -0,0 +1,4 @@ +#!/bin/bash +podman run -v "$(pwd):/pandash:Z" teampandory/teampandory-a500-private sh -c "cd /pandash; make" + +cp -fv pandash ../pandory-packagebuilder/pandory500/root/bin/ \ No newline at end of file diff --git a/pandash b/pandash new file mode 100755 index 0000000..d1085cf Binary files /dev/null and b/pandash differ diff --git a/src/CommandLine/CommandLineArguments.cpp b/src/CommandLine/CommandLineArguments.cpp new file mode 100644 index 0000000..da10d7d --- /dev/null +++ b/src/CommandLine/CommandLineArguments.cpp @@ -0,0 +1,45 @@ +#include +#include "CommandLineArguments.h" + +CommandLineArguments::CommandLineArguments(int argc, char *argv[]) { + argumentCount = argc; + argumentPointers = argv; +} + +int CommandLineArguments::getArgumentCount() { + return argumentCount; +} + +std::string CommandLineArguments::getArgument(int n) { + for (int i = 0; i < argumentCount; ++i) { + if (i == n) { + return std::string(argumentPointers[i]); + } + } + return std::string(); +} + +std::string CommandLineArguments::getPathArgument(int n) { + std::string arg = getArgument(n); + if (!arg.empty()) { + int len = arg.length(); + std::string end = arg.substr(len-1, 1); + if (end == ":") { + arg += "/"; + } + return arg; + } + return std::string(); +} + +std::string CommandLineArguments::getAllAsString() { + std::string stringArgs; + for (int i = 0; i < argumentCount; ++i) { + stringArgs.append(std::string(argumentPointers[i])+" "); + } + return stringArgs; +} + + + + diff --git a/src/CommandLine/CommandLineArguments.h b/src/CommandLine/CommandLineArguments.h new file mode 100644 index 0000000..7787380 --- /dev/null +++ b/src/CommandLine/CommandLineArguments.h @@ -0,0 +1,19 @@ +#ifndef TESTC_COMMANDLINEARGUMENTS_H +#define TESTC_COMMANDLINEARGUMENTS_H + +#include +#include +class CommandLineArguments { +protected: + int argumentCount; + char **argumentPointers; +public: + CommandLineArguments(int argc, char *argv[]); + int getArgumentCount(); + std::string getArgument(int n); + std::string getAllAsString(); + + std::string getPathArgument(int n); +}; + +#endif //TESTC_COMMANDLINEARGUMENTS_H diff --git a/src/Fs/Fs.cpp b/src/Fs/Fs.cpp new file mode 100644 index 0000000..9430b56 --- /dev/null +++ b/src/Fs/Fs.cpp @@ -0,0 +1,8 @@ +#include +#include +#include +#include "Fs.h" + +bool Fs::exists(const std::string& file) { + return std::filesystem::exists(file.c_str()); +} diff --git a/src/Fs/Fs.h b/src/Fs/Fs.h new file mode 100644 index 0000000..712bddc --- /dev/null +++ b/src/Fs/Fs.h @@ -0,0 +1,12 @@ +#ifndef PANDORER_FILESYSTEM_H +#define PANDORER_FILESYSTEM_H +#include +#include + +class Fs { +public: + static bool exists(const std::string& file); +}; + + +#endif //PANDORER_FILESYSTEM_H diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..71638bc --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,350 @@ +#include +#include +#include +#include +#include "CommandLine/CommandLineArguments.h" +#include "Fs/Fs.h" + +void pandoryExec(std::string const& cmd) +{ + std::cout << "Executing shell: " << cmd << std::endl; + system(cmd.c_str()); +} + +void freezeProcess(const std::string &processName) +{ + std::cout << "Freezing process: " << processName << std::endl; + std::string pauseCmd = "kill -STOP $(pidof "+ processName +") 2>/dev/null"; + pandoryExec(pauseCmd); +} + +void unfreezeProcess(const std::string &processName) +{ + std::cout << "Unfreezing process: " << processName << std::endl; + std::string pauseCmd = "kill -CONT $(pidof "+ processName +") 2>/dev/null"; + pandoryExec(pauseCmd); +} + +void shuffleMusic() +{ + pandoryExec("umount /tmp/pandory/share/retroarch/assets/sounds/bgm.mp3"); + pandoryExec("cd /mnt/Pandory/.user/bgm && ls | sed -n \"$((RANDOM%$(ls | wc -l)+1))p\" > /tmp/pandory_track"); + pandoryExec("busybox mount -o bind /mnt/Pandory/.user/bgm/$(cat /tmp/pandory_track) /tmp/pandory/share/retroarch/assets/sounds/bgm.mp3"); +} + + +void forceKill(const std::string &processName) +{ + std::cout << "Force killing process: " << processName << std::endl; + std::string cmd = "killall -9 " + processName + " 2>/dev/null"; + pandoryExec(cmd.c_str()); +} + +void yaft() +{ + pandoryExec("cp -fv /tmp/pandory/bin/shell /tmp/pandoryshell && chmod +x /tmp/pandoryshell"); + pandoryExec("/tmp/pandory/bin/yaft < /dev/tty0"); +} + +void ppsspp() +{ + pandoryExec("/tmp/pandory/bin/PPSSPPGold --fullscreen"); +} + +void retroarch() +{ + // if mode == retroarch + shuffleMusic(); + + // TODO: just complain instead if at 60hz. autopatch retroarch.cfg for 50/60hz + system("busybox ash /tmp/pandory/bin/checkfreq.sh"); + + system("mount -o bind /mnt/Pandory/.user/.config/retroarch/thumbnails/ /tmp/pandory/share/retroarch/thumbnails"); + system("mount -o loop,ro /mnt/Pandory/.pandorythumbs /tmp/pandory/share/retroarch/thumbnails"); + system("mount -o bind /tmp/pandory/share/retroarch/thumbnails/Arcade '/tmp/pandory/share/retroarch/thumbnails/FBNeo - Arcade Games'"); + system("mount -o bind /tmp/pandory/share/retroarch/thumbnails/Arcade '/tmp/pandory/share/retroarch/thumbnails/MAME'"); + pandoryExec("/tmp/pandory/bin/retroarch -c /mnt/Pandory/.user/.config/retroarch/retroarch.cfg"); +} + +void spectrum() +{ + pandoryExec("/tmp/pandory/bin/zesarux.sh"); +} + +void dosbox() +{ + pandoryExec("/tmp/pandory/bin/dosbox -conf /mnt/Pandory/.user/config/dosbox/dosbox-staging.conf"); +} + +void openbor() +{ + pandoryExec("cd /mnt/Pandory/.roms/OpenBOR && OpenBOR.elf"); +} + +void amiberry5(std::string const &executionMode, std::string const &romPath) +{ + forceKill("amiberry5"); + + std::string cmd = ""; + + if (romPath != "") { + cmd = "cd /mnt/Pandory/.user/.config/amiberry/; amiberry5 -o default_fullscreen_mode=1 -o default_vkbd_enabled=yes -o default_vkbd_exit=yes -o default_vkbd_style=Cool --autoload \""+romPath+"\""; + } else { + cmd = "cd /mnt/Pandory/.user/.config/amiberry/; amiberry5 -o default_fullscreen_mode=1"; + } + pandoryExec(cmd); +} + +void scummvm() +{ + pandoryExec("/tmp/pandory/bin/scummvm --config=/mnt/Pandory/.user/.config/scummvm/scummvm.ini"); +} + + +void darkplaces() +{ + pandoryExec("export LD_LIBRARY_PATH=\"/opt/gles/lib:$LD_LIBRARY_PATH\" && cd /mnt/Pandory/.roms/Quake/ && darkplaces-sdl"); + //pandoryExec("export LD_LIBRARY_PATH=\"/opt/gles/lib:$LD_LIBRARY_PATH\" && darkplaces.sh"); +} + +void emulationStation() +{ + pandoryExec("/tmp/pandory/bin/emulationstation"); +} + +void hatari() +{ + pandoryExec("/tmp/pandory/bin/hatari"); +} + +void vanillaTD() +{ + system("cd \"/mnt/Pandory/.roms/Vanilla Conquer/TD/\" && ./vanillatd"); +} + +void vanillaRA() +{ + system("cd \"/mnt/Pandory/.roms/Vanilla Conquer/RA/\" && ./vanillara"); +} + + + +void loadKernelModule(const std::string &module) +{ + std::string modulePath = "/tmp/pandory/lib/modules/"; + std::string cmd = "insmod " + modulePath + module + ".ko"; + system(cmd.c_str()); +} + +void enableNetwork() +{ + loadKernelModule("ipv4"); + loadKernelModule("af_packet"); + loadKernelModule("mii"); + loadKernelModule("rtl8150"); + loadKernelModule("r8152"); + loadKernelModule("tcp_cubic"); + + loadKernelModule("usbnet"); + loadKernelModule("libphy"); + + loadKernelModule("asix"); + //loadKernelModule("ax88179_178a"); + + loadKernelModule("catc"); + loadKernelModule("cdc_ether"); + loadKernelModule("ipheth"); + loadKernelModule("kaweth"); + loadKernelModule("pegasus"); + + loadKernelModule("squashfs"); + + // wait for interfaces and bring them up + system("sleep 5"); + system("ifconfig eth0 up"); + + //dhcp + system("busybox udhcpc -s /tmp/pandory/etc/udhcpc.script &"); + + system("cd /mnt/Pandory/.webserver && php -S 0.0.0.0:80 &"); + system("dropbear -r /mnt/Pandory/.user/.config/dropbear/dropbear_rsa_host_key -E -p 0.0.0.0:22 &"); +} + +void prepareBios() +{ + // Make a virtual kickstarts folder in /tmp + mkdir("/tmp/bios/", 0750); + chdir("/tmp/bios/"); + + // Symlink all the nand-kickstarts to /tmp/bios/ + system("find /usr/share/amiberry/kickstarts/ -type f -exec ash -c 'ln -sfv {} $(basename {})' \\;"); + + // Symlink all the libre amiberry-fallback-kickstarts to /tmp/bios/ + system("find /mnt/Pandory/.user/.config/amiberry/kickstarts/ -type f -exec ash -c 'ln -sfv {} $(basename {})' \\;"); + + // Rsync the preferred kickstarts to their correct names in the amiberry kickstart folder + system("rsync -av --size-only /usr/share/amiberry/kickstarts/kick34005.A500 '/mnt/Pandory/.user/.config/amiberry/kickstarts/Kickstart v1.3 rev 34.5 (1987)(Commodore)(A500-A1000-A2000-CDTV).rom'"); + system("rsync -av --size-only /usr/share/amiberry/kickstarts/kick37350.A600 '/mnt/Pandory/.user/.config/amiberry/kickstarts/Kickstart v2.05 rev 37.350 (1992)(Commodore)(A600HD)[!].rom'"); + system("rsync -av --size-only /usr/share/amiberry/kickstarts/kick40068.A1200 '/mnt/Pandory/.user/.config/amiberry/kickstarts/Kickstart v3.1 rev 40.68 (1993)(Commodore)(A1200)[!].rom'"); + + // ..and to the whdload boot folder + system("rsync -av --size-only /usr/share/amiberry/kickstarts/kick34005.A500 /mnt/Pandory/.user/.config/amiberry/whdboot/save-data/Kickstarts/"); + system("rsync -av --size-only /usr/share/amiberry/kickstarts/kick37350.A600 /mnt/Pandory/.user/.config/amiberry/whdboot/save-data/Kickstarts/"); + system("rsync -av --size-only /usr/share/amiberry/kickstarts/kick40068.A1200 /mnt/Pandory/.user/.config/amiberry/whdboot/save-data/Kickstarts/"); + + // ..and the rtb files, because whdload. the a600 one doesn't exist. + system("rsync -av --size-only /usr/share/amiberry/kickstarts/kick34005.A500.RTB /mnt/Pandory/.user/.config/amiberry/whdboot/save-data/Kickstarts/"); + system("rsync -av --size-only /usr/share/amiberry/kickstarts/kick40068.A1200.RTB /mnt/Pandory/.user/.config/amiberry/whdboot/save-data/Kickstarts/"); +} + +void parseAmiberryCommandLine(std::string const &name, std::string const &mode) +{ + std::string cmd = "ps -oargs | grep -v grep | grep amiberry | grep \""+name+"\" && touch /tmp/pandory_mode_" + mode; + pandoryExec(cmd); +} + +void clearCaches() +{ + pandoryExec("busybox sysctl vm.drop_caches=3"); +} + +int main(int argc, char *argv[]) +{ + // init pandory libraries and paths + setenv("LD_LIBRARY_PATH", "/tmp/pandory/usr/lib:/tmp/pandory/lib64:/tmp/pandory/lib", 1); + setenv("PATH", "/mnt/Pandory/.bin:/tmp/pandory/usr/bin:/tmp/pandory/sbin:/tmp/pandory/bin:/usr/bin:/sbin:/bin", 1); + + // empty caches + clearCaches(); + + + CommandLineArguments args = CommandLineArguments(argc, argv); + std::string mode = args.getArgument(1); + std::string rom = args.getArgument(2); + std::string romExtra = args.getArgument(3); + + if (mode == "network") { + enableNetwork(); + return 0; + } + + if (mode == "bios") { + prepareBios(); + return 0; + } + + if (mode == "amiberry5") { + std::string executionMode = args.getArgument(2); + std::string romPath = args.getArgument(3); + amiberry5(executionMode, romPath); + return 0; + } + + if (mode == "quake") { + freezeProcess("amiberry5"); + darkplaces(); + unfreezeProcess("amiberry5"); + return 0; + } + + + freezeProcess("manhattan"); + freezeProcess("skyline"); + freezeProcess("amiberry"); + + + if (!Fs::exists("/tmp/pandory_original_amiberry")) { + pandoryExec("mkdir /tmp/dbus/"); + pandoryExec("mount -o bind /mnt/Pandory/.user /root"); + pandoryExec("cp -f /usr/bin/amiberry /tmp/pandory_original_amiberry"); + pandoryExec("mount -o bind /tmp/pandory/bin/amiberry-proxy.sh /usr/bin/amiberry"); + pandoryExec("mount -o bind /tmp/pandory/share/terminfo/ /usr/share/terminfo/"); + + // fork network in the background + pandoryExec("pandash network &"); + + // prepare bios in the background -> do it sync instead of async + pandoryExec("pandash bios"); + + // rsync /etc/ to /tmp/etc/ and bind mount it back so it's writable + system("mkdir /tmp/etc/ && rsync -av /etc/ /tmp/etc/"); + system("mount -o bind /tmp/etc/ /etc/"); + + // make an empty mountpoint for dropbear and bind mount ssh configuration from usb stick + pandoryExec("mkdir /tmp/etc/dropbear/"); + //pandoryExec("mount -o bind /mnt/Pandory/.user/.config/dropbear/ /etc/dropbear/"); + pandoryExec("cp -fv /mnt/Pandory/.user/.config/dropbear/shadow /etc/shadow"); + pandoryExec("cp -fv /mnt/Pandory/.user/.config/dropbear/passwd /etc/passwd"); + } + + system("rm -f /tmp/pandory_mode_*"); + + parseAmiberryCommandLine("Start AMiNIMiga", "aminimiga"); + parseAmiberryCommandLine("Start AGS", "ags2"); + parseAmiberryCommandLine("Get Pandory500", "upgrade"); + + parseAmiberryCommandLine("Start PPSSPP (PSP)", "ppsspp"); + parseAmiberryCommandLine("Start Darkplaces (Quake)", "darkplaces"); + parseAmiberryCommandLine("Start Hatari (Atari)", "hatari"); + parseAmiberryCommandLine("Start Amiberry 5 (Amiga)", "amiberry5"); + parseAmiberryCommandLine("Start OpenBor (Beat-em-ups)", "openbor"); + parseAmiberryCommandLine("Start Terminal (Linux)", "terminal"); + parseAmiberryCommandLine("Start ScummVM (Adventure Games)", "scummvm"); + parseAmiberryCommandLine("Start Zesarux (Spectrum)", "spectrum"); + + parseAmiberryCommandLine("Start DOSBox Staging (IBM PC)", "dosbox"); + parseAmiberryCommandLine("Start Tiberian Dawn (C&C)", "vanillatd"); + parseAmiberryCommandLine("Start Red Alert (C&C)", "vanillara"); + + // free up memory + forceKill("amiberry"); + + // empty caches + clearCaches(); + + if (Fs::exists("/tmp/pandory_mode_ppsspp")) { + ppsspp(); + } else if (Fs::exists("/tmp/pandory_mode_terminal")) { + system("cp -fv /tmp/pandory/bin/shell /tmp/pandoryshell"); + yaft(); + } else if (Fs::exists("/tmp/pandory_mode_darkplaces")) { + darkplaces(); + } else if (Fs::exists("/tmp/pandory_mode_spectrum")) { + spectrum(); + } else if (Fs::exists("/tmp/pandory_mode_dosbox")) { + dosbox(); + } else if (Fs::exists("/tmp/pandory_mode_hatari")) { + hatari(); + } else if (Fs::exists("/tmp/pandory_mode_amiberry5")) { + // start amiberry with no arguments + amiberry5("", ""); + } else if (Fs::exists("/tmp/pandory_mode_scummvm")) { + scummvm(); + } else if (Fs::exists("/tmp/pandory_mode_openbor")) { + openbor(); + } else if (Fs::exists("/tmp/pandory_mode_vanillatd")) { + vanillaTD(); + } else if (Fs::exists("/tmp/pandory_mode_vanillara")) { + vanillaRA(); + } else if (Fs::exists("/tmp/pandory_mode_emulationstation")) { + emulationStation(); + } else if (Fs::exists("/tmp/pandory_mode_aminimiga")) { + pandoryExec("/mnt/AMiNIMiga/.pandory/boot.sh"); + pandoryExec("cd /mnt/Pandory/.user/.config/amiberry/; amiberry5 -o default_fullscreen_mode=1 -o config_path=/mnt/AMiNIMiga/.pandory/ --config /mnt/AMiNIMiga/.pandory/aminimiga.uae -s use_gui=no"); + } else if (Fs::exists("/tmp/pandory_mode_ags2")) { + pandoryExec("/mnt/AGS/.pandory/boot.sh"); + pandoryExec("cd /mnt/Pandory/.user/.config/amiberry/; amiberry5 -o default_fullscreen_mode=1 -o config_path=/mnt/AGS/.pandory/ --config /mnt/AGS/.pandory/ags.uae -s use_gui=no"); + } else if (Fs::exists("/tmp/pandory_mode_upgrade")) { + //pandoryExec("echo 'echo Upgrade to the full Pandory500 to add many emulators and new features to your A500 Mini. https://go.teampandory.com/a500 && sleep 10 && exit' > /tmp/pandoryshell"); + pandoryExec("mpv.sh /tmp/pandory/etc/pandory.mp4"); + } else { + retroarch(); + } + + unfreezeProcess("manhattan"); + unfreezeProcess("skyline"); + + // empty caches + clearCaches(); + return 0; +}