Repository: danmons/retronas Branch: main Commit: 45cdaaa9e802 Files: 535 Total size: 998.8 KB Directory structure: gitextract_oklxbxnr/ ├── .github/ │ └── ISSUE_TEMPLATE/ │ ├── bug-report.yml │ └── config.yml ├── .gitignore ├── LICENSE ├── README.md ├── SECURITY ├── ansible/ │ ├── ansible.cfg │ ├── hosts.yml │ ├── install_3ds_qr_codes.yml │ ├── install_adtpro.yml │ ├── install_affstools.yml │ ├── install_amitools.yml │ ├── install_analoguepocket_cifs.yml │ ├── install_apfs-fuse.yml │ ├── install_aria2.yml │ ├── install_assembly64.yml │ ├── install_atarist-sidecart.yml │ ├── install_batocera_cifs.yml │ ├── install_cockpit-retronas.yml │ ├── install_cockpit.yml │ ├── install_cue2pops.yml │ ├── install_curlftpfs.yml │ ├── install_deluge.yml │ ├── install_dhcpcd.yml │ ├── install_disable-laptop-lid.yml │ ├── install_disc-image-creator.yml │ ├── install_dnsmasq-retro.yml │ ├── install_dnsmasq.yml │ ├── install_doc.yml │ ├── install_dreampi.yml │ ├── install_dvdauth.yml │ ├── install_eccedc.yml │ ├── install_emudeck_cifs.yml │ ├── install_emuelec_cifs.yml │ ├── install_etherdfs.yml │ ├── install_ethflopd.yml │ ├── install_extract-xiso.yml │ ├── install_extradirs.yml │ ├── install_far2l.yml │ ├── install_fenrir-ode-webserver.yml │ ├── install_filesystems.yml │ ├── install_firewalld-zones.yml │ ├── install_firewalld.yml │ ├── install_flippydrive.yml │ ├── install_freestation.yml │ ├── install_fsp.yml │ ├── install_gogrepo.yml │ ├── install_hb-store-cdn.yml │ ├── install_hdldump.yml │ ├── install_hdparm.yml │ ├── install_hfsutils.yml │ ├── install_hostapd.yml │ ├── install_kermit.yml │ ├── install_lighttpd.yml │ ├── install_linux-dexdrive.yml │ ├── install_linux-gadgets.yml │ ├── install_litch.yml │ ├── install_lynx.yml │ ├── install_macproxy_classic.yml │ ├── install_mc.yml │ ├── install_megatools.yml │ ├── install_minicom.yml │ ├── install_mister-organize.yml │ ├── install_mister_cifs.yml │ ├── install_mtcp-netdrive.yml │ ├── install_mysticbbs.yml │ ├── install_nabu.yml │ ├── install_nbd-client.yml │ ├── install_netatalk2.yml │ ├── install_netatalk2x.yml │ ├── install_netatalk3.yml │ ├── install_netatalk3_source.yml │ ├── install_netatalk4.yml │ ├── install_netlink.yml │ ├── install_netmount.yml │ ├── install_network-presets-ethernet-dhcp.yml │ ├── install_network-presets-standalone.yml │ ├── install_network-presets-zoned.yml │ ├── install_networkmanager.yml │ ├── install_nfs.yml │ ├── install_nginx.yml │ ├── install_ntp.yml │ ├── install_open-iscsi.yml │ ├── install_openssh.yml │ ├── install_pandoc.yml │ ├── install_pfsshell.yml │ ├── install_pi1541.yml │ ├── install_piscsi.yml │ ├── install_proftpd.yml │ ├── install_ps2_openps2loader.yml │ ├── install_ps2_udpbd.yml │ ├── install_ps3netsrv.yml │ ├── install_pygopherd.yml │ ├── install_rclone.yml │ ├── install_recalbox_cifs.yml │ ├── install_redumper.yml │ ├── install_retroaimserver.yml │ ├── install_retroarch_cifs.yml │ ├── install_retrodeck_cifs.yml │ ├── install_romdir.yml │ ├── install_romimport.yml │ ├── install_romm_cifs.yml │ ├── install_sabretools.yml │ ├── install_samba.yml │ ├── install_seaweedfs.yml │ ├── install_sit.yml │ ├── install_smbmounter.yml │ ├── install_sslcert.yml │ ├── install_syncthing.yml │ ├── install_tcpser.yml │ ├── install_telnet.yml │ ├── install_tftpd-hpa.yml │ ├── install_tnfs.yml │ ├── install_troubleshooting.yml │ ├── install_ucon64.yml │ ├── install_waybackproxy.yml │ ├── install_webone.yml │ ├── install_wrp.yml │ ├── install_xbox.yml │ ├── install_xbox360.yml │ ├── install_xbox360_netiso.yml │ ├── install_xboxmanager.yml │ ├── install_xlink-kai.yml │ ├── install_ytree.yml │ ├── install_zterm.yml │ ├── migrate_mister_cifs_issue21.yml │ ├── retronas_create_dirs.yml │ ├── retronas_dependencies.yml │ ├── retronas_system_config.yml │ ├── retronas_systems.yml │ ├── retronas_update_user.yml │ ├── retronas_vars.yml.default │ ├── roles/ │ │ ├── retronas.role.apt-backports/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.cache/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.cockpit/ │ │ │ ├── handlers/ │ │ │ │ └── main.yaml │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.cockpit-packages/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ ├── templates/ │ │ │ │ └── install_cockpit-packages/ │ │ │ │ └── cockpit-packages.sh.j2 │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.createdirs/ │ │ │ └── tasks/ │ │ │ └── main.yaml │ │ ├── retronas.role.curlftpfs/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ ├── templates/ │ │ │ │ └── install_curlftpfs.sh.j2 │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.dotnetcore3/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.dotnetcore6/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.dotnetcore8/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.extradirs/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.filesystems/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.firewalld.port/ │ │ │ └── tasks/ │ │ │ └── main.yaml │ │ ├── retronas.role.htpasswd/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yml │ │ ├── retronas.role.nfs/ │ │ │ ├── handlers/ │ │ │ │ └── main.yaml │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.nginx/ │ │ │ ├── handlers/ │ │ │ │ └── main.yaml │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ ├── templates/ │ │ │ │ └── install_nginx/ │ │ │ │ ├── conf/ │ │ │ │ │ ├── includes/ │ │ │ │ │ │ ├── autoindex.conf │ │ │ │ │ │ ├── listen-80.conf │ │ │ │ │ │ └── ssl.conf │ │ │ │ │ └── sites-available/ │ │ │ │ │ ├── 10-retronas.conf │ │ │ │ │ └── 99-retronas-files.conf │ │ │ │ └── www/ │ │ │ │ └── index.html │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.package.latest/ │ │ │ └── tasks/ │ │ │ └── main.yaml │ │ ├── retronas.role.paths/ │ │ │ └── tasks/ │ │ │ └── main.yaml │ │ ├── retronas.role.romdir/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.samba/ │ │ │ ├── handlers/ │ │ │ │ └── main.yaml │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ ├── templates/ │ │ │ │ └── retronas.conf.j2 │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.samba.system/ │ │ │ ├── tasks/ │ │ │ │ ├── link.yml │ │ │ │ ├── main.yaml │ │ │ │ └── nolink.yml │ │ │ └── templates/ │ │ │ └── retronas_system.conf.j2 │ │ ├── retronas.role.sslcert/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.system-config/ │ │ │ ├── tasks/ │ │ │ │ └── main.yaml │ │ │ └── vars/ │ │ │ └── main.yaml │ │ ├── retronas.role.templates/ │ │ │ └── tasks/ │ │ │ └── main.yaml │ │ ├── retronas.role.update-user/ │ │ │ └── tasks/ │ │ │ └── main.yaml │ │ └── retronas.role.x11vnc/ │ │ ├── tasks/ │ │ │ └── main.yaml │ │ ├── templates/ │ │ │ └── install_x11vnc/ │ │ │ └── x11vnc_wrapper.sh.j2 │ │ └── vars/ │ │ └── main.yaml │ └── templates/ │ ├── install_3ds_qr_codes/ │ │ ├── 3ds_qr.sh.j2 │ │ └── retronas_3ds_qr.cron.j2 │ ├── install_adtpro/ │ │ ├── ADTPro.properties.j2 │ │ ├── adtpro.service.j2 │ │ ├── adtpro_retronas.sh.j2 │ │ └── install_adtpro.sh.j2 │ ├── install_affstools/ │ │ └── install_affstools.sh.j2 │ ├── install_amitools/ │ │ └── install_amitools.sh.j2 │ ├── install_apfs-fuse/ │ │ └── install_apfs-fuse.sh.j2 │ ├── install_assembly64/ │ │ ├── assembly64.service.j2 │ │ ├── assembly64_retronas.sh.j2 │ │ └── install_assembly64.sh.j2 │ ├── install_atarist-sidecart/ │ │ ├── 99-retronas-sidecart.conf.j2 │ │ ├── atarist-sidecart-generate-roms.sh.j2 │ │ ├── atarist-sidecart-mirrordb.sh.j2 │ │ ├── atarist-sidecart-updatedb.sh.j2 │ │ ├── index.html.j2 │ │ └── retronas_atarist.conf.j2 │ ├── install_cockpit-retronas/ │ │ └── install_cockpit-retronas.sh.j2 │ ├── install_cue2pops/ │ │ └── install_cue2pops.sh.j2 │ ├── install_deluge/ │ │ ├── auth.j2 │ │ ├── autoadd.conf.j2 │ │ ├── core.conf.j2 │ │ ├── deluge-web.service.j2 │ │ ├── deluged.j2 │ │ ├── deluged.service.j2 │ │ └── upgrade_deluge.sh.j2 │ ├── install_disable-laptop-lid/ │ │ └── retronas.conf.j2 │ ├── install_disc-image-creator/ │ │ └── install_disc-image-creator.sh.j2 │ ├── install_dnsmasq-retro/ │ │ ├── dnsmasq-retro.service.j2 │ │ └── retro/ │ │ ├── dhcp-retro-ethernet.conf.j2 │ │ ├── dhcp-retro-wifi.conf.j2 │ │ ├── dhcp.conf.j2 │ │ ├── dns.conf.j2 │ │ ├── dnsmasq.conf.j2 │ │ ├── interfaces.conf.j2 │ │ └── ipv6.conf.j2 │ ├── install_dreampi/ │ │ ├── dreampi.conf.j2 │ │ └── install_dreampi.sh.j2 │ ├── install_dvdauth/ │ │ └── install_dvdauth.sh.j2 │ ├── install_eccedc/ │ │ └── install_eccedc.sh.j2 │ ├── install_etherdfs/ │ │ ├── etherdfs.service.j2 │ │ ├── install_etherdfs.sh.j2 │ │ └── retronas_dos.conf.j2 │ ├── install_ethflopd/ │ │ ├── ethflopd.service.j2 │ │ └── install_ethflopd.sh.j2 │ ├── install_extract-xiso/ │ │ └── install_extract-xiso.sh.j2 │ ├── install_far2l/ │ │ └── install_far2l.sh.j2 │ ├── install_fenrir-ode-webserver/ │ │ ├── fenrir-ode-webserver.service.j2 │ │ └── install_fenrir-ode-webserver.sh.j2 │ ├── install_firewalld/ │ │ └── workarounds/ │ │ ├── clear-python-bytecode.j2 │ │ └── override.conf.j2 │ ├── install_firewalld-zones/ │ │ ├── policies/ │ │ │ └── retro_to_modern.xml.j2 │ │ ├── services/ │ │ │ ├── ps3netsrv.xml.j2 │ │ │ └── samba-modern.xml.j2 │ │ └── zones/ │ │ ├── modern.xml.j2 │ │ └── retro.xml.j2 │ ├── install_flippydrive/ │ │ ├── flippydrive.service.j2 │ │ ├── flippydrive.sh.j2 │ │ └── install_flippydrive.sh.j2 │ ├── install_freestation/ │ │ ├── retronas_freestation_cifs.conf.j2 │ │ └── retronas_freestation_nfs.conf.j2 │ ├── install_fsp/ │ │ ├── fspd.conf.j2 │ │ ├── fspd.service.j2 │ │ └── install_fsp.sh.j2 │ ├── install_gogrepo/ │ │ ├── gogrepo-wrapper.sh.j2 │ │ ├── gogrepo_download.sh.j2 │ │ ├── gogrepo_import-cookies.sh.j2 │ │ ├── gogrepo_login.sh.j2 │ │ └── gogrepo_update.sh.j2 │ ├── install_hb-store-cdn/ │ │ ├── config.ini.j2 │ │ ├── hb-store-cdn-check.sh.j2 │ │ ├── hb-store-cdn.cron.j2 │ │ ├── hb-store-cdn.service.j2 │ │ └── install_hb-store-cdn.sh.j2 │ ├── install_hdldump/ │ │ └── install_hdldump.sh.j2 │ ├── install_hdparm/ │ │ ├── hdparm-manager.sh.j2 │ │ ├── hdparm.service.j2 │ │ ├── hdparm.sh.j2 │ │ └── hdparm.timer.j2 │ ├── install_hfsutils/ │ │ └── install_hfsutils.sh.j2 │ ├── install_hostapd/ │ │ ├── hostapd-dnsmasq.conf.j2 │ │ ├── hostapd-retronas.conf.j2 │ │ └── hostapd-retronas.service.j2 │ ├── install_kermit/ │ │ ├── iksd.socket.j2 │ │ └── iksd@.service.j2 │ ├── install_lighttpd/ │ │ └── 99-retronas.conf.j2 │ ├── install_linux-dexdrive/ │ │ ├── dexdrive_dumper.sh.j2 │ │ ├── install_linux-dexdrive.sh.j2 │ │ ├── linux-dexdrive.service.j2 │ │ └── makefile.patch.j2 │ ├── install_linux-gadgets/ │ │ └── gadget-mass-storage-manage.sh.j2 │ ├── install_litch/ │ │ ├── litch_claim.sh.j2 │ │ ├── litch_download.sh.j2 │ │ ├── litch_download_clean.sh.j2 │ │ └── litch_login.sh.j2 │ ├── install_macproxy_classic/ │ │ └── macproxy.service.j2 │ ├── install_megatools/ │ │ └── install_megatools.sh.j2 │ ├── install_minicom/ │ │ ├── minicom.sh.j2 │ │ └── minirc.dfl.j2 │ ├── install_mister-organize/ │ │ ├── install_mister-organize.sh.j2 │ │ └── mister-organize.sh.j2 │ ├── install_mister_cifs/ │ │ ├── retronas-mister-dirs.service.j2 │ │ └── retronas-mister-dirs.timer.j2 │ ├── install_mtcp-netdrive/ │ │ ├── install_mtcp-netdrive.sh.j2 │ │ ├── mtcp-netdrive.service.j2 │ │ ├── mtcp-netdrive.sh.j2 │ │ └── mtcp-netdrive.xml.j2 │ ├── install_mysticbbs/ │ │ ├── create_filebone_na.py.j2 │ │ ├── install_mysticbbs.sh.j2 │ │ ├── mysticbbs-mis.service.j2 │ │ ├── mysticbbs.sh.j2 │ │ ├── mysticbbs.xml.j2 │ │ ├── retronas_create_fileareas.ini.j2 │ │ └── retronas_massupload.ini.j2 │ ├── install_nabu/ │ │ ├── install_nabu.sh.j2 │ │ └── nabu.sh.j2 │ ├── install_nbd-client/ │ │ └── nbd.conf.j2 │ ├── install_netatalk2/ │ │ ├── AppleVolumes.default.j2 │ │ ├── afpd.conf.j2 │ │ └── default.j2 │ ├── install_netatalk2x/ │ │ ├── AppleVolumes.default.j2 │ │ ├── afpd.conf.j2 │ │ ├── afpexpect.sh.j2 │ │ ├── atalkd.conf.j2 │ │ ├── default.j2 │ │ └── install_netatalk2x.sh.j2 │ ├── install_netatalk3/ │ │ ├── install_netatalk3.sh.j2 │ │ ├── netatalk.service.j2 │ │ └── retronas.conf.j2 │ ├── install_netatalk4/ │ │ ├── atalkd.service.j2 │ │ ├── install_netatalk4.sh.j2 │ │ ├── netatalk.service.j2 │ │ └── retronas.conf.j2 │ ├── install_netlink/ │ │ ├── install_netlink.sh.j2 │ │ ├── netlink.conf.j2 │ │ ├── netlink.patch.j2 │ │ └── netlink.service.j2 │ ├── install_netmount/ │ │ ├── install_netmount.sh.j2 │ │ ├── netmount-confman.py.j2 │ │ ├── netmount-confman.sh.j2 │ │ └── retronas.yaml.j2 │ ├── install_network-presets-standalone/ │ │ └── dhcpcd.conf.j2 │ ├── install_network-presets-zoned/ │ │ └── dhcpcd.conf.j2 │ ├── install_nfs/ │ │ ├── exports.j2 │ │ └── nfs-kernel-server.j2 │ ├── install_open-iscsi/ │ │ └── iscsi-manager-target-login.sh.j2 │ ├── install_pfsshell/ │ │ └── install_pfsshell.sh.j2 │ ├── install_pi1541/ │ │ └── pi1541.sh.j2 │ ├── install_piscsi/ │ │ ├── install_piscsi.sh.j2 │ │ ├── install_piscsi_standard.sh.j2 │ │ ├── piscsi.service.j2 │ │ └── piscsi_retronas_patch.diff.j2 │ ├── install_proftpd/ │ │ ├── ftp.service.j2 │ │ └── retronas.conf.j2 │ ├── install_ps2_openps2loader/ │ │ └── retronas_ps2.conf.j2 │ ├── install_ps2_udpbd/ │ │ ├── install_ps2_udpbd.sh.j2 │ │ ├── ps2_udpbd.service.j2 │ │ └── udpbd_manager.sh.j2 │ ├── install_ps3netsrv/ │ │ ├── install_ps3netsrv.sh.j2 │ │ ├── ps3netsrv-perms.service.j2 │ │ ├── ps3netsrv-perms.timer.j2 │ │ └── ps3netsrv.service.j2 │ ├── install_pygopherd/ │ │ ├── install_pygopherd.sh.j2 │ │ ├── pygopherd.conf.j2 │ │ └── pygopherd.service.j2 │ ├── install_rclone/ │ │ └── rclone-webui.service.j2 │ ├── install_redumper/ │ │ └── install_redumper.sh.j2 │ ├── install_retroaimserver/ │ │ ├── install_retroaimserver.sh.j2 │ │ ├── retro-aim-server.service.j2 │ │ ├── retroaimserver.xml.j2 │ │ └── retroainserver.xml.j2 │ ├── install_romimport/ │ │ └── romimport.sh.j2 │ ├── install_romm_cifs/ │ │ ├── retronas-romm-dirs.service.j2 │ │ ├── retronas-romm-dirs.sh.j2 │ │ └── retronas-romm-dirs.timer.j2 │ ├── install_sabretools/ │ │ └── install_sabretools.sh.j2 │ ├── install_seaweedfs/ │ │ ├── install_seaweedfs.sh.j2 │ │ ├── seaweedfs-credentials.sh.j2 │ │ ├── seaweedfs-retronas.service.j2 │ │ ├── seaweedfs.xml.j2 │ │ └── weed-retronas-s3.json.j2 │ ├── install_sit/ │ │ └── install_sit.sh.j2 │ ├── install_smbmounter/ │ │ └── retronas_smbmounter.conf.j2 │ ├── install_tcpser/ │ │ ├── install_tcpser.sh.j2 │ │ └── tcpser@.service.j2 │ ├── install_telnet/ │ │ └── telnet.j2 │ ├── install_tftpd-hpa/ │ │ └── tftpd-hpa.j2 │ ├── install_tnfs/ │ │ ├── install_tnfs.sh.j2 │ │ └── tnfsd.service.j2 │ ├── install_ucon64/ │ │ └── install_ucon64.sh.j2 │ ├── install_waybackproxy/ │ │ ├── config.json.j2 │ │ ├── install_waybackproxy.sh.j2 │ │ └── waybackproxy.service.j2 │ ├── install_webone/ │ │ ├── install_webone.sh.j2 │ │ └── webone.service.j2 │ ├── install_wrp/ │ │ ├── install_wrp.sh.j2 │ │ └── wrp.service.j2 │ ├── install_x11vnc/ │ │ └── x11vnc_wrapper.sh.j2 │ ├── install_xbox/ │ │ └── retronas_xbox.conf.j2 │ ├── install_xbox360/ │ │ └── retronas_xbox360.conf.j2 │ ├── install_xbox360_netiso/ │ │ ├── dummy.iso.j2 │ │ ├── install_xbox360_netiso.sh.j2 │ │ └── xbox360_netiso.service.j2 │ ├── install_xboxmanager/ │ │ └── xboxmanager.cfg.j2 │ ├── install_xlink-kai/ │ │ └── xlink-kai.service.j2 │ ├── install_ytree/ │ │ └── install_ytree.sh.j2 │ └── install_zterm/ │ ├── install_zterm.sh.j2 │ └── zterm.service.j2 ├── config/ │ ├── menu/ │ │ ├── 3ds_qr.json │ │ ├── _template.json │ │ ├── adtpro.json │ │ ├── assembly64.json │ │ ├── atarist-sidecart.json │ │ ├── cockpit.json │ │ ├── config.json │ │ ├── deluge.json │ │ ├── dexdrive.json │ │ ├── doc.json │ │ ├── dreampi.json │ │ ├── etherdfs.json │ │ ├── ethflopd.json │ │ ├── experimental.json │ │ ├── fenrirodewebserver.json │ │ ├── flippydrive.json │ │ ├── fsp.json │ │ ├── gogrepo.json │ │ ├── hbstorecdn.json │ │ ├── hdparm.json │ │ ├── install.json │ │ ├── lighttpd.json │ │ ├── linux-gadgets.json │ │ ├── litch.json │ │ ├── lynx.json │ │ ├── macproxy_classic.json │ │ ├── main.json │ │ ├── minicom.json │ │ ├── mister-organize.json │ │ ├── mister_cifs.json │ │ ├── mtcp-netdrive.json │ │ ├── mysticbbs.json │ │ ├── nabu.json │ │ ├── netatalk-legacy.json │ │ ├── netatalk.json │ │ ├── netlink.json │ │ ├── netmount.json │ │ ├── network-manual.json │ │ ├── network-presets.json │ │ ├── network-setup-modern.json │ │ ├── network-setup-retro.json │ │ ├── network-setup-wifiap.json │ │ ├── network-setup.json │ │ ├── network.json │ │ ├── nginx.json │ │ ├── ntp.json │ │ ├── open-iscsi.json │ │ ├── openssh.json │ │ ├── pi1541.json │ │ ├── piscsi.json │ │ ├── profiles.json │ │ ├── proftpd.json │ │ ├── ps2_udpbd.json │ │ ├── ps3netsrv.json │ │ ├── rclone.json │ │ ├── retroaimserver.json │ │ ├── romimport.json │ │ ├── romimportsystem.json │ │ ├── romm_cifs.json │ │ ├── samba.json │ │ ├── seaweedfs.json │ │ ├── services.json │ │ ├── sslcert.json │ │ ├── syncthing.json │ │ ├── tcpser.json │ │ ├── telnet.json │ │ ├── tftpd-hpa.json │ │ ├── tnfs.json │ │ ├── tools.json │ │ ├── update.json │ │ ├── webone.json │ │ ├── wrp.json │ │ ├── xbox360_netiso.json │ │ ├── xlinkkai.json │ │ └── zterm.json │ └── retronas.cfg ├── dialog/ │ ├── adtpro_ethernet_edit.sh │ ├── adtpro_localhost_edit.sh │ ├── adtpro_serial_edit.sh │ ├── d_input.sh │ ├── d_menu.sh │ ├── d_yn.sh │ ├── dexdrive_memcards.sh │ ├── dexdrive_serial_edit.sh │ ├── disclaimer.sh │ ├── gogrepo.sh │ ├── profiles.sh │ ├── retronas_fixperms.sh │ ├── retronas_password.sh │ ├── romimportsystem.sh │ ├── tcpser_edit.sh │ ├── tcpser_status.sh │ ├── wifi_password.sh │ └── zterm_edit.sh ├── dist/ │ ├── install_preseed.sh │ └── retronas ├── install_retronas.sh ├── lib/ │ ├── ansible_runner.sh │ ├── common.sh │ ├── markup_runner.sh │ └── script_runner.sh ├── retronas.sh └── scripts/ ├── maint/ │ ├── git-changes-summary.sh │ ├── install-profile.py │ ├── migrate_romdirs.py │ ├── retronas-systems-manager.py │ ├── sort_menu_json.py │ └── tests/ │ ├── lint-yaml.sh │ └── test-retronas-json.py ├── patch/ │ ├── cache-dir.sh │ ├── git-config.sh │ ├── install-jq.sh │ ├── new-startup-file.sh │ └── update-retronas_vars.sh └── static/ ├── check-samba-user.sh ├── clean-broken-symlinks.sh ├── get-drives.sh ├── get-interfaces.sh ├── git-switch-branch.sh ├── network-example-presets-standalone.sh ├── network-example-presets-zoned.sh ├── permissions.sh ├── run-local-module.sh ├── service-samba.sh ├── set-etherdfs-nic.sh ├── set-top-level-dir.sh ├── update-group.sh ├── update-passwd.sh ├── update-retronas.sh ├── update-system-history.sh ├── update-system.sh ├── update-username.sh ├── wifi-show-passwd.sh └── wifi-update-passwd.sh ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/bug-report.yml ================================================ name: "Bug report" description: Report problematic behaviour. body: - type: markdown attributes: value: | If this is a new feature request please use the RetroNAS Discussion area. Before raising an issue confirm you are using a supported distribution by checking the wiki and include as much detail as possible about your issue - type: textarea attributes: label: Details description: | Any relevant details, e.g Error message text or screenshot, retronas branch, linux distribution information, ansible version etc. placeholder: | Installer , on retronas . I am using a supported distribution with Ansible installed. ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: true contact_links: - name: Discussions url: https://github.com/orgs/retronas/discussions about: For questions, feature requests etc. - name: "#retronas" url: https://libera.chat/guides/connect about: General chatter on Libera IRC - name: r/retroNAS url: https://www.reddit.com/r/retroNAS/ about: Community support (not monitored) ================================================ FILE: .gitignore ================================================ bin scripts/*.sh !scripts/static/*.sh src log doc ansible/retronas_vars.yml etc/* config/installed.json ansible/collections .fuse* ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021 Dan Mons Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ ![logo](dist/retronas-logo.png) # RetroNAS ## Project Information * [Status](https://github.com/retronas/retronas/wiki/Status) * [About](https://github.com/retronas/retronas/wiki/About) * [HowTo](https://github.com/retronas/retronas/wiki) * [Contributing](https://github.com/retronas/retronas/wiki/Contributing) * [Thanks and Credits](https://github.com/retronas/retronas/wiki/Credits) ## WARNINGS * [SECURITY](https://github.com/retronas/retronas/wiki/SECURITY-WARNING) * [FILENAMES](https://github.com/retronas/retronas/wiki/Filenames) ## Community * [Guides](https://github.com/retronas/retronas/wiki/Guides) * [Coverage](https://github.com/retronas/retronas/wiki/Coverage) * [Other Projects](https://github.com/retronas/retronas/wiki/Other-projects-and-sites) ================================================ FILE: SECURITY ================================================ ============================================================================= WARNING / TERMS OF USE / LICENSE ============================================================================= RetroNAS is a compilation of existing opensource products. RetroNAS is made available under the MIT license https://github.com/retronas/retronas/blob/main/LICENSE Due to the nature of retro computing, many of the tools and protocols used in this project are COMPLETELY INSECURE. It is at the users behest which tools are installed and as such all liabilies are transfered to you as the user in the use of RetroNAS. Most of these tools offer little to NO ENCRYPTION of neither data nor passwords, some tools offer access to your system WITHOUT any AUTHENTICATION, and some of the protocols have known EXPLOITS that cannot be fixed due to their legacy design. It is your responsiblity to secure your infrastructure. The RetroNAS team only support use of this software on a PRIVATE NETWORK A private network is considered one where at the very least the RetroNAS is located behind a firewall that denies inbound traffic from the internet. DO NOT expose a configured RetroNAS to the public INTERNET Doing so may result is unintentional DATA LOSS and or exposure of your network and subsequent contents beit computer and/or data to BAD ACTORS. It is your responsiblity to secure your infrastructure. The services RetroNAS installs will attempt to run as unprivileged user accounts where possible, but the RetroNAS installer scripts themselves all run as root (the "Adminstrator" account in Linux). These have the power to dramatically change and break working systems, so please ensure you undeerstand the consequence of the code you are about to run, i.e code review etc but the onus is on you. RetroNAS provides automatic compilation, installation and configuration of many third party tools these tools may be vulnerable to supply chain attacks of which we have no control over at installation time. If a project is shown to have been exploited we may remove or modify installation support at any time. It is your responsibility to ensure the options you are selecting for installation are as per the third party project authors intent and the onus is on said authors to secure their products. If you are UNSURE if ANY of the ABOVE statements apply to you. DO NOT CONTINUE to use this project. If you have questions in regards to RetroNAS use and/or risk you may ask your question on the github discussion boards for the project. The RetroNAS team may in turn use this enquiry to revise support documentation for the benefit of the project https://github.com/retronas/retronas The RetroNAS team are retro computing ENTHUSIASTS The RetroNAS team should not be considered computer, networking nor security experts and as such you are responsible to EDUCATE YOURSELF to the use of and/or risks associated with the tools in this project. This is NOT A NAS project for use with modern computing If you understand the above fully and accept all subsequent liabilties as your own in use of this project type AGREE at the prompt otherwise cease use of this project immediately. ================================================ FILE: ansible/ansible.cfg ================================================ [defaults] deprecation_warnings = False command_warnings = False inventory = /opt/retronas/ansible/hosts.yml log_path = /opt/retronas/log/ansible.log callbacks_enabled = ansible.posix.profile_tasks,ansible.posix.profile_roles callbacks_whitelist = ansible.posix.profile_tasks,ansible.posix.profile_roles cache = True gathering = smart fact_caching=jsonfile fact_caching_connection=/opt/retronas/cache fact_caching_timeout=86400 collections_paths = /opt/retronas/ansible/collections roles_path = /opt/retronas/ansible/roles private_role_vars = True ================================================ FILE: ansible/hosts.yml ================================================ --- all: hosts: localhost: vars: ansible_connection: local cache_plugin: jsonfile ================================================ FILE: ansible/install_3ds_qr_codes.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "3DS QR Codes" my_file: "install_3ds_qr_codes" rom_path: "{{ retronas_path }}/3ds" module_name: "3ds_qr_codes" dirs: - cia - qr tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.nginx - name: "{{ my_name }} - configure 3DS directory" ansible.builtin.file: path: "{{ rom_path }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory - name: "{{ my_name }} - create dirs" ansible.builtin.file: path: "{{ rom_path }}/{{ item }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory with_items: "{{ dirs }}" - name: "{{ my_name }} - link 3DS cia directory" ansible.builtin.file: src: "{{ rom_path }}/cia" dest: "{{ retronas_path }}/roms/nintendo/3ds/cia" state: link - name: "{{ my_name }} - install qrencode" ansible.builtin.apt: name: qrencode state: latest - name: "{{ my_name }} - configure QR generator script" ansible.builtin.template: src: "templates/{{ my_file }}/3ds_qr.sh.j2" dest: "{{ retronas_root }}/scripts/3ds_qr.sh" owner: root group: root mode: '0755' - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_adtpro.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "adtpro" my_file: "install_{{ my_name }}" my_dir: /opt/adtpro module_name: "adtpro" systemd_units: - { name: "adtpro", type: 'service', state: "stopped", enabled: "no", restart: "no", instance: "no" } packages: - default-jre - xvfb - x11vnc templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "ADTPro.properties", dest: "{{ my_dir }}", force: no } - { name: "adtpro_retronas.sh", dest: "{{ my_dir }}", mode: "0755" } paths: - { name: "{{ my_name }}", dest: "/opt", state: "directory", mode: "0755"} # - { name: "{{ my_name }}", dest: "{{ retronas_path }}", state: "directory", mode: "0755"} firewalld_ports: - { port: 60000, protocol: tcp } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.x11vnc - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - disks symlink" ansible.builtin.file: src: "roms/apple/appleii" dest: "{{ retronas_path }}/{{ my_name }}" state: "link" - name: "{{ my_name }} - Install" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root}} {{ my_dir }}/adtpro.sh" - name: "{{ my_name }} - create startup service(s) instance" ansible.builtin.template: src: templates/{{ my_file }}/{{ item.name }}.{{ item.type }}.j2 dest: /usr/lib/systemd/system/{{ item.name }}@.{{ item.type }} owner: root group: root mode: 0644 with_items: "{{ systemd_units }}" notify: "{{ my_name }} daemon-reload" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} daemon-reload" ansible.builtin.systemd: daemon_reload: true ================================================ FILE: ansible/install_affstools.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "affstools" my_file: "install_{{ my_name }}" module_name: "affstools" packages: - make - autoconf - gcc - curl - build-essential templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "/usr/local/sbin/mkaffs" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_amitools.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "amitools" my_file: "install_{{ my_name }}" module_name: "amitools" packages: - python3 - python3-pip templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_analoguepocket_cifs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "analoguepocket CIFS" my_file: "install_analoguepocket_cifs" module_name: "analoguepocket_cifs" system_key: "analoguepocket" top_level_paths: - { name: "Assets", enabled: yes, generic: "roms", systems: yes } - { name: "Cores", enabled: yes, generic: "", systems: no } - { name: "Platforms", enabled: yes, generic: "", systems: no } - { name: "Presets", enabled: yes, generic: "", systems: no } - { name: "Saves", enabled: yes, generic: "", systems: no } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_apfs-fuse.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "apfs-fuse" my_file: "install_apfs-fuse" module_name: "apfs-fuse" packages: - git - fuse - libfuse3-dev - bzip2 - libbz2-dev - cmake - g++ - libattr1-dev - zlib1g-dev templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "{{ retronas_root }}/bin/apfs-fuse" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_aria2.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "aria2" my_file: "install_aria2" module_name: "aria2" module_state: "present" packages: - aria2 tasks: - name: "{{ my_name }} - Load RetroNAS config" include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_assembly64.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "assembly64" my_file: "install_{{ my_name }}" my_dir: /opt/{{ my_name }} module_name: "assembly64" module_state: "present" packages: - xvfb - x11vnc templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}_retronas.sh", dest: "/opt/{{ my_name }}", mode: "0755" } - { name: "{{ my_name }}.service", dest: "/etc/systemd/system", mode: "0644" } paths: - { name: "{{ my_name }}", dest: "/opt", state: "directory", mode: "0755"} firewalld_ports: - { port: "66000", protocol: tcp} tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} daemon-reload" - name: "{{ my_name }} - disks symlink" ansible.builtin.file: src: "roms/apple/appleii" dest: "{{ retronas_path }}/{{ my_name }}" state: "link" - name: "{{ my_name }} - Install" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root}} {{ my_dir }}/{{ my_file }}.sh" - ansible.builtin.import_role: name: retronas.role.x11vnc - name: "{{ my_name }} - firewalld" ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} daemon-reload" ansible.builtin.systemd: daemon_reload: true ================================================ FILE: ansible/install_atarist-sidecart.yml ================================================ --- - hosts: localhost gather_facts: false roles: - retronas.role.romdir - retronas.role.nginx - retronas.role.samba vars: my_name: "atarist-sidecart" my_file: "install_{{ my_name }}" base_path: "{{ retronas_path }}/atarist" script_url: "https://raw.githubusercontent.com/diegoparrilla/atarist-sidecart-raspberry-pico/main/roms/update_json" script_dest: "{{ retronas_root }}/bin/{{ my_name }}-generate-roms.sh" module_name: "atarist-sidecart" packages: - python3-boto3 paths: - { name: "bin", dest: "{{ retronas_root }}" } - { name: "atarist", dest: "{{ retronas_path }}" } - { name: "sidecart", dest: "{{ base_path }}" } - { name: "db", dest: "{{ base_path }}/sidecart" } links: - { src: "{{ retronas_path }}/roms/atari/st/cart", dest: "{{ base_path }}/roms" } - { src: "{{ retronas_path }}/roms/atari/st/flop", dest: "{{ base_path }}/floppies" } templates: - { name: "retronas_atarist.conf", dest: "/etc/samba" } - { name: "{{ my_name }}-updatedb.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}-mirrordb.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}-generate-roms.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "99-retronas-sidecart.conf", dest: "/etc/nginx/sites-available" } - { name: "index.html", dest: "{{ base_path }}/sidecart", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } firewalld_rules: - { zone: "retro", service: "http" } tasks: - name: "{{ my_name }} - Install packages" ansible.builtin.package: name: "{{ packages }}" state: latest - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - symlinks" ansible.builtin.file: src: "{{ item.src }}" dest: "{{ item.dest }}" state: "link" with_items: "{{ links }}" - name: "{{ my_name }} - get update script" ansible.builtin.shell: curl -kLso "{{ script_dest }}" {{ script_url }} - name: "{{ my_name }} - make script executable" file: path: "{{ script_dest }}" mode: '0755' - name: "{{ my_name }} - configure includes file" ansible.builtin.ini_file: path: /etc/samba/smb.conf section: atarist option: "include" value: "/etc/samba/retronas_atarist.conf" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_batocera_cifs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "Batocera CIFS" my_file: "install_batocera_cifs" module_name: "batocera_cifs" system_key: "batocera" top_level_paths: - { name: "ROMS", enabled: yes, generic: "roms", systems: yes } - { name: "SAVES", enabled: yes, generic: "saves", systems: yes } - { name: "BIOS", enabled: yes, generic: "bios", systems: yes } internal_symlinks: - { src: 'sega/megadrive', dest: 'msu-md' } - { src: 'sharp/mz', dest: 'mz700' } - { src: 'sharp/mz', dest: 'mz800' } - { src: 'sharp/mzb', dest: 'mz2500' } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_cockpit-retronas.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "cockpit-retronas" my_file: "install_cockpit-retronas" package_dir: "/usr/share/cockpit" module_name: "cockpit-retronas" tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.include_role: name: retronas.role.filesystems - ansible.builtin.include_role: name: retronas.role.cockpit - name: "{{ my_name }} - create package directory" ansible.builtin.file: path: "{{ package_dir }}/{{ my_name }}" owner: root group: root mode: 0755 state: directory - name: "{{ my_name }} - Generate scripts" ansible.builtin.template: src: "templates/{{ my_file }}/{{ my_file }}.sh.j2" dest: "{{ retronas_root }}/scripts/{{ my_file }}.sh" owner: root group: root mode: 0755 - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" - ansible.builtin.include_role: name: retronas.role.system-config ================================================ FILE: ansible/install_cockpit.yml ================================================ --- - hosts: localhost gather_facts: true vars: module_name: "cockpit" roles: - retronas.role.filesystems - retronas.role.apt-backports - retronas.role.cockpit - retronas.role.cockpit-packages - retronas.role.system-config ================================================ FILE: ansible/install_cue2pops.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "cue2pops" my_file: "install_cue2pops" module_name: "cue2pops" packages: - git - coreutils - make - gcc - g++ - build-essential templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Run installer" ansible.builtin.shell: cmd: "./{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ retronas_root }}/scripts" executable: /bin/bash - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_curlftpfs.yml ================================================ --- - hosts: localhost gather_facts: true vars: module_name: "curlftpfs" roles: - retronas.role.curlftpfs - retronas.role.system-config ================================================ FILE: ansible/install_deluge.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "Deluge" my_file: "install_deluge" module_name: "bittorrent" packages: - geoip-bin - geoip-database - deluged - deluge-web - deluge-console systemd_units: - { name: "deluged", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } - { name: "deluge-web", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } paths: - { name: "deluged", dest: "/var/lib", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "config", dest: "/var/lib/deluged", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "bittorrent", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "torrents", dest: "{{ retronas_path }}/bittorrent", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "auto-add", dest: "{{ retronas_path }}/bittorrent", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "downloading", dest: "{{ retronas_path }}/bittorrent", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "complete", dest: "{{ retronas_path }}/bittorrent", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "autoadd.conf", dest: "/var/lib/deluged/config" } - { name: "deluged", dest: "/etc/default" } - { name: "core.conf", dest: "/var/lib/deluged/config" } - { name: "auth", dest: "/var/lib/deluged/config" } - { name: "upgrade_deluge.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "deluged.service", dest: '/usr/lib/systemd/system' } - { name: "deluge-web.service", dest: '/usr/lib/systemd/system' } firewalld_ports: - { zone: retro, port: "8112", protocol: "tcp" } - { zone: modern, port: "8112", protocol: "tcp" } - { zone: retro, port: "58846", protocol: "tcp" } - { zone: modern, port: "58846", protocol: "tcp" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - firewalld" ansible.builtin.import_role: name: retronas.role.firewalld.port - name: "{{ my_name }} -remove legacy deluged startup file" file: path: "/etc/init.d/deluged" state: absent - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" when: - item.instance == 'no' notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: restarted daemon_reload: true with_items: "{{ systemd_units }}" when: - item.restart == 'yes' - item.instance == 'no' ================================================ FILE: ansible/install_dhcpcd.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "dhcpcd" my_file: "install_{{ my_name }}" module_name: "dhcpcd" packages: - dhcpcd changed: false tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - restart if imported because handlers will not run" service: name: "{{ item }}" state: restarted enabled: true with_items: "{{ my_services }}" when: changed is true - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_disable-laptop-lid.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "Disable Laptop Lid" my_file: "install_disable-laptop-lid" service: "systemd-logind.service" module_name: "disable-laptop-lid" paths: - { name: "logind.conf.d", dest: "/etc/systemd/", state: "directory", mode: "0755"} templates: - { name: "retronas.conf", dest: "/etc/systemd/logind.conf.d", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ service }}" state: restarted ================================================ FILE: ansible/install_disc-image-creator.yml ================================================ # Dependencies - ansible.builtin.import_playbook: install_dvdauth.yml - ansible.builtin.import_playbook: install_eccedc.yml - hosts: localhost gather_facts: false vars: my_name: "Disc Image Creator" my_file: "install_disc-image-creator" module_name: "disc-image-creator" packages: - git - coreutils - make - gcc - g++ - curl - build-essential - unzip templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts/", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Run installer" ansible.builtin.shell: cmd: "./{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ retronas_root }}/scripts" executable: /bin/bash - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_dnsmasq-retro.yml ================================================ --- # Dependencies - import_playbook: install_ntp.yml - import_playbook: install_dnsmasq.yml - hosts: localhost gather_facts: false vars: my_name: "dnsmasq-retro" my_service: "{{ my_name }}" my_file: "install_{{ my_name }}" module_name: "dnsmasq-retro" templates: - { name: "dhcp-retro-ethernet.conf", sub: "retro", dest: "/etc/dnsmasq.d/retro", force: no } - { name: "dhcp-retro-wifi.conf", sub: "retro", dest: "/etc/dnsmasq.d/retro", force: no } - { name: "dhcp.conf", sub: "retro", dest: "/etc/dnsmasq.d/retro", force: no } - { name: "dns.conf", sub: "retro", dest: "/etc/dnsmasq.d/retro", force: no } - { name: "dnsmasq.conf", sub: "retro", dest: "/etc/dnsmasq.d/retro", force: no } - { name: "interfaces.conf", sub: "retro", dest: "/etc/dnsmasq.d/retro", force: no } - { name: "ipv6.conf", sub: "retro", dest: "/etc/dnsmasq.d/retro", force: no } - { name: "dnsmasq-retro.service", sub: "", dest: "/etc/systemd/system"} paths: - { name: "dnsmasq.d", dest: "/etc", state: "directory", mode: "0755" } - { name: "retro", dest: "/etc/dnsmasq.d", state: "directory", mode: "0755" } net_settings: - { option: "interface", value: "{{ retronas_net_retro_interface }}", match_regex: "^interface {{ retronas_net_retro_interface }}$", after_regex: "", state: "present", dest: "/etc/dhcpcd.conf" } #- { option: "interface", value: "{{ retronas_net_wifi_interface }}", match_regex: "^interface {{ retronas_net_wifi_interface }}$", after_regex: "", state: "present", dest: "/etc/dhcpcd.conf" } - { option: "static", value: 'ip_address\={{ retronas_net_retro_ip }}/{{ retronas_net_retro_subnet }}', after_regex: "^interface {{ retronas_net_retro_interface }}$", state: "present", dest: "/etc/dhcpcd.conf" } - { option: "static", value: 'domain_name_servers\={{ retronas_net_retro_dns }}', after_regex: "^interface ip_address=.+$", state: "present", dest: "/etc/dhcpcd.conf" } my_services: - dhcpcd - "{{ my_name }}" tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - mask default dnsmasq service" service: name: "dnsmasq" state: stopped daemon_reload: true enabled: false masked: true - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart services" - name: "{{ my_name }} - checking for dhcpcd" stat: path: "/etc/dhcpcd.conf" register: dhcpcd_check - name: "{{ my_name }} - setup dhcpcd" lineinfile: path: "{{ item.dest }}" search_string: "{{ item.match_regex | default('^$') }}" insertbefore: "{{ item.before_regex | default(omit) }}" insertafter: "{{ item.after_regex | default(omit) }}" line: "{{ item.option }} {{ item.value }}" with_items: "{{ net_settings }}" when: dhcpcd_check.stat.exists notify: "{{ my_name }} - Restart services" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart services" service: name: "{{ item }}" state: restarted daemon_reload: true enabled: true with_items: "{{ my_service }}" ================================================ FILE: ansible/install_dnsmasq.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "dnsmasq" my_file: "install_{{ my_name }}" module_name: "dnsmasq" packages: - dnsmasq my_services: - dnsmasq changed: false tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - restart if imported because handlers will not run" service: name: "{{ item }}" state: restarted enabled: true with_items: "{{ my_services }}" when: changed is true - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_doc.yml ================================================ # Dependencies - ansible.builtin.import_playbook: install_lynx.yml - hosts: localhost gather_facts: false vars: my_name: "retronas_docs" my_file: "install_retronas_docs" module_name: "retronas_docs" packages: - git - pandoc tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Clone local copy of RetroNAS wiki" ansible.builtin.git: repo: https://github.com/retronas/retronas.wiki.git dest: "{{ retronas_root }}/doc" update: false - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_dreampi.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "dreampi" my_file: "install_dreampi" module_name: "dreampi" packages: - git - dnsmasq - dnsutils - libnetfilter-queue-dev - libnetfilter-queue1 - ppp - arping - nftables - tcpd - wvdial - python3-pip groups: - dialout - dip templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}.conf", dest: "/etc/dnsmasq.d", force: no } paths: - { name: "dnsmasq.d", dest: "/etc" } systemd_patches: - { unit: "dreampi.service", line: "Restart=on-failure", regex: "^Restart=on-failure$", after: "^ExecStart=.*$" } - { unit: "dreampi.service", line: "RestartSec=30s", regex: "^RestartSec=.+", after: "^Restart=.*$" } tasks: - name: "{{ my_name }} - Checking hw platform compatiblity" ansible.builtin.debug: msg: "INCOMPATIBLE PLATFORM, only arm platforms are supported" when: ansible_architecture is not search('arm') and ansible_architecture != 'aarch64' - ansible.builtin.meta: end_play when: ansible_architecture is not search('arm') and ansible_architecture != 'aarch64' - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Run installer" ansible.builtin.shell: cmd: "./{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ retronas_root }}/scripts" executable: /bin/bash notify: "{{ my_name }} Restart Services" - name: "{{ my_name }} - Patch systemd service" ansible.builtin.lineinfile: path: /etc/systemd/system/{{ item.unit }} regex: "{{ item.regex }}" insertafter: "{{ item.after }}" line: "{{ item.line }}" state: present with_items: "{{ systemd_patches }}" notify: "{{ my_name }} Restart Services" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} Restart Services" ansible.builtin.service: name: "{{ item }}" state: started enabled: true daemon_reload: true with_items: - "{{ my_name }}.service" ================================================ FILE: ansible/install_dvdauth.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "DVDAuth" my_file: "install_dvdauth" module_name: "dvdauth" packages: - git - coreutils - make - gcc - g++ - curl - build-essential - unzip - util-linux templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Run installer" ansible.builtin.shell: cmd: "./{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ retronas_root }}/scripts" executable: /bin/bash - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_eccedc.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "EccEDC" my_file: "install_eccedc" module_name: "eccedc" packages: - coreutils - make - gcc - g++ - curl - build-essential - unzip templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Run installer" ansible.builtin.shell: cmd: "./{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ retronas_root }}/scripts" executable: /bin/bash - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_emudeck_cifs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "EmuDeck CIFS" my_file: "install_emudeck_cifs" system_key: "emudeck" module_name: "emudeck_cifs" top_level_paths: - { name: "roms", enabled: yes, generic: "roms", systems: yes } # - { name: "saves", enabled: yes, generic: "saves", systems: yes } - { name: "bios", enabled: yes, generic: "bios", systems: yes } internal_symlinks: - { src: 'commodore/amiga', dest: 'ags' } - { src: 'commodore/amiga', dest: 'amiga600' } - { src: 'atari/jaguar', dest: 'atarijaguarcd' } - { src: 'capcom/cps1', dest: 'cps' } - { src: 'nintendo/gamecube', dest: 'gc' } - { src: 'mame/mame', dest: 'mame-advmame' } - { src: 'mame/mame', dest: 'mame-mame4all' } - { src: 'mame/mame', dest: 'mame-mame4all' } - { src: 'sega/megacd', dest: 'segacd' } - { src: 'sega/megacd', dest: 'megacdjp' } - { src: 'sega/megadrive', dest: 'genesis' } - { src: 'sega/megadrive', dest: 'megadrivejp' } - { src: 'nintendo/3ds', dest: 'n3ds' } - { src: 'snk/neogeocd', dest: 'neogeocdjp' } - { src: 'sony/playstation1', dest: 'psx' } - { src: 'sega/saturn', dest: 'saturnjp' } - { src: 'sega/32x', dest: 'sega32xjp' } - { src: 'sega/32x', dest: 'sega32xna' } - { src: 'nintendo/superfamicom', dest: 'sneshd' } - { src: 'nintendo/superfamicom', dest: 'snesna' } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_emuelec_cifs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "EmuElec CIFS" my_file: "install_emuelec_cifs" module_name: "emuelec_cifs" system_key: "emuelec" internal_symlinks: - { src: 'nintendo/famicom', dest: 'nesh' } - { src: 'nintendo/gameboyadvance', dest: 'gbah' } - { src: 'nintendo/gameboy', dest: 'gbh' } - { src: 'nintendo/gameboycolor', dest: 'gbch' } - { src: 'nintendo/superfamicom', dest: 'snesh' } - { src: 'sega/gamegear', dest: 'gamegearh' } - { src: 'sega/megadrive', dest: 'genh' } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_etherdfs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "EtherDFS" my_file: "install_etherdfs" module_name: "etherdfs" packages: - make - automake - autoconf - gcc - g++ - git - build-essential - coreutils paths: - { name: "dos", dest: "{{ retronas_path }}", state: "directory", owner: "{{ retronas_user }}", group: "{{ retronas_group }}", mode: "0755" } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "etherdfs.service", dest: "/usr/lib/systemd/system/" } - { name: "retronas_dos.conf", dest: "/etc/samba/" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root }}/bin/ethersrv" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - configure includes file" ansible.builtin.ini_file: path: /etc/samba/smb.conf section: dos option: "include" value: "/etc/samba/retronas_dos.conf" notify: "{{ my_name }} - Install Samba" - name: "{{ my_name }} - enable startup service" ansible.builtin.service: name: "{{ item }}" state: started enabled: true daemon_reload: true with_items: - etherdfs - ansible.builtin.import_role: name: retronas.role.samba vars: changed: "{{ install_changed }}" when: install_changed is defined and install_changed is true - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted daemon_reload: true with_items: - etherdfs - name: "{{ my_name }} - Install Samba" set_fact: install_changed: true ================================================ FILE: ansible/install_ethflopd.yml ================================================ - hosts: localhost gather_facts: false vars: my_name: "ethflopd" my_file: "install_{{ my_name }}" module_name: "ethflopd" packages: - make - automake - autoconf - gcc - g++ - git - build-essential - coreutils paths: - { name: "dos", dest: "{{ retronas_path }}", state: "directory", owner: "{{ retronas_user }}", group: "{{ retronas_group }}", mode: "0755" } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "ethflopd.service", dest: "/usr/lib/systemd/system/" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root }}/bin/{{ my_name }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup service" ansible.builtin.service: name: "{{ my_name }}.service" state: started enabled: true daemon_reload: true - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ my_name }}.service" state: restarted daemon_reload: true ================================================ FILE: ansible/install_extract-xiso.yml ================================================ - hosts: localhost gather_facts: false vars: my_name: "extract-xiso" my_file: "install_extract-xiso" module_name: "extract-xiso" packages: - make - gcc - coreutils - cmake templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "/usr/local/bin/extract-xiso" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_extradirs.yml ================================================ --- - hosts: localhost gather_facts: false vars: module_name: "extradirs" tasks: - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_far2l.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "far2l" my_file: "install_{{ my_name }}" module_name: "far2l" packages: - gawk - m4 - libpcre2-dev - libxerces-c-dev - libspdlog-dev - libuchardet-dev - libssh-dev - libssl-dev - libsmbclient-dev - libnfs-dev - libneon27-dev - libarchive-dev - cmake - g++ - gcc - git templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_fenrir-ode-webserver.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "fenrir-ode-webserver" my_file: "install_fenrir-ode-webserver" module_name: "fenrir-ode-webserver" packages: - make - gcc - g++ - coreutils - cmake fenrir_ode_path: "{{ retronas_path }}/fenrir-ode-webserver" fenrir_ode_port: "31994" fenrir_ode_bin: "/usr/local/bin/FenrirServer" my_service: "{{ my_name }}.service" templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}.service", dest: "/usr/lib/systemd/system" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - run build tool" ansible.builtin.shell: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "{{ fenrir_ode_bin }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - create share link" ansible.builtin.file: src: "roms/sega/saturn" dest: "{{ fenrir_ode_path }}" state: link notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted enabled: true daemon_reload: true with_items: "{{ my_service }}" ================================================ FILE: ansible/install_filesystems.yml ================================================ --- - hosts: localhost gather_facts: false vars: module_name: "filesystems" roles: - retronas.role.filesystems - retronas.role.system-config ================================================ FILE: ansible/install_firewalld-zones.yml ================================================ --- # Dependencies - ansible.builtin.import_playbook: install_dnsmasq.yml - ansible.builtin.import_playbook: install_firewalld.yml - hosts: localhost gather_facts: false vars: my_name: "firewalld-zones" my_service: firewalld my_file: "install_{{ my_name }}" module_name: "firewalld-zones" templates: - { name: "retro_to_modern.xml", sub: "policies", dest: "/etc/{{ my_service }}/policies", force: no } - { name: "samba-modern.xml", sub: "services", dest: "/etc/{{ my_service }}/services", force: no } - { name: "ps3netsrv.xml", sub: "services", dest: "/etc/{{ my_service }}/services", force: no } - { name: "modern.xml", sub: "zones", dest: "/etc/{{ my_service }}/zones", force: no } - { name: "retro.xml", sub: "zones", dest: "/etc/{{ my_service }}/zones", force: no } paths: - { name: "{{ my_service }}", dest: "/etc", state: "directory", mode: "0750" } - { name: "{{ my_service }}/policies", dest: "/etc", state: "directory", mode: "0750" } - { name: "{{ my_service }}/services", dest: "/etc", state: "directory", mode: "0750" } - { name: "{{ my_service }}/zones", dest: "/etc", state: "directory", mode: "0750" } firewalld_rules: - { zone: "retro", service: "ssh" } - { zone: "modern", service: "ssh" } - { zone: "retro", service: "cockpit" } - { zone: "modern", service: "cockpit" } tasks: - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Reload firewalld to pickup the new zones" ansible.builtin.service: name: "firewalld" state: restarted daemon_reload: true enabled: true force: true - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Reload firewalld" ansible.builtin.set_fact: install_changed: true - ansible.builtin.import_playbook: install_firewalld.yml vars: changed: "{{ install_changed }}" when: install_changed is defined and install_changed is true ================================================ FILE: ansible/install_firewalld.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "firewalld" my_file: "install_{{ my_name }}" my_services: "firewalld.service" module_name: "firewalld" templates: - { name: "clear-python-bytecode", sub: "workarounds", dest: "/usr/local/sbin", mode: '0750' } - { name: "override.conf", sub: "workarounds", dest: "/etc/systemd/system" } paths: - { name: "{{ my_name }}", dest: "/etc", state: "directory", mode: "0750" } - { name: "{{ my_name }}.service.d", dest: "/etc/systemd/system/", state: "directory", mode: "0750" } packages: - firewalld - python3-firewall collections: - { collection: ansible.posix, creates: ansible/posix } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - install related ansible collections" ansible.builtin.command: cmd: /usr/bin/ansible-galaxy collection install {{ item.collection }} creates: /opt/retronas/ansible/collections/ansible_collections/{{ item.creates }} with_items: "{{ collections }}" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted daemon_reload: true enabled: true force: true with_items: "{{ my_services }}" ================================================ FILE: ansible/install_flippydrive.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "Flippydrive" my_file: "install_flippydrive" my_service: "flippydrive" module_name: "flippydrive" paths: - { name: "gamecube", dest: "{{ retronas_path }}" } - { name: "{{ my_service }}", dest: "/opt" } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_service }}.sh", dest: "/opt/{{ my_service }}", mode: "0755" } - { name: "{{ my_service }}.service", dest: "/etc/systemd/system/" } firewalld_ports: - { port: 7031, protocol: tcp } packages: - unzip - curl tasks: - ansible.builtin.assert: that: ansible_architecture == "x86_64" fail_msg: "Unsupported architecture" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Load RetroNAS systems" ansible.builtin.include_vars: retronas_systems.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from repo" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup service" ansible.builtin.service: name: "{{ my_service }}" state: started enabled: true daemon_reload: true - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ my_service }}" state: restarted daemon_reload: false ================================================ FILE: ansible/install_freestation.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "freestation" my_file: "install_{{ my_name }}" module_name: "freestation" system_key: "freestation" top_level_paths: - { name: "games", enabled: yes, generic: "roms", systems: yes } - { name: "bios", enabled: yes, generic: "bios", systems: yes } templates: - { name: "retronas_freestation_cifs.conf", name_dest: "retronas_freestation.conf", dest: "/etc/samba"} - { name: "retronas_freestation_nfs.conf", name_dest: "retronas_freestation.conf", dest: "/etc/exports.d"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.nfs - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_fsp.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "FSP for Swiss" my_file: "install_fsp" my_service: "fspd" module_name: "fsp" packages: - python3 - python-is-python3 - build-essential - flex - gcc - scons swiss_rw: - .FSP_OK_ADD - .FSP_OK_DEL - .FSP_OK_MKDIR - .FSP_OK_RENAME paths: - { name: "fsp", dest: "{{ retronas_root }}/bin/" } - { name: "etc", dest: "{{ retronas_root }}/bin/fsp/" } - { name: "gamecube", dest: "{{ retronas_path }}" } - { name: "swiss", dest: "{{ retronas_path }}/gamecube" } - { name: "swiss", dest: "{{ retronas_path }}/gamecube/swiss" } # ???? - { name: "tmp", dest: "{{ retronas_path }}/gamecube/swiss" } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} - { name: "{{ my_service }}.conf", dest: "{{ retronas_root }}/bin/fsp/etc" } - { name: "fspd.service", dest: "/usr/lib/systemd/system/" } firewalld_ports: - { port: 2121, protocol: udp } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Load RetroNAS systems" ansible.builtin.include_vars: retronas_systems.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - name: "{{ my_name }} - build layout" ansible.builtin.file: src: "../../roms/{{ item.src }}" dest: "{{ retronas_path }}/gamecube/swiss/{{ item.fspd }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: link loop: "{{ system_map }}" when: item.fspd | length > 0 notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - Set write permissions top level" ansible.builtin.copy: content: "" dest: "{{ retronas_path }}/gamecube/{{ item.0 }}/{{ item.1 }}" force: false owner: "{{ retronas_user }}" group: "{{ retronas_group }}" mode: 0644 with_nested: - ["swiss", "swiss/swiss"] - "{{ swiss_rw }}" - name: "{{ my_name }} - enable startup service" ansible.builtin.service: name: "{{ my_service }}" state: started enabled: true daemon_reload: true - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ my_service }}" state: restarted daemon_reload: false ================================================ FILE: ansible/install_gogrepo.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "gogrepo" my_file: "install_gogrepo" module_name: "gogrepo" packages: - python3 - python-is-python3 - python3-html5lib - git - sudo templates: - { name: "gogrepo_login.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} - { name: "gogrepo_import-cookies.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} - { name: "gogrepo_download.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} - { name: "gogrepo_update.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} - { name: "gogrepo-wrapper.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - create GOG dir" ansible.builtin.file: path: "{{ retronas_path }}/{{ item }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" mode: "0775" state: directory with_items: - gog - name: "{{ my_name }} - download gogrepo+patches (sairuk)" ansible.builtin.shell: chdir: "{{ retronas_root }}/bin" cmd: "git clone https://github.com/sairuk/gogrepo.git" creates: "{{ retronas_root }}/bin/gogrepo" - name: "{{ my_name }} - update gogrepo" ansible.builtin.shell: chdir: "{{ retronas_root }}/bin/gogrepo" cmd: "git pull" - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_hb-store-cdn.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: hb-store-cdn my_file: "install_{{ my_name }}" module_name: "hb-store-cdn" systemd_units: - { name: "{{ my_name }}", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } packages: - git - npm - gcc - g++ - build-essential packages_debian: debian12: - libnode108 debian13: - libnode115 paths: - { name: "{{ my_name }}", dest: "{{ retronas_root }}/bin", state: "directory", mode: "0755", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "bin", dest: "{{ retronas_root }}/bin/{{ my_name }}", state: "directory", mode: "0755", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "ps4", dest: "{{ retronas_path }}", state: "directory", mode: "0755", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "{{ my_name }}-check.sh", dest: "{{ retronas_root }}/bin/{{ my_name }}", mode: "0755"} - { name: "{{ my_name }}.cron", dest: "/etc/cron.d" } - { name: "config.ini", dest: "{{ retronas_root }}/bin/{{ my_name }}" } - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}.service", dest: "/usr/lib/systemd/system" } firewalld_ports: - { port: 6449, protocol: "tcp" } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.package.latest vars: packages: "{{ packages_debian['debian' + ansible_distribution_major_version ] }}" when: ansible_distribution == 'Debian' notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.paths - name: "{{ my_name }} - build layout" ansible.builtin.file: src: "{{ retronas_path }}/roms/sony/playstation4/pkg" dest: "{{ retronas_path }}/ps4/{{ my_name }}" state: link notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root }}/bin/{{ my_name }}/hb-store-cdn-cli-server" - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" when: - item.instance == 'no' notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" when: - item.instance == 'no' - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: restarted daemon_reload: true with_items: "{{ systemd_units }}" when: - item.restart == 'yes' - item.instance == 'no' - name: "{{ my_name }} - Restart instances" ansible.builtin.service: name: "{{ item.1.name }}{{ item.0.dest }}.{{ item.1.type }}" state: restarted daemon_reload: true with_items: - "{{ system_map }}" - "{{ systemd_units }}" when: - item.1.restart == 'yes' - item.1.instance == 'yes' ================================================ FILE: ansible/install_hdldump.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "hdldump" my_file: "install_{{ my_name }}" module_name: "hdldump" packages: - make - gcc - coreutils templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "/usr/local/bin/hdldump" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_hdparm.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "hdparm" my_file: "install_{{ my_name }}" module_name: "hdparm" packages: - hdparm - coreutils scripts: - "{{ my_name }}.sh" - "{{ my_name }}-manager.sh" symlinks: - hdparm-manager-disable-apm - hdparm-manager-disable-standby - hdparm-manager-start-service - hdparm-manager-query-service - hdparm-manager-stop-service - hdparm-manager-drive-selector systemd_units: - { name: "{{ my_name }}", type: "timer", state: "stopped", instance: "no", enabled: "no", restart: "no" } - { name: "{{ my_name }}", type: "service", state: "stopped", instance: "no", enabled: "no", restart: "no" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - check dir" ansible.builtin.file: path: /usr/lib/systemd/system owner: root group: root mode: 0755 state: directory - name: "{{ my_name }} - install script" ansible.builtin.template: src: "templates/{{ my_file }}/{{ item }}.j2" dest: "{{ retronas_root }}/scripts/{{ item }}" owner: root group: root mode: '0755' with_items: - "{{ scripts }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - create startup service" ansible.builtin.template: src: templates/{{ my_file }}/{{ item.name }}.{{ item.type }}.j2 dest: /usr/lib/systemd/system/{{ item.name }}.{{ item.type }} owner: root group: root mode: 0644 with_items: - "{{ systemd_units }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - create symlinks for webui" ansible.builtin.file: src: "{{ retronas_root }}/scripts/{{ my_name }}-manager.sh" dest: "{{ retronas_root }}/scripts/{{ item }}.sh" owner: root group: root state: link with_items: - "{{ symlinks }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup service" ansible.builtin.service: name: "{{ item.name }}" state: started enabled: "{{ item.enabled }}" daemon_reload: true with_items: - "{{ systemd_units }}" when: - item.enabled == "yes" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted daemon_reload: true with_items: - "{{ systemd_units }}" when: - item.restart == "yes" ================================================ FILE: ansible/install_hfsutils.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "hfsutils" my_file: "install_hfsutils" module_name: "hfsutils" packages: - git - autoconf - build-essential templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_hostapd.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "hostapd" my_file: "install_{{ my_name }}" module_name: "hostapd" packages: - hostapd - pwgen my_services: "hostapd-retronas.service" templates: - { name: "hostapd-retronas.conf", sub: "", dest: "/etc/{{ my_name }}", force: no, mode: "0640" } - { name: "hostapd-dnsmasq.conf", sub: "", dest: "/etc/dnsmasq.d/retro/", force: no, mode: "0640" } - { name: "hostapd-retronas.service", sub: "", dest: "/etc/systemd/system" } paths: - { name: "dnsmasq.d", dest: "/etc", state: "directory", mode: "0755" } - { name: "retro", dest: "/etc/dnsmasq.d", state: "directory", mode: "0755" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - generate password" shell: cmd: pwgen -s 12 1 no_log: true register: retronas_wifi_password - name: "{{ my_name }} - generate unique ssid" shell: cmd: echo "retronas-$(pwgen 8 -A -0 -B 1)" no_log: true register: retronas_net_wifi_ssid when: retronas_net_wifi_ssid == "" - name: "{{ my_name }} - update wifi ssid config" lineinfile: path: /opt/retronas/ansible/retronas_vars.yml regexp: ^retronas_net_wifi_ssid.* line: 'retronas_net_wifi_ssid: "{{ retronas_net_wifi_ssid.stdout_lines[0] }}"' when: retronas_net_wifi_ssid is defined - name: "{{ my_name }} - Re-read RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - enable" ansible.builtin.service: name: "{{ item }}" state: started enabled: true daemon_reload: true force: true with_items: "{{ my_services }}" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted daemon_reload: true force: true with_items: "{{ my_services }}" ================================================ FILE: ansible/install_kermit.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "kermit" my_file: "install_{{ my_name }}" module_name: "kermit" packages: - ckermit systemd_units: - { name: "iksd.socket", enabled: yes, state: 'restarted' } templates: - { name: "iksd@.service", dest: "/etc/systemd/system" } - { name: "iksd.socket", dest: "/etc/systemd/system" } firewalld_ports: - { port: 1649, protocol: tcp } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - manage startup services" ansible.builtin.service: name: "{{ item.name }}" state: "{{ item.state|default('stopped') }}" enabled: "{{ item.enabled|default('no') }}" daemon_reload: true with_items: "{{ systemd_units }}" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_lighttpd.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "lighttpd" my_file: "install_{{ my_name }}" module_name: "lighttpd" packages: - { name: "nginx", state: "absent" } - { name: "{{ my_name }}", state: "latest" } config_settings_absent: - { section: null, option: "server.document-root"} - { section: null, option: "server.username"} - { section: null, option: "server.groupname"} templates: - { name: "99-retronas.conf", dest: "/etc/{{ my_name }}/conf-available", mode: "0640"} conf_enable: - "99-retronas.conf" systemd_units: - { name: "{{ my_name }}", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } firewalld_rules: - { service: "http" } - { service: "https" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - manage packages" ansible.builtin.package: name: "{{ item.name }}" state: "{{ item.state }}" with_items: "{{ packages }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - configure main config" ansible.builtin.ini_file: path: /etc/{{ my_name }}/{{ my_name }}.conf section: "{{ item.section }}" option: "{{ item.option }}" state: absent with_items: "{{ config_settings_absent }}" notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - enable conf" ansible.builtin.file: src: /etc/{{ my_name }}/conf-available/{{ item }} dest: /etc/{{ my_name }}/conf-enabled/{{ item }} state: "link" with_items: "{{ conf_enable }}" - name: "{{ my_name }} - set logfile permissions" ansible.builtin.file: path: /var/log/{{ my_name }} owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory recurse: true - name: "{{ my_name }} - set run dir permissions" ansible.builtin.file: path: /var/run/{{ my_name }} owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory recurse: true - name: "{{ my_name }} - configure server.errorlog" ansible.builtin.ini_file: path: /etc/{{ my_name }}/{{ my_name }}.conf section: null option: server.errorlog state: absent notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item.name }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" with_items: "{{ systemd_units }}" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}" state: restarted with_items: "{{ systemd_units }}" when: item.restart == "yes" ================================================ FILE: ansible/install_linux-dexdrive.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "linux-dexdrive" my_file: "install_{{ my_name }}" module_name: "linux-dexdrive" packages: - git - build-essential templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "makefile.patch", dest: "/tmp" } - { name: "dexdrive_dumper.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}.service", dest: "/etc/systemd/system" } systemd_units: - { name: "{{ my_name }}", type: 'service', state: "stopped", enabled: "no", restart: "no", instance: "no" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Load RetroNAS systems" ansible.builtin.include_vars: retronas_systems.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} daemon-reload" - name: "{{ my_name }} - build source" ansible.builtin.shell: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "/usr/local/bin/dexattach" - name: "{{ my_name }} - dexdrive module" ansible.builtin.lineinfile: path: /etc/modules-load.d/modules.conf regex: "^dexdrive$" line: "dexdrive" - name: "{{ my_name }} - {{ retronas_user }} groups" ansible.builtin.user: name: "{{ retronas_user }}" group: "disk" append: true - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} daemon-reload" ansible.builtin.systemd: daemon_reload: true ================================================ FILE: ansible/install_linux-gadgets.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "linux-gadgets" my_file: "install_{{ my_name }}" module_name: "linux-gadgets" templates: - { name: "gadget-mass-storage-manage.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} paths: - { name: "images", dest: "{{ retronas_path }}", state: "directory", mode: "0755", owner: "{{ retronas_user }}", group: "{{ retronas_group }}"} tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_litch.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "litch" my_file: "install_litch" module_name: "litch" packages: - python3 - python3-bs4 - git templates: - { name: "litch_login.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "litch_download.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "litch_download_clean.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "litch_claim.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - create GOG dir" ansible.builtin.file: path: "{{ retronas_path }}/itchio" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" mode: "0775" state: directory - name: "{{ my_name }} - download litch" ansible.builtin.shell: chdir: "{{ retronas_root }}/bin" cmd: "git clone https://github.com/sairuk/litch.git" creates: "{{ retronas_root }}/bin/litch" - name: "{{ my_name }} - update litch" ansible.builtin.shell: chdir: "{{ retronas_root }}/bin/litch" cmd: "git pull" - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_lynx.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "lynx" my_file: "install_lynx" module_name: "lynx" packages: - lynx tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_macproxy_classic.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "macproxy_classic" my_file: "install_macproxy_classic" module_name: "macproxy_classic" packages: - python3 - python3-venv - python3-pip service_name: "macproxy" templates: - { name: "{{ service_name }}.service", dest: "/etc/systemd/system" } repo: https://github.com/rdmark/macproxy_classic.git firewalld_ports: - { port: 5001, protocol: tcp } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - clone repo" ansible.builtin.git: repo: "{{ repo }}" dest: /opt/{{ my_name }} - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} Restart Services" ansible.builtin.service: name: "{{ service_name }}.service" state: started enabled: true daemon_reload: true ================================================ FILE: ansible/install_mc.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "mc" my_file: "install_mc" module_name: "mc" packages: - mc tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Load RetroNAS systems" ansible.builtin.include_vars: retronas_systems.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_megatools.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "megatools" my_file: "install_megatools" module_name: "megatools" packages_build: - build-essential - libglib2.0-dev - libssl-dev - libcurl4-openssl-dev - make - gcc - coreutils - meson - ninja-build packages: - megatools templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - block: - name: "{{ my_name }} - Install distro package" ansible.builtin.import_role: name: retronas.role.package.latest rescue: - ansible.builtin.set_fact: package_distro: false - meta: clear_host_errors - block: - ansible.builtin.import_role: name: retronas.role.package.latest vars: packages: "{{ packages_build }}" - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "/usr/local/bin/megatools" when: not package_distro|default(true) - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_minicom.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "minicom" my_file: "install_{{ my_name }}" my_dir: "" module_name: "minicom" append_user_group: "dialout" packages: - minicom - lrzsz templates: - { name: "minirc.dfl", dest: "/etc/minicom", mode: "0644", owner: "{{ retronas_user }}", group: "{{ retronas_user }}", force: no } - { name: "minicom.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} script_links: - { dest: "minicom-config.sh", src: "minicom.sh" } paths: - { name: "{{ my_name }}", dest: "/etc", state: "directory", mode: "0755", owner: "{{ retronas_user }}", group: "{{ retronas_user }}" } - { name: "{{ my_name }}", dest: "{{ retronas_path }}", state: "directory", mode: "0755", owner: "{{ retronas_user }}", group: "{{ retronas_user }}"} tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.update-user - name: "{{ my_name }} - script links" ansible.builtin.file: dest: "{{ retronas_root }}/scripts/{{ item.dest }}" src: "{{ retronas_root }}/scripts/{{ item.src }}" state: link with_items: "{{ script_links }}" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_mister-organize.yml ================================================ --- - hosts: localhost vars: my_name: "MiSTer Organize" my_file: "install_mister-organize" module_name: "mister-organize" packages: - git - curl - unzip paths: - { name: "mister-organize", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "romimport", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755", force: true} - { name: "mister-organize.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - ansible.builtin.assert: that: ansible_architecture == "x86_64" fail_msg: "Unsupported architecture" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Load RetroNAS Systems" ansible.builtin.include_vars: retronas_systems.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from project repo" ansible.builtin.git: repo: "https://github.com/MiSTerOrganize/MiSTerOrganize.git" dest: "{{ retronas_path}}/{{ module_name }}" single_branch: true clone: true update: true force: true - name: "{{ my_name }} - setup local" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1" - ansible.builtin.import_role: name: retronas.role.system-config - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system vars: system_key: "{{ module_name }}" ================================================ FILE: ansible/install_mister_cifs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "MiSTer CIFS" my_file: "install_mister_cifs" module_name: "mister_cifs" system_key: "mister" top_level_paths: - { name: "games", enabled: yes, generic: "roms", systems: yes } - { name: "saves", enabled: yes, generic: "saves", systems: yes } - { name: "savestates", enabled: yes, generic: "savestates", systems: yes } - { name: "BIOS", enabled: yes, generic: "bios", systems: yes } - { name: "wallpapers", enabled: yes, generic: "wallpapers", systems: no } save_overrides: - { name: "GAMEBOY2P", src: "nintendo/gameboy2p" } - { name: "GBA2P", src: "nintendo/gameboyadvance2p" } templates: # - { name: "retronas_mister.conf", dest: "/etc/samba" } - { name: "retronas-mister-dirs.service", dest: "/etc/systemd/system" } - { name: "retronas-mister-dirs.timer", dest: "/etc/systemd/system" } systemd_units: - { name: "retronas-mister-dirs", type: 'service', state: "stopped", enabled: "no", restart: "no", instance: "no" } - { name: "retronas-mister-dirs", type: 'timer', state: "stopped", enabled: "no", restart: "no", instance: "no" } dirs_only: false savedirs: - "saves" - "savestates" tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system - name: "{{ my_name }} - create custom save directories" ansible.builtin.file: dest: "{{ retronas_path }}/{{ item.1 }}/{{ item.0.src|lower }}" state: directory loop: "{{ save_overrides|product(savedirs)|list }}" - name: "{{ my_name }} - create custom save links" ansible.builtin.file: src: "../../{{ item.1 }}/{{ item.0.src|lower }}" dest: "{{ retronas_path }}/{{ system_key }}/{{ item.1 }}/{{ item.0.name }}" state: link loop: "{{ save_overrides|product(savedirs)|list }}" - ansible.builtin.import_role: name: retronas.role.templates when: dirs_only is false - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} daemon-reload" ansible.builtin.systemd: daemon_reload: true ================================================ FILE: ansible/install_mtcp-netdrive.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "mtcp-netdrive" my_file: "install_mtcp-netdrive" module_name: "mtcp-netdrive" packages: - screen - curl - unzip paths: - { name: "{{ my_name }}", dest: "/opt", state: "directory", mode: "0755", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "install_mtcp-netdrive.sh", dest: "{{ retronas_root }}/scripts", mode: "0755", force: "yes" } - { name: "mtcp-netdrive.service", dest: "/etc/systemd/system", force: "yes" } - { name: "mtcp-netdrive.sh", dest: "{{ retronas_root }}/scripts", mode: "0755", force: "yes" } firewalld_rules: - { zones: retro, service: mtcp-netdrive } my_services: - mtcp-netdrive tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - install mtcp-netdrive" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item }}" state: started enabled: true daemon-reload: true with_items: "{{ my_services }}" # # FIREWALL # - name: "{{ my_name }} - checking firewall rule" ansible.builtin.stat: path: /etc/firewalld/services register: firewalld_services - name: "{{ my_name }} - Generate firewall service" ansible.builtin.template: src: "templates/{{ my_file }}/mtcp-netdrive.xml.j2" dest: "/etc/firewalld/services/mtcp-netdrive.xml" owner: root group: root mode: 0644 when: firewalld_services.stat.exists - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_mysticbbs.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "mysticbbs" my_file: "install_mysticbbs" module_name: "mysticbbs" packages: - p7zip-full - p7zip-rar - screen paths: - { name: "{{ my_name }}", dest: "/opt", state: "directory", mode: "0755", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "mysticbbs.sh", dest: "{{ retronas_root }}/scripts", mode: "0755", force: "yes" } - { name: "install_mysticbbs.sh", dest: "{{ retronas_root }}/scripts", mode: "0755", force: "yes" } - { name: "mysticbbs-mis.service", dest: "/etc/systemd/system", force: "yes" } - { name: "retronas_create_fileareas.ini", dest: "/opt/mysticbbs", force: "yes" } - { name: "retronas_massupload.ini", dest: "/opt/mysticbbs", force: "yes" } - { name: "create_filebone_na.py", dest: "/opt/mysticbbs", force: "yes" } firewalld_rules: - { zones: retro, service: mysticbbs } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Enable non-free repo for p7zip-rar" ansible.builtin.apt_repository: repo: deb http://deb.debian.org/debian/ {{ ansible_distribution_release }} main non-free-firmware non-free state: present - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - install mysticbbs" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" - name: "{{ my_name }} - daemon-reload" ansible.builtin.command: cmd: "systemctl daemon-reload" # # FIREWALL # - name: "{{ my_name }} - checking firewall rule" ansible.builtin.stat: path: /etc/firewalld/services register: firewalld_services - name: "{{ my_name }} - Generate firewall service" ansible.builtin.template: src: "templates/{{ my_file }}/mysticbbs.xml.j2" dest: "/etc/firewalld/services/mysticbbs.xml" owner: root group: root mode: 0644 when: firewalld_services.stat.exists - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_nabu.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "nabu" my_file: "install_{{ my_name }}" my_dir: /opt/nabu module_name: "nabu" systemd_units: - { name: "nabu", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } packages: - unzip templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } links: - { dest: "/home/{{ retronas_user }}/NABU Internet Adapter", src: "{{ retronas_path }}/roms/nabu" } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - add {{ retronas_user }} to dialout group" ansible.builtin.user: name: "{{ retronas_user }}" group: "dialout" append: true - name: "{{ my_name }} - links" ansible.builtin.file: src: "{{ item.src }}" dest: "{{ item.dest }}" state: "{{ item.state|default('link') }}" with_items: "{{ links }}" - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root}} {{ my_dir }}/nabu.sh" ================================================ FILE: ansible/install_nbd-client.yml ================================================ --- - hosts: localhost vars: my_name: "nbd-client" my_file: "install_nbd-client" module_name: "nbd-client" packages: - nbd-client templates: - { name: "nbd.conf", dest: "/etc/modules-load.d/" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - enable ndb kernel module" ansible.builtin.shell: cmd: "modprobe nbd" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_netatalk2.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "Netatalk2" my_file: "install_netatalk2" packages: - libacl1 - libattr1 - libavahi-client3 - libavahi-common3 - libc6 - libcomerr2 - libcrack2 - libcups2 - libdb5.3 - libgcrypt20 - libgssapi-krb5-2 - libk5crypto3 - libkrb5-3 - libldap-2.4-2 - libpam0g - libpam-modules - libwrap0 - netbase - perl - aria2 - avahi-daemon tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.debug: msg: "No longer supported, use Netatalk 4" - ansible.builtin.assert: that: true == false - name: "{{ my_name }} - unhold netatalk package" ansible.builtin.shell: "/usr/bin/apt-mark unhold netatalk" - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - download package for arm64" ansible.builtin.shell: chdir: "/tmp" cmd: "aria2c --allow-overwrite=true http://mirror.aarnet.edu.au/pub/debian/pool/main/n/netatalk/netatalk_2.2.5-2+deb9u1_arm64.deb http://ftp.debian.org/debian/pool/main/n/netatalk/netatalk_2.2.5-2+deb9u1_arm64.deb" when: ansible_architecture == "aarch64" - name: "{{ my_name }} - download package for armhf" ansible.builtin.shell: chdir: "/tmp" cmd: "aria2c --allow-overwrite=true http://mirror.aarnet.edu.au/pub/debian/pool/main/n/netatalk/netatalk_2.2.5-2+deb9u1_armhf.deb http://ftp.debian.org/debian/pool/main/n/netatalk/netatalk_2.2.5-2+deb9u1_armhf.deb" when: ansible_architecture == "armhf" - name: "{{ my_name }} - download package for x86_64" ansible.builtin.shell: chdir: "/tmp" cmd: "aria2c --allow-overwrite=true http://mirror.aarnet.edu.au/pub/debian/pool/main/n/netatalk/netatalk_2.2.5-2+deb9u1_amd64.deb http://ftp.debian.org/debian/pool/main/n/netatalk/netatalk_2.2.5-2+deb9u1_amd64.deb" when: ansible_architecture == "x86_64" - name: "{{ my_name }} - download package for x86" ansible.builtin.shell: chdir: "/tmp" cmd: "aria2c --allow-overwrite=true http://mirror.aarnet.edu.au/pub/debian/pool/main/n/netatalk/netatalk_2.2.5-2+deb9u1_i386.deb http://ftp.debian.org/debian/pool/main/n/netatalk/netatalk_2.2.5-2+deb9u1_i386.deb" when: ansible_architecture == "i386" - name: "{{ my_name }} - install package" ansible.builtin.shell: chdir: "/tmp" cmd: "dpkg -i netatalk_2.2.5*.deb" - name: "{{ my_name }} - hold netatalk package" ansible.builtin.shell: "/usr/bin/apt-mark hold netatalk" - name: "{{ my_name }} - configure /etc/default/netatalk" ansible.builtin.template: src: "templates/{{ my_file }}/default.j2" dest: /etc/default/netatalk owner: root group: root mode: '0644' notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - configure AppleVolumes.default" ansible.builtin.template: src: "templates/{{ my_file }}/AppleVolumes.default.j2" dest: /etc/netatalk/AppleVolumes.default owner: root group: root mode: '0644' notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - configure afpd.conf" ansible.builtin.template: src: "templates/{{ my_file }}/afpd.conf.j2" dest: /etc/netatalk/afpd.conf owner: root group: root mode: '0644' notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item }}" state: started enabled: true with_items: - avahi-daemon - netatalk handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted with_items: - avahi-daemon - netatalk - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "netatalk2" module_state: "present" ================================================ FILE: ansible/install_netatalk2x.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "Netatalk2.X" my_file: "install_netatalk2x" packages: - avahi-daemon - build-essential - make - automake - autoconf - libdb-dev - libdb++-dev - libavahi-common-dev - libavahi-client-dev - libavahi-core-dev - libdbus-1-dev - libssl-dev - autotools-dev - libtool - libcups2-dev - libavahi-client-dev - libgcrypt20-dev - expect - libltdl-dev - libtool-bin - libevent-dev services: - avahi-daemon - atalkd - afpd - papd - timelord - a2boot templates: - { name: "afpexpect.sh", dest: "{{ retronas_root }}/bin/netatalk2x/bin", mode: "0754" } - { name: "AppleVolumes.default", dest: "{{ retronas_root }}/bin/netatalk2x/etc/netatalk" } - { name: "afpd.conf", dest: "{{ retronas_root }}/bin/netatalk2x/etc/netatalk" } - { name: "atalkd.conf", dest: "{{ retronas_root }}/bin/netatalk2x/etc/netatalk" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - check if netatalk package is available" ansible.builtin.shell: "/usr/bin/apt-cache search netatalk | grep netatalk" register: result failed_when: - result.rc >= 2 when: - ansible_distribution == "Debian" - block: - name: "{{ my_name }} - unhold netatalk package" ansible.builtin.shell: "/usr/bin/apt-mark unhold netatalk" - name: "{{ my_name }} - remove package-based Netatalk" ansible.builtin.package: name: netatalk state: absent - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - create install script" ansible.builtin.template: src: "templates/{{ my_file }}/{{ my_file }}.sh.j2" dest: "{{ retronas_root }}/scripts/{{ my_file }}.sh" owner: root group: root mode: '0755' - name: "{{ my_name }} - install from source" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" - name: "{{ my_name }} - templates" ansible.builtin.template: src: "templates/{{ my_file }}/{{ item.name }}.j2" dest: "{{ item.dest }}/{{ item.name }}" owner: "{{ item.owner|default('root') }}" group: "{{ item.group|default('root') }}" mode: "{{ item.mode|default('0644') }}" with_items: "{{ templates }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item }}" state: started enabled: true with_items: "{{ services }}" when: - result is defined - result.rc == 0 handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted with_items: "{{ services }}" - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "netatalk2x" module_state: "present" ================================================ FILE: ansible/install_netatalk3.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "Netatalk3" my_file: "install_netatalk3" packages: - avahi-daemon - netatalk my_services: - avahi-daemon - netatalk config_settings: - { section: "Global", option: "uam list", value: "uams_guest.so uams_clrtxt.so uams_dhx.so uams_dhx2.so" } - { section: "Global", option: "hostname", value: "retroafp" } - { section: "Global", option: "mimic model", value: "PowerMac" } - { section: "Global", option: "zeroconf", value: "yes" } - { section: "Global", option: "log level", value: "info" } - { section: "Global", option: "log file", value: "/var/log/afp.log" } - { section: "Global", option: "afp listen", value: "0.0.0.0" } - { section: "Global", option: "include", value: "/etc/netatalk/retronas.conf" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - check if netatalk package is available" ansible.builtin.shell: "/usr/bin/apt-cache search netatalk | grep netatalk" register: result failed_when: - result.rc >= 2 - name: "{{ my_name }} - set fact if netatalk is not present" ansible.builtin.set_fact: no_netatalk: true when: result.rc == 1 - name: "{{ my_name }} - end play if no netatalk package" ansible.builtin.meta: end_play when: no_netatalk is defined and no_netatalk is true - name: "{{ my_name }} - unhold netatalk package" ansible.builtin.shell: "/usr/bin/apt-mark unhold netatalk" when: result.rc == 0 - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - configure" ansible.builtin.ini_file: dest: /etc/netatalk/afp.conf section: "{{ item.section }}" option: "{{ item.option }}" value: "{{ item.value }}" with_items: "{{ config_settings }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - configure retro shares" ansible.builtin.template: src: "templates/{{ my_file }}/retronas.conf.j2" dest: /etc/netatalk/retronas.conf owner: root group: root mode: '0644' notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item }}" state: started enabled: true with_items: "{{ my_services }}" handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted with_items: "{{ my_services }}" - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "netatalk3" module_state: "present" when: no_netatalk is undefined ================================================ FILE: ansible/install_netatalk3_source.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "Netatalk3" my_file: "install_netatalk3" packages: - avahi-daemon - build-essential - libevent-dev - libssl-dev - libgcrypt-dev - libkrb5-dev - libpam0g-dev - libwrap0-dev - libdb-dev - libtdb-dev - libavahi-client-dev - libacl1-dev - libldap2-dev - libcrack2-dev - systemtap-sdt-dev - libdbus-1-dev - libdbus-glib-1-dev - libglib2.0-dev - libio-socket-inet6-perl - tracker packages_debian: debian11: - libmysqlclient-dev - libtracker-sparql-2.0-dev debian12: - default-libmysqlclient-dev - libtracker-sparql-3.0-dev packages_ubuntu: - libmysqlclient-dev - libtracker-sparql-2.0-dev - libtracker-miner-2.0-dev my_services: - avahi-daemon - netatalk config_settings: - { section: "Global", option: "uam list", value: "uams_guest.so uams_clrtxt.so uams_dhx.so uams_dhx2.so" } - { section: "Global", option: "hostname", value: "retroafp" } - { section: "Global", option: "mimic model", value: "PowerMac" } - { section: "Global", option: "zeroconf", value: "yes" } - { section: "Global", option: "log level", value: "info" } - { section: "Global", option: "log file", value: "/var/log/afp.log" } - { section: "Global", option: "afp listen", value: "0.0.0.0" } - { section: "Global", option: "include", value: "/etc/netatalk/retronas.conf" } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts/", mode: '0755'} - { name: "netatalk.service", dest: "/etc/systemd/system"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - check if netatalk package is available" ansible.builtin.shell: "/usr/bin/apt-cache search netatalk | grep netatalk" register: result failed_when: - result.rc >= 2 - name: "{{ my_name }} - unhold netatalk package" ansible.builtin.shell: "/usr/bin/apt-mark unhold netatalk" when: result.rc == 0 - name: "{{ my_name }} - remove package-based Netatalk" ansible.builtin.package: name: netatalk state: absent - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - Install build tools (debian)" ansible.builtin.package: name: "{{ packages_debian['debian' + ansible_distribution_major_version ] }}" state: latest when: ansible_distribution == 'Debian' - name: "{{ my_name }} - Install build tools (ubuntu)" ansible.builtin.package: name: "{{ packages_ubuntu }}" state: latest when: ansible_distribution == 'Ubuntu' - name: "{{ my_name }} - templates" ansible.builtin.template: src: "templates/{{ my_file }}/{{ item.name }}.j2" dest: "{{ item.dest }}/{{ item.name }}" owner: "{{ item.owner|default('root') }}" group: "{{ item.group|default('root') }}" mode: "{{ item.mode|default('0644') }}" with_items: "{{ templates }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - install from source" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" - name: "{{ my_name }} - configure" ansible.builtin.ini_file: dest: /etc/netatalk/afp.conf section: "{{ item.section }}" option: "{{ item.option }}" value: "{{ item.value }}" with_items: "{{ config_settings }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - configure retro shares" ansible.builtin.template: src: "templates/{{ my_file }}/retronas.conf.j2" dest: /etc/netatalk/retronas.conf owner: root group: root mode: '0644' notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item }}" state: started enabled: true with_items: "{{ my_services }}" handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted daemon-reload: true with_items: "{{ my_services }}" - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "netatalk3" module_state: "present" ================================================ FILE: ansible/install_netatalk4.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "Netatalk4" my_file: "install_netatalk4" module_name: "netatalk4" packages: - avahi-daemon - avahi-utils - bison - build-essential - cmark - flex - libacl1-dev - libavahi-client-dev - libcmark-dev - libcrack2-dev - libdb-dev - libdbus-1-dev - libdbus-glib-1-dev - libevent-dev - libgcrypt-dev - libglib2.0-dev - libiniparser-dev - libio-socket-inet6-perl - libkrb5-dev - libldap2-dev - libmptcpwrap0 - libpam0g-dev - libssl-dev - libtdb-dev - libtirpc-dev - libtirpc3 - libwrap0-dev - meson - ninja-build - po4a - systemtap-sdt-dev - tracker packages_debian: debian11: - libmysqlclient-dev - libtracker-sparql-2.0-dev debian12: - default-libmysqlclient-dev - libtracker-sparql-3.0-dev debian13: - default-libmysqlclient-dev - libtracker-sparql-3.0-dev packages_ubuntu: - libmysqlclient-dev - libtracker-sparql-2.0-dev - libtracker-miner-2.0-dev my_services: - avahi-daemon - atalkd - netatalk afp_settings: - { section: "Global", option: "uam list", value: "uams_guest.so uams_clrtxt.so uams_dhx.so uams_dhx2.so" } - { section: "Global", option: "hostname", value: "retroafp" } - { section: "Global", option: "mimic model", value: "PowerMac" } - { section: "Global", option: "zeroconf", value: "yes" } - { section: "Global", option: "log level", value: "info" } - { section: "Global", option: "log file", value: "/var/log/afp.log" } - { section: "Global", option: "afp listen", value: "0.0.0.0" } - { section: "Global", option: "appletalk", value: "yes" } - { section: "Global", option: "spotlight", value: "yes" } - { section: "Global", option: "legacy icon", value: "globe" } # - { section: "Global", option: "include", value: "/opt/retronas/bin/netatalk4/etc/retronas.conf" } - { section: "retronas", option: "path", value: "{{ retronas_path }}" } - { section: "retronas", option: "rwlist", value: "{{ retronas_user }}" } - { section: "retronas", option: "rolist", value: "guest" } - { section: "retronas", option: "follow symlinks", value: "yes" } paths: - { name: "netatalk4", dest: "/opt/retronas/bin", mode: '0755' } - { name: "etc", dest: "/opt/retronas/bin/netatalk4", mode: '0755' } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts/", mode: '0755' } # - { name: "retronas.conf", dest: "/opt/retronas/bin/netatalk4/etc" } old_services: - { name: "atalkd.service", dest: "/etc/systemd/system"} - { name: "netatalk.service", dest: "/etc/systemd/system"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - check if netatalk package is available" ansible.builtin.shell: "/usr/bin/apt-cache search netatalk | grep netatalk" register: result failed_when: - result.rc >= 2 - name: "{{ my_name }} - unhold netatalk package" ansible.builtin.shell: "/usr/bin/apt-mark unhold netatalk" when: result.rc == 0 - name: "{{ my_name }} - remove package-based Netatalk" ansible.builtin.package: name: netatalk state: absent - name: "{{ my_name }} - remove old service files" ansible.builtin.stat: path: "{{ item.dest }}/{{ item.name }}" loop: "{{ old_services }}" register: old_services_check - name: "{{ my_name }} - Stopping existing netatalk service(s) during installation" ansible.builtin.service: name: "{{ item.stat.path }}" state: stopped daemon-reload: true loop: "{{ old_services_check.results }}" when: old_services_check is defined and item.stat.exists is true - name: "{{ my_name }} - Remove old service files" ansible.builtin.file: path: "{{ item.stat.path }}" state: absent loop: "{{ old_services_check.results }}" when: old_services_check is defined and item.stat.exists is true - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - Install build tools (debian)" ansible.builtin.package: name: "{{ packages_debian['debian' + ansible_distribution_major_version ] }}" state: latest when: ansible_distribution == 'Debian' - name: "{{ my_name }} - Install build tools (ubuntu)" ansible.builtin.package: name: "{{ packages_ubuntu }}" state: latest when: ansible_distribution == 'Ubuntu' - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - install from source" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" - name: "{{ my_name }} - configure" ansible.builtin.ini_file: dest: /opt/retronas/bin/netatalk4/etc/afp.conf section: "{{ item.section }}" option: "{{ item.option }}" value: "{{ item.value }}" with_items: "{{ afp_settings }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - atalkd" ansible.builtin.lineinfile: path: /opt/retronas/bin/netatalk4/etc/atalkd.conf regexp: "^{{ ansible_default_ipv4.interface }}.*" line: "{{ ansible_default_ipv4.interface }} -router -phase 2 -net 1 -zone \"retroafp\"" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item }}" state: started enabled: true with_items: "{{ my_services }}" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted daemon-reload: true with_items: "{{ my_services }}" ================================================ FILE: ansible/install_netlink.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "netlink" my_file: "install_netlink" module_name: "netlink" packages: - curl - unzip - dnsmasq - dnsutils - libnetfilter-queue-dev - libnetfilter-queue1 - ppp - arping - nftables - tcpd - wvdial - python3-pip templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}.service", dest: "/etc/systemd/system" } - { name: "{{ my_name }}.conf", dest: "/etc/dnsmasq.d" } - { name: "{{ my_name }}.patch", dest: "/tmp" } paths: - { name: "dnsmasq.d", dest: "/etc" } firewalld_ports: - { zone: modern, port: 65432, protocol: tcp } - { zone: modern, port: 20001, protocol: udp } - { zone: modern, port: 20002, protocol: udp } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Run installer" ansible.builtin.shell: cmd: "./{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ retronas_root }}/scripts" executable: /bin/bash notify: "{{ my_name }} Restart Services" - name: "{{ my_name }} - Patch com port range detection" ansible.builtin.patch: src: /tmp/{{ my_name }}.patch dest: /opt/{{ my_name }}/tunnel.py - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} Restart Services" ansible.builtin.service: name: "{{ item }}" state: started enabled: true daemon_reload: true with_items: - "{{ my_name }}.service" ================================================ FILE: ansible/install_netmount.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "netmount" my_file: "install_netmount" module_name: "netmount" packages: - bzip2 - python3 - python3-yaml systemd_units: - { name: "netmount-drives-retronas", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "netmount-confman.py", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "netmount-confman.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "retronas.yaml", dest: "{{ retronas_path }}/config/netmount", mode: "0755" } firewalld_rules: - { zones: retro, service: netmount } paths: - dos - config/netmount tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - build top level" ansible.builtin.file: path: "{{ retronas_path }}/{{ item }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory mode: "0775" loop: "{{ paths }}" notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from git" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "/opt/netmount/netmount" - name: "{{ my_name }} - Build service files" ansible.builtin.shell: "python3 {{ retronas_root }}/scripts/netmount-confman.py" - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" when: - item.instance == 'no' notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: restarted daemon_reload: true with_items: "{{ systemd_units }}" when: - item.restart == 'yes' - item.instance == 'no' ================================================ FILE: ansible/install_network-presets-ethernet-dhcp.yml ================================================ --- # networkmanager - ansible.builtin.import_playbook: install_networkmanager.yml - hosts: localhost gather_facts: false vars: my_name: "network-presets-standalone-ethernet-dhcp" my_file: "install_{{ my_name }}" connections: - { name: "ethernet", state: "absent" } # remove it first because modules are a pain some times - { name: "wifi-retronas", state: "absent" } - { name: "ethernet", ipv4method: "auto", ifname: "{{ retronas_net_retro_interface }}", type: "ethernet" } disable_services: - dhcpcd - dnsmasq-retro - firewalld - hostapd-retronas tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "config connections" community.general.nmcli: type: "{{ item.type | default('ethernet') }}" conn_name: "{{ item.name }}" ip4: "{{ item.ipv4addr | default(omit) }}" gw4: "{{ item.ipv4gw | default(omit) }}" dns4: "{{ item.ipv4dns | default(omit) }}" method4: "{{ item.ipv4method | default('manual') }}" ifname: "{{ item.ifname | default(omit) }}" route_metric4: "{{ item.metric | default(omit) }}" state: "{{ item.state| default('present') }}" autoconnect: true with_items: - '{{ connections }}' - name: "{{ my_name }} - check which services is installed" ansible.builtin.stat: path: /usr/lib/systemd/system/{{ item }}.service loop: "{{ disable_services }}" register: services_installed - name: "{{ my_name }} - back to dhcp, turn off our services" ansible.builtin.service: name: "{{ item.item }}" state: stopped enabled: false force: true loop: "{{ services_installed.results }}" when: item.stat.exists is true # alt presets removed - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "network-presets-standalone" module_state: "absent" - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "network-presets-zoned" module_state: "absent" ================================================ FILE: ansible/install_network-presets-standalone.yml ================================================ --- # networkmanager - ansible.builtin.import_playbook: install_networkmanager.yml # hostapd # using NM api mode now # - ansible.builtin.import_playbook: install_hostapd.yml # dnsmassq # IMPORTED IN DNSMASQ-RETRO - ansible.builtin.import_playbook: install_dnsmasq.yml - ansible.builtin.import_playbook: install_dnsmasq-retro.yml # ntp - ansible.builtin.import_playbook: install_ntp.yml # dhpcd # - ansible.builtin.import_playbook: install_dhcpcd.yml - hosts: localhost gather_facts: true vars: my_name: "network-presets-standalone" my_file: "install_{{ my_name }}" templates: - { name: "dhcpcd.conf", dest: "/etc", mode: "0640", force: "yes" } connections: - { name: "ethernet", state: "absent" } - { name: "wifi-retronas", state: "absent" } my_packages: - pwgen tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Install packages" ansible.builtin.package: name: "{{ my_packages }}" state: latest - name: "{{ my_name }} - generate password" shell: cmd: pwgen -s 12 1 no_log: true changed_when: false register: retronas_wifi_password - name: "{{ my_name }} - generate unique ssid" shell: cmd: echo "retronas-$(pwgen 8 -A -0 -B 1)" register: retronas_net_wifi_ssid_generated changed_when: false when: retronas_net_wifi_ssid == "" - name: "{{ my_name }} - config connections" community.general.nmcli: type: "{{ item.type | default('ethernet') }}" conn_name: "{{ item.name }}" ip4: "{{ item.ipv4addr | default(omit) }}" gw4: "{{ item.ipv4gw | default(omit) }}" dns4: "{{ item.ipv4dns | default(omit) }}" method4: "{{ item.ipv4method | default('manual') }}" ifname: "{{ item.ifname | default(omit) }}" route_metric4: "{{ item.metric | default(omit) }}" state: "{{ item.state| default('present') }}" autoconnect: true with_items: - '{{ connections }}' - name: "{{ my_name }} - config ethernet" community.general.nmcli: type: "ethernet" conn_name: "ethernet" ifname: "{{ retronas_net_retro_interface }}" ip4: "{{ retronas_net_retro_ip }}/{{ retronas_net_retro_subnet }}" gw4: "{{ retronas_net_retro_router }}" dns4: "{{ retronas_net_retro_dns }}" method4: "manual" state: "present" autoconnect: true - name: "{{ my_name }} - configure wifi ap" community.general.nmcli: type: "wifi" conn_name: "wifi-retronas" ifname: "{{ retronas_net_wifi_interface }}" ssid: "{{ retronas_net_wifi_ssid if retronas_net_wifi_ssid_generated == '' else retronas_net_wifi_ssid_generated.stdout }}" ip4: "{{ retronas_net_wifi_ip }}/{{ retronas_net_wifi_subnet }}" # gw4: "{{ retronas_net_wifi_router }}" never_default4: true dns4: "{{ retronas_net_wifi_dns }}" method4: "manual" wifi_sec: key-mgmt: wpa-psk psk: "{{ retronas_wifi_password.stdout }}" wifi: mode: "ap" channel: "{{ retronas_net_wifi_channel }}" band: "{{ retronas_net_wifi_hwmode }}" state: present autoconnect: true - name: "{{ my_name }} - templates" ansible.builtin.template: src: "templates/{{ my_file }}/{{ item.name }}.j2" dest: "{{ item.dest }}/{{ item.name }}" owner: "{{ item.owner|default('root') }}" group: "{{ item.group|default('root') }}" mode: "{{ item.mode|default('0644') }}" force: "{{ item.force|default('yes') }}" loop: "{{ templates }}" - name: "{{ my_name }} - check firewalld is installed" ansible.builtin.stat: path: /usr/lib/systemd/system/firewalld.service register: firewalld_installed - name: "{{ my_name }} - everything is retro here so disabling the firewalld zoned config" ansible.builtin.service: name: firewalld.service state: stopped enabled: false force: true when: firewalld_installed.stat.exists is true - name: "{{ my_name }} - check dhcpcd is installed" ansible.builtin.stat: path: /usr/lib/systemd/system/dhcpcd.service register: dhcpcd_installed - name: "{{ my_name }} - restart dhcpcd" ansible.builtin.service: name: dhcpcd.service state: stopped enabled: false force: true when: dhcpcd_installed.stat.exists is true - name: "{{ my_name }} - check hostapd is installed" ansible.builtin.stat: path: /usr/lib/systemd/system/hostapd.service register: hostapd_installed - name: "{{ my_name }} - remove hostapd dnsmasq configuration" ansible.builtin.file: path: /etc/dnsmasq.d/retro/hostapd-dnsmasq.conf state: absent when: hostapd_installed.stat.exists is true - name: "{{ my_name }} - stop hostapd" ansible.builtin.service: name: hostapd-retronas.service state: stopped enabled: false force: true when: hostapd_installed.stat.exists is true - name: "{{ my_name }} - restart dnsmasq" ansible.builtin.service: name: dnsmasq-retro.service state: restarted enabled: true force: true # alt preset removed - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "network-presets-zoned" module_state: "absent" # this preset added - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "network-presets-standalone" module_state: "present" ================================================ FILE: ansible/install_network-presets-zoned.yml ================================================ --- # networkmanager - ansible.builtin.import_playbook: install_networkmanager.yml # firewalld - ansible.builtin.import_playbook: install_firewalld.yml - ansible.builtin.import_playbook: install_firewalld-zones.yml # dnsmasq # IMPORTED IN DNSMASQ-RETRO - ansible.builtin.import_playbook: install_dnsmasq.yml - ansible.builtin.import_playbook: install_dnsmasq-retro.yml # ntp - ansible.builtin.import_playbook: install_ntp.yml # dhcpcd - ansible.builtin.import_playbook: install_dhcpcd.yml - hosts: localhost gather_facts: false vars: my_name: "network-presets-zoned" my_file: "install_{{ my_name }}" templates: - { name: "dhcpcd.conf", dest: "/etc", mode: "0640", force: "yes" } connections: - { name: "ethernet", state: "absent" } # remove it first because modules are a pain some times - { name: "wifi-retronas", state: "absent" } - { name: "ethernet", ipv4addr: "{{ retronas_net_retro_ip }}/{{ retronas_net_retro_subnet }}", ipv4dns: "{{ retronas_net_retro_dns }}", ipv4method: "manual", ifname: "{{ retronas_net_retro_interface }}", type: "ethernet", ipv4never_default4: true } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "config connections" community.general.nmcli: type: "{{ item.type | default('ethernet') }}" conn_name: "{{ item.name }}" ip4: "{{ item.ipv4addr | default(omit) }}" gw4: "{{ item.ipv4gw | default(omit) }}" never_default4: "{{ item.ipv4never_default4 | default(omit) }}" dns4: "{{ item.ipv4dns | default(omit) }}" method4: "{{ item.ipv4method | default('manual') }}" ifname: "{{ item.ifname | default(omit) }}" route_metric4: "{{ item.metric | default(omit) }}" state: "{{ item.state| default('present') }}" autoconnect: true with_items: - '{{ connections }}' - name: "{{ my_name }} - check hostapd is installed" ansible.builtin.stat: path: /usr/lib/systemd/system/hostapd.service register: hostapd_installed - name: "{{ my_name }} - remove hostapd dnsmasq configuration" ansible.builtin.file: path: /etc/dnsmasq.d/retro/hostapd-dnsmasq.conf state: absent when: hostapd_installed.stat.exists is true - name: "{{ my_name }} - stop hostapd" ansible.builtin.service: name: hostapd-retronas.service state: stopped enabled: false force: true when: hostapd_installed.stat.exists is true - name: "{{ my_name }} - templates" ansible.builtin.template: src: "templates/{{ my_file }}/{{ item.name }}.j2" dest: "{{ item.dest }}/{{ item.name }}" owner: "{{ item.owner|default('root') }}" group: "{{ item.group|default('root') }}" mode: "{{ item.mode|default('0644') }}" force: "{{ item.force|default('yes') }}" with_items: "{{ templates }}" - name: "{{ my_name }} - restart dhcpcd" ansible.builtin.service: name: dhcpcd.service state: restarted enabled: true force: true - name: "{{ my_name }} - restart dnsmasq" ansible.builtin.service: name: dnsmasq-retro.service state: restarted enabled: true force: true - name: "{{ my_name }} - start firewalld" ansible.builtin.service: name: firewalld.service state: restarted enabled: true force: true # alt preset removed - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "network-presets-standalone" module_state: "absent" # this preset added - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "network-presets-zoned" module_state: "present" ================================================ FILE: ansible/install_networkmanager.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "network manager" my_file: "install_{{ my_name }}" my_services: "NetworkManager.service" collections: - { collection: community.general, creates: community/general/nmcli } tasks: - name: "{{ my_name }} - does nothing" debug: msg: "currently does nothing" ================================================ FILE: ansible/install_nfs.yml ================================================ --- - hosts: localhost gather_facts: false vars: module_name: "nfs" tasks: - ansible.builtin.import_role: name: retronas.role.nfs ================================================ FILE: ansible/install_nginx.yml ================================================ --- - hosts: localhost gather_facts: false vars: module_name: "nginx" roles: - retronas.role.sslcert - retronas.role.nginx - retronas.role.system-config ================================================ FILE: ansible/install_ntp.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "ntp" my_service: "openntpd" my_file: "install_ntp" module_name: "ntp" packages: - openntpd remove_packages: - ntp tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Load RetroNAS systems" ansible.builtin.include_vars: retronas_systems.yml - name: "{{ my_name }} - remove packages" ansible.builtin.package: name: "{{ remove_packages }}" state: absent - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - listen" ansible.builtin.lineinfile: path: "/etc/openntpd/ntpd.conf" search_string: "^listen on *$" insertafter: "^# Addresses to listen on (ntpd does not listen by default)$" line: "listen on *" notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "openntpd.service" state: restarted daemon_reload: true enabled: true ================================================ FILE: ansible/install_open-iscsi.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "open-iscsi" my_file: "install_{{ my_name }}" module_name: "open-iscsi" packages: - open-iscsi my_services: - open-iscsi templates: - { name: "iscsi-manager-target-login.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Enable startup services" ansible.builtin.service: name: ssh state: started enabled: true - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_openssh.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "OpenSSH" module_name: "openssh" packages: - openssh-client - openssh-server - openssh-sftp-server firewalld_rules: - { zone: retro, service: ssh } - { zone: modern, service: ssh } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest notify: "{{ my_name }} - Restart ssh" - name: "{{ my_name }} - Enable startup services" ansible.builtin.service: name: ssh state: started enabled: true - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart ssh" ansible.builtin.service: name: ssh state: restarted ================================================ FILE: ansible/install_pandoc.yml ================================================ --- - hosts: localhost gather_facts: false vars: - my_name: "pandoc" - my_file: "install_pandoc" - packages: - pandoc tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Install packages" package: name: "{{ packages }}" state: latest - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "pandoc" module_state: "present" ================================================ FILE: ansible/install_pfsshell.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "pfsshell" my_file: "install_pfsshell" module_name: "pfsshell" packages: - make - gcc - coreutils - meson - ninja-build - libfuse-dev tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - install script" ansible.builtin.template: src: "templates/{{ my_file }}/{{ my_file }}.sh.j2" dest: "{{ retronas_root }}/scripts/{{ my_file }}.sh" owner: root group: root mode: '0750' - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "/usr/local/bin/pfsfuse" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_pi1541.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "pi1541" my_file: "install_{{ my_name }}" module_name: "pi1541" paths: - { name: "{{ my_name }}", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "{{ my_name }}", dest: "/mnt" } templates: - { name: "{{ my_name }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_piscsi.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "piscsi" my_file: "install_piscsi" module_name: "piscsi" packages: - bridge-utils - build-essential - disktype - clang - genisoimage - git - libev-dev - libevdev2 - libgmock-dev - libpcap-dev - libpcap0.8-dev - libprotobuf-dev - libspdlog-dev - man2html - nginx-light - protobuf-compiler - python3 - python3-dev - python3-pip - python3-setuptools - python3-venv - python3-wheel - unar - unzip - ca-certificates - dosfstools - kpartx - unzip - unar - gettext - rsyslog paths: - { name: "{{ my_name }}", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: '{{ retronas_group }}' } - { name: "src", dest: "{{ retronas_root }}", owner: "{{ retronas_user }}", group: '{{ retronas_group }}' } - { name: "{{ my_name }}", src: "{{ retronas_path }}/{{ my_name }}", dest: "/home/{{ retronas_user }}", state: "link" } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} - { name: "{{ my_file }}_standard.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} - { name: "{{ my_name }}_retronas_patch.diff", dest: "{{ retronas_root }}/src"} - { name: "{{ my_name }}.service", dest: "/etc/systemd/system"} systemd_units: - { name: "rsyslog", type: 'service', state: "restarted", enabled: "yes", restart: "yes", instance: "no" } - { name: "piscsi", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } tasks: - name: "{{ my_name }} - Load RetroNAS config" include_vars: retronas_vars.yml # libpcap can conflict with libpcap from backport (tcpdump etc) - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/install_{{ my_name }}.sh" creates: "{{ retronas_root }}/bin/{{ my_name }}/{{ my_name }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - password file" ansible.builtin.copy: dest: /etc/{{ my_name }}_passwd content: retronas mode: 0600 owner: root group: root - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" when: - item.instance == 'no' notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: restarted daemon_reload: true with_items: "{{ systemd_units }}" when: - item.restart == 'yes' - item.instance == 'no' ================================================ FILE: ansible/install_proftpd.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "ProFTPd" my_file: "install_proftpd" module_name: "proftpd" packages: - avahi-daemon - proftpd-core templates: - { name: "retronas.conf", dest: "/etc/proftpd/conf.d" } - { name: "ftp.service", dest: "/etc/avahi/services" } firewalld_rules: - { name: ftp, zone: retro } - { name: ftp, zone: modern } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - remove mod_unique_id.c" ansible.builtin.ini_file: path: /etc/proftpd/modules.conf section: null option: "LoadModule mod_unique_id.c" state: absent notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: proftpd state: started enabled: true - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted with_items: - avahi-daemon - proftpd ================================================ FILE: ansible/install_ps2_openps2loader.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "PS2 OpenPS2Loader" my_file: "install_ps2_openps2loader" my_dir: "{{ retronas_path }}/ps2/OpenPS2Loader" module_name: "ps2_openps2loader" paths: - { name: "APPS", dest: "{{ my_dir }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "ART", dest: "{{ my_dir }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "CFG", dest: "{{ my_dir }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "CHT", dest: "{{ my_dir }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "LNG", dest: "{{ my_dir }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "THM", dest: "{{ my_dir }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "VMC", dest: "{{ my_dir }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "retronas_ps2.conf", dest: "/etc/samba" } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.paths - name: "{{ my_name }} - check old pops dir" ansible.builtin.stat: path: "{{ my_dir }}/POPS" register: old_pops - debug: msg: "{{ old_pops }}" - name: "{{ my_name }} - rename old pops dir" ansible.builtin.shell: cmd: "mv {{ my_dir }}/POPS {{ my_dir }}/POPS-OLD" when: old_pops.stat.exists is true - name: "{{ my_name }} - build symlinks" ansible.builtin.file: src: "../../roms/{{ item.src }}" dest: "{{ my_dir }}/{{ item.ops2l }}" state: link loop: "{{ system_map }}" when: - item.ops2l | length > 0 - name: "{{ my_name }} - configure includes file" ansible.builtin.ini_file: path: /etc/samba/smb.conf section: ps2 option: "include" value: "/etc/samba/retronas_ps2.conf" - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.system-config - ansible.builtin.import_role: name: retronas.role.samba ================================================ FILE: ansible/install_ps2_udpbd.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "ps2_udpbd" my_file: "install_ps2_udpbd" module_name: "ps2_udpbd" append_user_group: "disk" systemd_units: - { name: "ps2_udpbd", type: 'service', state: "stopped", enabled: "no", restart: "no", instance: "no" } packages: - make - gcc - g++ - git - build-essential paths: - { name: "{{ my_name }}", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "udpbd_manager.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}.service", dest: "/etc/systemd/system" } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root}} /bin/ps2_udpbd" - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" when: - item.instance == 'no' notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.update-user - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: restarted daemon_reload: true with_items: "{{ systemd_units }}" when: - item.restart == 'yes' - item.instance == 'no' ================================================ FILE: ansible/install_ps3netsrv.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "ps3netsrv" my_file: "install_ps3netsrv" module_name: "ps3netsrv" system_key: "ps3netsrv" systemd_units: - { name: "ps3netsrv", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } - { name: "ps3netsrv-perms", type: 'service', state: "started", enabled: "no", restart: "yes", instance: "no" } - { name: "ps3netsrv-perms", type: 'timer', state: "started", enabled: "yes", restart: "yes", instance: "no" } packages: - make - automake - autoconf - gcc - g++ - meson - ninja-build - curl - wget - build-essential - unzip - libmbedtls-dev - coreutils - jq packages_debian: debian10: - libmbedtls12 debian11: - libmbedtls12 debian12: - libmbedtls14 debian13: - libmbedtls21 packages_ubuntu: - libmbedtls14 templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "ps3netsrv.service", dest: "/usr/lib/systemd/system" } - { name: "ps3netsrv-perms.service", dest: "/usr/lib/systemd/system" } - { name: "ps3netsrv-perms.timer", dest: "/usr/lib/systemd/system" } firewalld_rules: - { zones: retro, service: ps3netsrv } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - Install build tools (debian)" ansible.builtin.package: name: "{{ packages_debian['debian' + ansible_distribution_major_version] }}" state: latest when: ansible_distribution == 'Debian' - name: "{{ my_name }} - Install build tools (ubuntu)" ansible.builtin.package: name: "{{ packages_ubuntu }}" state: latest when: ansible_distribution == 'Ubuntu' - name: "{{ my_name }} - build top level" ansible.builtin.file: path: "{{ retronas_path }}/ps3/ps3netsrv" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory mode: "0775" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - build layout" ansible.builtin.file: src: "../../roms/{{ item.src }}" dest: "{{ retronas_path }}/ps3/ps3netsrv/{{ item.ps3netsrv }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: link loop: "{{ system_map }}" when: - item.ps3netsrv | length > 0 - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root}}/bin/ps3netsrv" - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" when: - item.instance == 'no' notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: restarted daemon_reload: true with_items: "{{ systemd_units }}" when: - item.restart == 'yes' - item.instance == 'no' - name: "{{ my_name }} - Restart instances" ansible.builtin.service: name: "{{ item.1.name }}{{ item.0.dest }}.{{ item.1.type }}" state: restarted daemon_reload: true with_items: - "{{ system_map }}" - "{{ systemd_units }}" when: - item.1.restart == 'yes' - item.1.instance == 'yes' ================================================ FILE: ansible/install_pygopherd.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "pygopherd" my_file: "install_pygopherd" module_name: "pygopherd" packages: - python3 templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}.conf", dest: "{{ retronas_root }}/etc" } - { name: "{{ my_name }}.service", dest: "/usr/lib/systemd/system" } firewalld_ports: - { port: 70, protocol: tcp } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "opt/pygopherd/bin/pygopherd" notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted daemon_reload: true with_items: - "{{ my_name }}" ================================================ FILE: ansible/install_rclone.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "rclone" my_file: "install_rclone" module_name: "rclone" packages: - rclone templates: - { name: "{{ my_name }}-webui.service", dest: "/etc/systemd/system", mode: "0644" } services: - "{{ my_name }}-webui.service" firewalld_ports: - { port: 5572, protocol: tcp, zone: retro } - { port: 5572, protocol: tcp, zone: modern } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.htpasswd notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" enabled: true state: restarted daemon_reload: true loop: "{{ services }}" ================================================ FILE: ansible/install_recalbox_cifs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "Recalbox CIFS" my_file: "install_recalbox_cifs" module_name: "recalbox_cifs" system_key: "recalbox" top_level_paths: - { name: "ROMS", enabled: yes, generic: "roms", systems: yes } - { name: "SAVES", enabled: yes, generic: "saves", systems: yes } - { name: "BIOS", enabled: yes, generic: "bios", systems: yes } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_redumper.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "redumper" my_file: "install_{{ my_name }}" module_name: "redumper" packages: - unzip - jq templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root}}/bin/ps3netsrv" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_retroaimserver.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "retroaimserver" my_file: "install_retroaimserver" my_dir: "/opt/retro-aim-server" module_name: "retroaimserver" systemd_units: - { name: "retro-aim-server", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } packages: - curl templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "retro-aim-server.service", dest: "/etc/systemd/system/" } firewalld_rules: - { zones: retro, service: retroaimserver } settings_env: - { regex: "^export OSCAR_HOST=.*", line: "export OSCAR_HOST={{ retronas_net_retro_ip }}" } - { regex: "^export DISABLE_AUTH=true", line: "export DISABLE_AUTH=false" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ my_dir }}/retro_aim_server" - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - configure defaults" ansible.builtin.lineinfile: path: "{{ my_dir }}/settings.env" regexp: "{{ item.regex }}" line: "{{ item.line }}" with_items: "{{ settings_env }}" # # FIREWALL # - name: "{{ my_name }} - checking firewall rule" ansible.builtin.stat: path: /etc/firewalld/services register: firewalld_services - name: "{{ my_name }} - Generate firewall service" ansible.builtin.template: src: "templates/{{ my_file }}/retroaimserver.xml.j2" dest: "/etc/firewalld/services/retroaimserver.xml" owner: root group: root mode: 0644 when: firewalld_services.stat.exists - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: restarted daemon_reload: true with_items: "{{ systemd_units }}" ================================================ FILE: ansible/install_retroarch_cifs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "RetroArch Based Systems CIFS" my_file: "install_retroarch_cifs" module_name: "retroarch_cifs" system_key: "retroarch" tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_retrodeck_cifs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "retrodeck CIFS" my_file: "install_retrodeck_cifs" module_name: "retrodeck_cifs" system_key: "retrodeck" top_level_paths: - { name: "roms", enabled: yes, generic: "roms", systems: yes } # - { name: "saves", enabled: yes, generic: "saves", systems: yes } - { name: "bios", enabled: yes, generic: "bios", systems: yes } internal_symlinks: - { src: 'commodore/amiga', dest: 'ags' } - { src: 'commodore/amiga', dest: 'amiga600' } - { src: 'capcom/cps1', dest: 'cps' } - { src: 'mame/mame', dest: 'mame-advmame' } - { src: 'nec/pcenginecd', dest: 'tg-cd' } - { src: 'sega/megacd', dest: 'segacd' } - { src: 'sega/megacd', dest: 'megacdjp' } - { src: 'sega/megadrive', dest: 'genesis' } - { src: 'sega/megadrive', dest: 'megadrivejp' } - { src: 'snk/neogeocd', dest: 'neogeocdjp' } - { src: 'sega/saturn', dest: 'saturnjp' } - { src: 'sega/32x', dest: 'sega32xjp' } - { src: 'sega/32x', dest: 'sega32xna' } - { src: 'nintendo/superfamicom', dest: 'sneshd' } - { src: 'nintendo/superfamicom', dest: 'snesna' } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_romdir.yml ================================================ --- - hosts: localhost gather_facts: false vars: module_name: "romdir" tasks: - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_romimport.yml ================================================ --- - hosts: localhost vars: my_name: "ROM Import" my_file: "install_romimport" module_name: "romimport" packages: - python3 - git paths: - { name: "romimport", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "romimport.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Load RetroNAS Systems" ansible.builtin.include_vars: retronas_systems.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "git clone https://github.com/frederic-mahe/Hardware-Target-Game-Database.git" args: chdir: "{{ retronas_root}}/bin" creates: "{{ retronas_root}}/bin/Hardware-Target-Game-Database" - name: "{{ my_name }} - set SMBD permissions" ansible.builtin.shell: "chown -R {{ retronas_user}}:{{ retronas_user }} Hardware-Target-Game-Database" args: chdir: "{{ retronas_root}}/bin" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_romm_cifs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "RomM CIFS" my_file: "install_romm_cifs" module_name: "romm_cifs" system_key: "romm" script_url: 'https://raw.githubusercontent.com/minorOffense/romdirflattener/refs/heads/main/flatten-romdir.sh' script_dest: "{{ retronas_root }}/bin/flatten-romdir.sh" fattenerscript: "retronas-romm-dirs" top_level_paths: - { name: "roms", enabled: yes, generic: "roms", systems: yes } templates: - { name: "retronas-romm-dirs.service", dest: "/etc/systemd/system" } - { name: "retronas-romm-dirs.timer", dest: "/etc/systemd/system" } - { name: "retronas-romm-dirs.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } systemd_units: - { name: "retronas-romm-dirs", type: 'service', state: "stopped", enabled: "no", restart: "no", instance: "no" } - { name: "retronas-romm-dirs", type: 'timer', state: "started", enabled: "yes", restart: "no", instance: "no" } # needs review or be handled in the flatten script #internal_symlinks: # - { src: 'sega/advancedpicobeena', dest: 'beena' } # - { src: 'panasonic/3do', dest: 'panasonic-m2' } # - { src: 'apple/pippin', dest: 'pippin' } # - { src: 'interton/vc4000', dest: 'vc-4000' } # - { src: 'tandy/vis', dest: 'vis' } # - { src: 'tapwave/zodiac', dest: 'zod' } # # 'amiga-cd', # ?? tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - get update script" ansible.builtin.shell: curl -kLso "{{ script_dest }}" {{ script_url }} - name: "{{ my_name }} - make script executable" file: path: "{{ script_dest }}" mode: '0755' - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.samba.system vars: nolink: true writable: "no" - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - create startup service(s) instance" ansible.builtin.template: src: templates/{{ my_file }}/{{ item.name }}.{{ item.type }}.j2 dest: /etc/systemd/system/{{ item.name }}.{{ item.type }} owner: root group: root mode: 0644 with_items: "{{ systemd_units }}" notify: "{{ my_name }} daemon-reload" - name: "Import system-config role" ansible.builtin.import_role: name: retronas.role.system-config - name: Run flatten-romdir.sh for each src/dest (no top_level) ansible.builtin.shell: "{{ retronas_root }}/bin/flatten-romdir.sh {{ retronas_path }}/roms/{{ item.src }} {{ retronas_path }}/{{ system_key }}/roms/{{ item[system_key] }}" become: true loop: "{{ system_map }}" when: top_level_paths is defined and item[system_key] is defined and item[system_key] | length > 0 - name: patch up perms ansible.builtin.shell: "chown -R {{ retronas_user }}:{{ retronas_group }} {{ retronas_path }}/{{ system_key }}" become: true handlers: - name: "{{ my_name }} daemon-reload" ansible.builtin.systemd: daemon_reload: true ================================================ FILE: ansible/install_sabretools.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "SabreTools" my_file: "install_sabretools" module_name: "sabretools" packages: - git - coreutils - unzip my_arch: "x86_64" templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Run installer" ansible.builtin.shell: cmd: "./{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ retronas_root }}/scripts" executable: /bin/bash - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_samba.yml ================================================ --- - hosts: localhost gather_facts: false roles: - retronas.role.samba vars: module_name: "samba" tasks: - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_seaweedfs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "seaweedfs" my_file: "install_{{ my_name }}" module_name: "seaweedfs" systemd_units: - { name: "{{ my_name }}-retronas", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } packages: - pwgen firewalld_rules: - { zones: retro, service: "{{ my_name }}" } - { zones: modern, service: "{{ my_name }}" } templates: - { name: "{{ my_name }}-retronas.service", dest: "/etc/systemd/system" } - { name: "install_{{ my_name }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "seaweedfs-credentials.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "weed-retronas-s3.json", dest: "{{ retronas_root }}/bin", mode: "0640", force: no } paths: - { name: "s3", dest: "{{ retronas_path }}", state: "directory", mode: "0755"} tasks: - ansible.builtin.import_role: name: retronas.role.package.latest - name: "generate access key" shell: cmd: pwgen -s 32 1 no_log: true register: retronas_s3_access_key - name: "generate secret key" shell: cmd: pwgen -s 64 1 no_log: true register: retronas_s3_secret_key - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - Install release" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root}}/bin/weed" - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" notify: "{{ my_name }} - Restart service" # # FIREWALL # - name: "{{ my_name }} - checking firewall rule" ansible.builtin.stat: path: /etc/firewalld/services register: firewalld_services - name: "{{ my_name }} - templates" ansible.builtin.template: src: "templates/{{ my_file }}/{{ my_name }}.xml.j2" dest: /etc/firewalld/services/{{ my_name }}.xml owner: root group: root mode: 0644 force: true when: firewalld_services.stat.exists - ansible.builtin.shell: cmd: 'sleep 10' - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: restarted daemon_reload: true with_items: "{{ systemd_units }}" ================================================ FILE: ansible/install_sit.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "sit" my_file: "install_sit" module_name: "sit" packages: - make - gcc - git - coreutils templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "/usr/local/bin/sit" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_smbmounter.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "smbmounter" my_file: "install_{{ my_name }}" module_name: "smbmounter" system_key: "smbmounter" templates: - { name: "retronas_{{ my_name }}.conf", dest: "/etc/samba" } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.extradirs - ansible.builtin.import_role: name: retronas.role.samba - name: "{{ my_name }} - link romdir" ansible.builtin.file: src: "{{ retronas_path }}/roms/commodore/amiga" dest: "{{ retronas_path }}/amiga" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: link mode: "0775" - name: "{{ my_name }} - configure includes file" ansible.builtin.ini_file: path: /etc/samba/smb.conf section: "amiga" option: "include" value: "/etc/samba/retronas_smbmounter.conf" notify: "restart samba" - ansible.builtin.import_role: name: retronas.role.templates notify: "restart samba" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_sslcert.yml ================================================ --- - hosts: localhost gather_facts: false roles: - retronas.role.sslcert vars: module_name: "sslcert" tasks: - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_syncthing.yml ================================================ --- - hosts: localhost vars: my_name: "Syncthing" my_file: "install_syncthing" module_name: "syncthing" packages: - syncthing firewalld_rules: - { zone: modern, service: syncthing } - { zone: modern, service: syncthing-gui } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Package signing key" ansible.builtin.get_url: url: https://syncthing.net/release-key.gpg dest: /etc/apt/trusted.gpg.d/syncthing-archive-keyring.gpg owner: root group: root mode: "0644" - name: "{{ my_name }} - Configure APT repo" ansible.builtin.apt_repository: repo: deb https://apt.syncthing.net/ syncthing stable state: present filename: syncthing update_cache: true - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - Web config http://{{ ansible_default_ipv4.address }}:8384" ansible.builtin.ini_file: path: /usr/lib/systemd/system/syncthing@.service section: Service option: ExecStart value: "/usr/bin/syncthing serve --no-browser --no-restart --logflags=0 --gui-address=0.0.0.0:8384" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item }}" state: started enabled: true daemon_reload: true with_items: - syncthing@{{ retronas_user }} - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted daemon_reload: true with_items: - syncthing@{{ retronas_user }} ================================================ FILE: ansible/install_tcpser.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "tcpser" my_file: "install_tcpser" module_name: "tcpser" append_user_group: "dialout" packages: - make - gcc - coreutils - git paths: - { name: "{{ my_name }}", dest: "{{ retronas_root }}/etc" } templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "tcpser@.service", dest: "/usr/lib/systemd/system" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.update-user - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "{{ retronas_root }}/bin/tcpser" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_telnet.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "Telnet" my_file: "install_telnet" module_name: "telnet" templates: - { name: "telnet", dest: "/etc/xinetd.d", force: false } firewalld_rules: - { zone: "retro", service: "telnet" } packages: - telnet - telnetd - xinetd tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - Enable startup services" ansible.builtin.service: name: xinetd state: started enabled: true - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart services" ansible.builtin.service: name: xinetd state: restarted ================================================ FILE: ansible/install_tftpd-hpa.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "tftpd-hpa" my_file: "install_tftpd-hpa" module_name: "tftpd-hpa" firewalld_rules: - { zone: "retro", service: "tftp" } packages: tftpd-hpa templates: - { name: "tftpd-hpa", dest: "/etc/default" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: tftpd-hpa state: started enabled: true - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: tftpd-hpa state: restarted ================================================ FILE: ansible/install_tnfs.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "TNFS Atari 8-bit and ZX Spectrum" my_file: "install_tnfs" module_name: "tnfs" packages: - build-essential templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "tnfsd.service", dest: "/usr/lib/systemd/system" } firewalld_ports: - { zone: "retro", port: 16384, protocol: tcp } - { zone: "retro", port: 16384, protocol: udp } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" # args: # creates: "{{ retronas_root}}/bin/tnfs" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - enable startup service" ansible.builtin.service: name: "{{ item }}" state: started enabled: true daemon_reload: true with_items: - tnfsd - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted daemon_reload: true with_items: - tnfsd ================================================ FILE: ansible/install_troubleshooting.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "troubleshooting" my_file: "install_troubleshooting" module_name: "troubleshooting" packages: - ioping - iotop - iperf3 - tcpdump - iftop - traceroute - ethtool - socat - nmap - bind9-dnsutils - mtr - strace - curl - smartmontools - htop tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_ucon64.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "ucon64" my_file: "install_ucon64" module_name: "ucon64" packages: - make - gcc - coreutils templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - build source" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_file }}.sh" creates: "/usr/local/bin/ucon64" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_waybackproxy.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "waybackproxy" my_file: "install_{{ my_name }}" my_dir: "/opt/{{ my_name }}" module_name: "waybackproxy" systemd_units: - { name: "{{ my_name }}", type: 'service', state: "started", enabled: "no", restart: "yes", instance: "no" } templates: - { name: "config.json", dest: "{{ my_dir }}" } - { name: "{{ my_name }}.service", dest: "/etc/systemd/system" } - { name: "install_waybackproxy.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } packages: - git paths: - { name: "{{ my_name }}", dest: "/opt", state: "directory", mode: "0755" } firewalld_ports: - { zone: "retro", port: 8888, protocol: tcp } tasks: - name: "{{ my_name }} - Load RetroNAS config" include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - Install" shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "/opt/{{ my_name }}/{{ my_name }}.py" - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" service: name: "{{ my_name }}.service" state: restarted daemon_reload: true ================================================ FILE: ansible/install_webone.yml ================================================ --- - hosts: localhost gather_facts: true vars: my_name: "WebOne proxy" my_file: "install_webone" module_name: "webone" packages: - git - ffmpeg - coreutils packages_debian: debian12: - imagemagick-6.q16 - imagemagick-6-common debian13: - imagemagick-7.q16 - imagemagick-7-common templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "webone.service", dest: "/usr/lib/systemd/system" } firewalld_ports: - { zone: "retro", port: 8080, protocol: tcp } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.package.latest vars: packages: "{{ packages_debian['debian' + ansible_distribution_major_version ] }}" when: ansible_distribution == 'Debian' notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.dotnetcore8 - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - Run installer" ansible.builtin.shell: cmd: "./{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ retronas_root }}/scripts" executable: /bin/bash creates: "{{ retronas_root }}/bin/webone/webone" notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: webone state: restarted daemon_reload: true ================================================ FILE: ansible/install_wrp.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "wrp" my_file: "install_{{ my_name }}" module_name: "wrp" packages: - chromium google_chrome: /usr/bin/google-chrome chromium: /usr/bin/chromium templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "{{ my_name }}.service", dest: "/usr/lib/systemd/system" } firewalld_ports: - { zone: "retro", port: 8080, protocol: tcp } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - check architecture" ansible.builtin.shell: cmd: dpkg --print-architecture | head -n1 register: architecture - name: "{{ my_name }} - check google-chrome" ansible.builtin.stat: path: "{{ google_chrome }}" register: google_chrome_check - ansible.builtin.import_role: name: retronas.role.package.latest when: google_chrome_check.stat.exists is false - name: "{{ my_name }} - fake google-chrome" ansible.builtin.file: src: "{{ chromium }}" dest: "{{ google_chrome }}" state: link when: google_chrome_check.stat.exists is false - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Run installer" ansible.builtin.shell: cmd: "./{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ retronas_root }}/scripts" executable: /bin/bash - name: "{{ my_name }} - enable startup service" ansible.builtin.service: name: "{{ my_name }}" state: started enabled: true daemon_reload: true - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ my_name }}" state: restarted daemon_reload: true ================================================ FILE: ansible/install_xbox.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "xbox" my_file: "install_xbox" module_name: "xbox" system_key: "xbox" paths: - { name: "xbox", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "retronas_xbox.conf", dest: "/etc/samba/" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - symlinks" ansible.builtin.file: src: "{{ item.src }}" dest: "{{ retronas_path }}/xbox/{{ item.dest }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: link with_items: - { src: "../roms/microsoft/xbox/games", dest: "games" } - { src: "../roms/microsoft/xbox/iso", dest: "iso" } - name: "{{ my_name }} - configure includes file" ansible.builtin.ini_file: path: /etc/samba/smb.conf section: xbox option: "include" value: "/etc/samba/retronas_xbox.conf" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_xbox360.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "XBox360" my_file: "install_xbox360" module_name: "xbox360" system_key: "xbox360" paths: - { name: "xbox360", dest: "{{ retronas_path }}" } templates: - { name: "retronas_xbox360.conf", dest: "/etc/samba" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.samba - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - symlinks" ansible.builtin.file: src: "{{ item.src }}" dest: "{{ retronas_path }}/xbox360/{{ item.dest }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: link with_items: - { src: "../roms/microsoft/xbox360/games", dest: "games" } - name: "{{ my_name }} - configure includes file" ansible.builtin.ini_file: path: /etc/samba/smb.conf section: xbox360 option: "include" value: "/etc/samba/retronas_xbox360.conf" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_xbox360_netiso.yml ================================================ --- - hosts: localhost gather_facts: false vars: my_name: "XBox360 NetISO" my_file: "install_xbox360_netiso" module_name: "xbox360_netiso" system_key: "xbox360" packages: - unzip - curl - jq paths: - { name: "xbox360", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "install_xbox360_netiso.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "xbox360_netiso.service", dest: "/etc/systemd/system" } - { name: "dummy.iso", dest: "{{ retronas_path }}/{{ system_key }}" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.romdir - ansible.builtin.import_role: name: retronas.role.paths - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - symlinks" ansible.builtin.file: src: "{{ item.src }}" dest: "{{ retronas_path }}/xbox360/{{ item.dest }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: link with_items: - { src: "../roms/microsoft/xbox360/games", dest: "games" } - name: "{{ my_name }} - Install from git repo" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "xbox360_netiso.service" state: restarted enabled: true daemon_reload: true ================================================ FILE: ansible/install_xboxmanager.yml ================================================ --- # Dependencies - ansible.builtin.import_playbook: install_extract-xiso.yml - hosts: localhost gather_facts: true roles: - retronas.role.cockpit - retronas.role.filesystems - retronas.role.curlftpfs vars: my_name: "xboxmanager" my_file: "install_xboxmanager" my_path: "/opt" module_name: "xboxmanager" paths: - { name: "device-mounts", dest: "{{ retronas_path }}", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } - { name: "xbox", dest: "{{ retronas_path }}/device-mounts", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } templates: - { name: "xboxmanager.cfg", dest: "/opt/xboxmanager", owner: "{{ retronas_user }}", group: "{{ retronas_group }}" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - clone repo" ansible.builtin.git: repo: 'https://github.com/sairuk/cockpit-xboxmanager.git' dest: "{{ my_path }}/xboxmanager" clone: true update: true version: "main" - ansible.builtin.import_role: name: retronas.role.paths - name: "{{ my_name }} - run installer" ansible.builtin.command: cmd: "{{ my_path }}/xboxmanager/xboxmanager-install.sh" - ansible.builtin.import_role: name: retronas.role.templates - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_xlink-kai.yml ================================================ --- - hosts: localhost gather_facts: false become: true # https://dist.teamxlink.co.uk/ vars: my_name: "xlink-kai" my_file: "install_xlink-kai" my_keyrings: "/etc/apt/keyrings" my_key: "{{ my_keyrings }}/teamxlink.gpg" my_repo: "https://dist.teamxlink.co.uk/linux/debian" module_name: "xlink-kai" prerequisite_packages: - ca-certificates - gnupg - curl packages: - xlinkkai templates: - { name: "{{ my_name }}.service", dest: "/etc/systemd/system" } firewalld_ports: - { zone: "modern", port: 30000, protocol: udp } - { zone: "retro", port: 34522, protocol: tcp } - { zone: "modern", port: 34522, protocol: tcp } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - clean up old key" ansible.builtin.shell: "rm -f /usr/share/keyrings/teamxlink.asc" - name: "{{ my_name }} - Install prerequisite packages" ansible.builtin.package: name: "{{ prerequisite_packages }}" update_cache: true - name: "{{ my_name }} - Create key dir" ansible.builtin.file: path: "{{ my_keyrings }}" mode: 0755 owner: root group: root state: directory - name: "{{ my_name }} - Add teamxlink key" ansible.builtin.shell: cmd: "curl -fsSL {{ my_repo }}/gpg | gpg --dearmor -o {{ my_key }}" creates: "{{ my_key }}" - name: "{{ my_name }} - Fix perms on file" ansible.builtin.file: path: "{{ my_key }}" mode: 0755 owner: root group: root - name: "{{ my_name }} - Add teamxlink repository" ansible.builtin.copy: dest: "/etc/apt/sources.list.d/teamxlink.list" content: | deb [signed-by={{ my_key }}] {{ my_repo }}/static/deb/release/ / - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - check for arm build" ansible.builtin.stat: path: "/usr/bin/kaiengine_arm" register: arm_build - name: "{{ my_name }} - link arm build" ansible.builtin.file: src: "/usr/bin/kaiengine_arm" dest: "/usr/bin/kaiengine" state: link when: arm_build.stat.exists is true - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service(s)" - name: "{{ my_name }} - fix config perms for {{ retronas_user }}" ansible.builtin.file: path: "/etc/kaiengine.conf" owner: "{{ retronas_user }}" group: "{{ retronas_user }}" mode: '0640' notify: "{{ my_name }} - Restart service(s)" - ansible.builtin.import_role: name: retronas.role.firewalld.port - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service(s)" ansible.builtin.service: name: "{{ my_name }}.service" state: started enabled: true daemon_reload: true ================================================ FILE: ansible/install_ytree.yml ================================================ --- - hosts: localhost gather_facts: no vars: my_name: "ytree" my_file: "install_{{ my_name }}" module_name: "ytree" packages: - build-essential - libreadline-dev - gcc templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Load RetroNAS systems" ansible.builtin.include_vars: retronas_systems.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" - ansible.builtin.import_role: name: retronas.role.system-config ================================================ FILE: ansible/install_zterm.yml ================================================ --- - hosts: localhost vars: my_name: "zterm" my_file: "install_{{ my_name }}" module_name: "zterm" append_user_group: dialout systemd_units: - { name: "zterm", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } packages: - make - cmake - git - build-essential - lrzsz templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755" } - { name: "zterm.service", dest: "/usr/lib/systemd/system" } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.update-user - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "{{ retronas_root}} /opt/zterm/zterm" - name: "{{ my_name }} - enable service(s)" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" daemon_reload: true with_items: "{{ systemd_units }}" when: - item.instance == 'no' notify: "{{ my_name }} - Restart service" - ansible.builtin.import_role: name: retronas.role.system-config handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item.name }}.{{ item.type }}" state: restarted daemon_reload: true with_items: "{{ systemd_units }}" when: - item.restart == 'yes' - item.instance == 'no' - name: "{{ my_name }} - Restart instances" ansible.builtin.service: name: "{{ item.1.name }}{{ item.0.dest }}.{{ item.1.type }}" state: restarted daemon_reload: true with_items: - "{{ system_map }}" - "{{ systemd_units }}" when: - item.1.restart == 'yes' - item.1.instance == 'yes' ================================================ FILE: ansible/migrate_mister_cifs_issue21.yml ================================================ --- ### migration playbook for issue #21 # this issue is old and the fix is slow so users who haven't updated in a while # will have to run this manually with # # ansible-playbook migrate_mister_cifs_issue21.yml # # Dependencies - ansible.builtin.import_playbook: install_samba.yml - ansible.builtin.import_playbook: install_romdir.yml - ansible.builtin.import_playbook: install_extradirs.yml - hosts: localhost vars: - my_name: "MiSTer CIFS" - my_file: "install_mister_cifs" - top_level_paths: - { name: "games", enabled: yes, generic: "roms", systems: yes } - { name: "saves", enabled: yes, generic: "saves", systems: yes } - { name: "savestates", enabled: yes, generic: "savestates", systems: yes } - { name: "BIOS", enabled: yes, generic: "bios", systems: yes } - { name: "wallpapers", enabled: yes, generic: "wallpapers", systems: no } tasks: - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - build top level" ansible.builtin.file: path: "{{ retronas_path }}/mister" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory mode: "0775" notify: "{{ my_name }} - Restart service" - name: "get facts for path" ansible.builtin.stat: path: "{{ retronas_path }}/mister/{{ item.mister }}" with_items: - "{{ system_map }}" register: mister_stat - name: "{{ my_name }} - removing old symlink layout see issue #21" ansible.builtin.file: path: "{{ retronas_path }}/mister/{{ item.item.mister }}" state: absent with_items: - "{{ mister_stat.results }}" when: item.stat.islnk is defined and item.stat.islnk == True notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - build top level share paths" ansible.builtin.file: path: "{{ retronas_path }}/mister/{{ item.name }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory mode: "0775" with_items: "{{ top_level_paths }}" when: - item.enabled is true notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - build systems directory layout" ansible.builtin.file: src: "../../{{ item.1.generic|lower }}/{{ item.0.src }}" dest: "{{ retronas_path }}/mister/{{ item.1.name }}/{{ item.0.mister }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: link with_nested: - "{{ system_map }}" - "{{ top_level_paths }}" when: - item.1.enabled is true - item.0.mister | length > 0 - item.1.systems is true notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - configure includes file" ansible.builtin.ini_file: path: /etc/samba/smb.conf section: mister option: "include" value: "/etc/samba/retronas_mister.conf" notify: "{{ my_name }} - Restart service" - name: "{{ my_name }} - configure retro shares" ansible.builtin.template: src: "templates/{{ my_file }}/retronas_mister.conf.j2" dest: /etc/samba/retronas_mister.conf owner: root group: root mode: '0644' notify: "{{ my_name }} - Restart service" handlers: - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted with_items: - smbd - nmbd - ansible.builtin.import_playbook: retronas_system_config.yml vars: module_name: "mister_cifs" module_state: "present" ================================================ FILE: ansible/retronas_create_dirs.yml ================================================ --- - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - stat our path" ansible.builtin.stat: path: "{{ retronas_path }}" register: rn_path - name: "{{ my_name }} - create our base" ansible.builtin.shell: cmd: "mkdir -p {{ rn_path}}" changed_when: false when: rn_path is defined and rn_path.stat.exists is false - name: "{{ my_name }} - perms" ansible.builtin.shell: cmd: "chown -R {{ retronas_user }}:{{ retronas_group }} {{ rn_path }}" changed_when: false when: rn_path is defined and rn_path.stat.exists is false - name: "{{ my_name }} - stat top level paths" ansible.builtin.stat: path: "{{ retronas_path }}/{{ item }}" loop: [ "roms", "bios", "saves", "savestates" ] register: tl_paths - name: "{{ my_name }} - create our missing paths" ansible.builtin.file: path: "{{ retronas_path }}/{{ item.item }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory mode: '0755' loop: "{{ tl_paths.results }}" when: tl_paths is defined and item.stat.exists is false - name: "{{ my_name }} - build layout list (set fact)" ansible.builtin.set_fact: path_list: "{{ path_list|default([]) + [ retronas_path + '/' + item.1.name + '/' + item.0.src if item.1.systems is true else '' ] }}" no_log: true loop: "{{ system_map|product(top_level_paths)|list }}" when: item.1.enabled is true - name: "{{ my_name }} - build layout" ansible.builtin.shell: cmd: mkdir -p {{ path_list|flatten|join(' ') }} become: true become_user: "{{ retronas_user }}" when: path_list is defined changed_when: False - name: "{{ my_name }} - build systems directory layout (set fact)" ansible.builtin.set_fact: link_list: "{{ link_list|default([]) + [ 'ln -sfT ' + retronas_path + '/' + item.1.name|lower + '/' + item.0.src + ' ' + retronas_path + '/' + item.1.name + '/' + item.0.dest + ';' ] }}" loop: "{{ system_links|product(top_level_paths)|list }}" when: - item.1.enabled is true - item.1.systems is true - name: "{{ my_name }} - build systems directory layout (link list)" ansible.builtin.shell: cmd: "{{ link_list|join('') }}" when: link_list is defined changed_when: false - name: "{{ my_name }} - add top level directory info" ansible.builtin.copy: dest: "{{ item.stat.path }}/dir.txt" content: | this folder structure is the responsiblity of the user to populate owner: "{{ retronas_user }}" group: "{{ retronas_group }}" mode: "0644" loop: "{{ tl_paths.results }}" when: tl_paths is defined and item.stat.exists is true ================================================ FILE: ansible/retronas_dependencies.yml ================================================ --- - hosts: localhost become: yes vars: my_name: "RetroNAS dependencies" my_file: "retronas_dependencies" packages: - jq - sudo - git - dialog directories: - bin - etc - scripts - log - cache tasks: - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - configure program directories" ansible.builtin.file: path: "{{ retronas_root }}/{{ item }}" owner: root group: root mode: 0755 state: directory with_items: "{{ directories }}" - name: "{{ my_name }} - configure top level share directory" ansible.builtin.file: path: "{{ retronas_path }}" owner: "{{ retronas_user }}" group: "{{ retronas_user }}" mode: 0775 state: directory - ansible.builtin.include_role: name: "{{ role }}" loop: - retronas.role.package.latest - retronas.role.cache loop_control: loop_var: role ================================================ FILE: ansible/retronas_system_config.yml ================================================ --- - hosts: localhost gather_facts: true roles: - retronas.role.system-config ================================================ FILE: ansible/retronas_systems.yml ================================================ --- # __________________________ # .-:=[ RetroNAS_Systems_Mapping ]=:-. # # Please keep everything organized, make sure if adding a new system all keys # are populated and the entry is in the appropriate area and order. # # usage # - use the retronas-systems-manager.py script in the maint directory to manage # new systems and projects (keys) in this file # - keep systems in their subgroups based on parent rom directory # - combine subgroups into other groups using union (see: system_map) # # terms: # - system: generally a manufacturer but the term system is carry over from og # retronas setup with this file # - project: batocera is a project and will be added to all entries as a blank # key you can populate later # # adding a new system # - retronas-systems-manager.py --add-new-system generic # # checking for project before adding # - retronas-systems-manager.py --check-project bestsoftware # # adding a new project # - retronas-systems-manager.py --add-new-project bestsoftware # system_template: - src: '' last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' system_links: - src: nec/pcengine dest: nec/turbografx16 - src: nec/pcenginecd dest: nec/turbografxcd - src: nintendo/famicom dest: nintendo/nes - src: nintendo/superfamicom dest: nintendo/snes - src: sega/megacd dest: sega/segacd - src: sega/megadrive dest: sega/genesis system_map: - src: acorn/archimedes last: '' mister: ARCHIE retropie: '' batocera: archimedes recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: acorn-archimedes replayfpgaarcade: '' retrodeck: archimedes romm: acorn-archimedes pretty_name: Acorn Achimedes - src: acorn/atom last: '' mister: AcornAtom retropie: '' batocera: atom recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: atom pretty_name: Acorn Atom - src: acorn/bbcmicro last: '' mister: BBCMicro retropie: '' batocera: bbcmicro recalbox: bbcmicro retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: bbcmicro igdb: bbcmicro replayfpgaarcade: '' retrodeck: bbcmicro romm: bbcmicro pretty_name: Acorn BBC Micro - src: acorn/electron last: '' mister: AcornElectron retropie: '' batocera: electron recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: acorn-electron replayfpgaarcade: '' retrodeck: electron romm: acorn-electron pretty_name: Acorn Electron - src: amstrad/cpc last: '' mister: Amstrad retropie: '' batocera: amstradcpc recalbox: amstradcpc retroarch: Amstrad - CPC ops2l: '' ps3netsrv: '' fspd: '' emuelec: amstradcpc smdb: '' freestation: '' analoguepocket: '' emudeck: amstradcpc igdb: acpc replayfpgaarcade: '' retrodeck: amstradcpc romm: acpc pretty_name: Amstrad CPC - src: amstrad/pcw last: '' mister: Amstrad PCW retropie: '' batocera: pcw recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: apcw replayfpgaarcade: '' retrodeck: '' romm: amstrad-pcw pretty_name: Amstrad PCW - src: amstrad/gx4000 last: '' mister: '' retropie: '' batocera: gx4000 recalbox: gx4000 retroarch: Amstrad - GX4000 ops2l: '' ps3netsrv: '' fspd: '' emuelec: amstradgx4000 smdb: '' freestation: gx4000 analoguepocket: '' emudeck: gx4000 igdb: gx4000 replayfpgaarcade: '' retrodeck: gx4000 romm: 'amstrad-gx4000' pretty_name: Amstrad GX4000 - src: antonic/galaksija last: other/antonic_galaksija mister: Galaksija retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Antonic Galaksija - src: apf/mp1000 last: '' mister: '' retropie: '' batocera: apfm1000 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: apf pretty_name: APF MP1000 - src: apogee/bk-01 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: bk-01 pretty_name: Apogee BK-01 - src: apple/applei last: '' mister: APPLE-I retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: 'apple' pretty_name: Apple 1 - src: apple/appleii last: '' mister: Apple-II retropie: '' batocera: apple2 recalbox: apple2 retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: apple2 smdb: '' freestation: '' analoguepocket: '' emudeck: apple2 igdb: appleii replayfpgaarcade: '' retrodeck: apple2 romm: appleii pretty_name: Apple II - src: apple/appleii last: '' mister: TK2000 retropie: '' batocera: '' recalbox: '' retroarch: Apple - II ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: TK2000 - src: apple/appleiigs last: '' mister: '' retropie: '' batocera: apple2gs recalbox: apple2gs retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: apple2gs igdb: apple-iigs replayfpgaarcade: '' retrodeck: apple2gs romm: apple-iigs pretty_name: Apple II/GS - src: apple/appleiii last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: 'appleiii' pretty_name: Apple III - src: apple/lisa last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: apple-lisa pretty_name: Apple Lisa - src: apple/macintosh last: '' mister: MACPLUS retropie: '' batocera: macintosh recalbox: macintosh retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: macintosh igdb: mac replayfpgaarcade: '' retrodeck: macintosh romm: mac pretty_name: Apple Machintosh - src: apple/newton last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: newton pretty_name: Apple Newton - src: apple/pippin last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: apple-pippin replayfpgaarcade: '' retrodeck: '' romm: apple-pippin pretty_name: Apple Pippin - src: arcade last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: arcade smdb: '' freestation: '' analoguepocket: '' emudeck: arcade igdb: arcade replayfpgaarcade: '' retrodeck: arcade romm: arcade pretty_name: Arcade - src: dice last: '' mister: '' retropie: '' batocera: dice recalbox: dice retroarch: DICE ops2l: '' ps3netsrv: '' fspd: '' emuelec: arcade smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: mame/hbmame last: '' mister: hbmame retropie: '' batocera: '' recalbox: '' retroarch: HBMAME ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: HBMAME - src: mame/mame last: '' mister: mame retropie: '' batocera: mame recalbox: mame retroarch: MAME ops2l: '' ps3netsrv: '' fspd: '' emuelec: mame smdb: '' freestation: mame analoguepocket: '' emudeck: mame igdb: '' replayfpgaarcade: '' retrodeck: mame romm: '' pretty_name: MAME - src: mame/mess last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: mess igdb: '' replayfpgaarcade: '' retrodeck: mess romm: '' pretty_name: MESS - src: mame/mame2000 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: MAME 2000 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: mame/mame2003p last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: MAME 2003-Plus ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: mame/mame2003 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: MAME 2003 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: mame/mame2010 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: MAME 2010 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: mame/mame2015 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: MAME 2015 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: mame/mame2016 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: MAME 2016 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: mame/namco22 last: '' mister: '' retropie: '' batocera: namco22 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: finalburn/fba last: '' mister: '' retropie: '' batocera: '' recalbox: fba retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: fba igdb: '' replayfpgaarcade: '' retrodeck: fba romm: '' pretty_name: Final Burn Alpha - src: finalburn/fbneo last: '' mister: '' retropie: '' batocera: fbneo recalbox: fbneo retroarch: FBNeo - Arcade Games ops2l: '' ps3netsrv: '' fspd: '' emuelec: fbn smdb: '' freestation: '' analoguepocket: '' emudeck: fbneo igdb: '' replayfpgaarcade: '' retrodeck: fbneo romm: '' pretty_name: Final Burn NEO - src: gaelco last: '' mister: '' retropie: '' batocera: gaelco recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Gaelco - src: snk/mvs last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: neogeomvs replayfpgaarcade: '' retrodeck: '' romm: neogeomvs pretty_name: SNK MVS - src: snk/hyper-neo-geo-64 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: hyper-neo-geo-64 replayfpgaarcade: '' retrodeck: '' romm: hyper-neo-geo-64 pretty_name: SNK Hyper NEO-GEO 64 - src: laserdisc last: '' mister: '' retropie: '' batocera: daphne recalbox: daphne retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: daphne smdb: '' freestation: '' analoguepocket: '' emudeck: daphne igdb: '' replayfpgaarcade: '' retrodeck: daphne romm: '' pretty_name: Daphne - src: laserdisc last: '' mister: '' retropie: '' batocera: singe recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: laserdisc romm: '' pretty_name: LaserDisc - src: pgm2 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: pgm2 smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: PGM2 - src: 'astral/2000' last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: astral-2000 pretty_name: Astral 2000 - src: atari/2600 last: '' mister: Atari2600 retropie: '' batocera: atari2600 recalbox: atari2600 retroarch: Atari - 2600 ops2l: '' ps3netsrv: '' fspd: '' emuelec: atari2600 smdb: Atari 2600 SMDB.txt freestation: a2600 analoguepocket: '2600' emudeck: atari2600 igdb: atari2600 replayfpgaarcade: '' retrodeck: atari2600 romm: atari2600 pretty_name: Atari 2600 - src: atari/5200 last: '' mister: ATARI5200 retropie: '' batocera: atari5200 recalbox: atari5200 retroarch: Atari - 5200 ops2l: '' ps3netsrv: '' fspd: '' emuelec: atari5200 smdb: Atari 5200 SMDB.txt freestation: a5200 analoguepocket: '' emudeck: atari5200 igdb: atari5200 replayfpgaarcade: '' retrodeck: atari5200 romm: atari5200 pretty_name: Atari 5200 - src: atari/7800 last: '' mister: ATARI7800 retropie: '' batocera: atari7800 recalbox: atari7800 retroarch: Atari - 7800 ops2l: '' ps3netsrv: '' fspd: '' emuelec: atari7800 smdb: Atari 7800 SMDB.txt freestation: a7800 analoguepocket: '7800' emudeck: atari7800 igdb: atari7800 replayfpgaarcade: '' retrodeck: atari7800 romm: atari7800 pretty_name: Atari 7800 - src: atari/800 last: '' mister: ATARI800 retropie: '' batocera: atari800 recalbox: atari800 retroarch: Atari - 8-bit Family ops2l: '' ps3netsrv: '' fspd: '' emuelec: atari800 smdb: '' freestation: a800 analoguepocket: '' emudeck: atari800 igdb: atari8bit replayfpgaarcade: '' retrodeck: atari800 romm: atari800 pretty_name: Atari 8-bit - src: atari/jaguar last: '' mister: Jaguar retropie: '' batocera: jaguar recalbox: jaguar retroarch: Atari - Jaguar ops2l: '' ps3netsrv: '' fspd: '' emuelec: atarijaguar smdb: Atari Jaguar SMDB.txt freestation: '' analoguepocket: '' emudeck: atarijaguar igdb: jaguar replayfpgaarcade: '' retrodeck: atarijaguar romm: jaguar pretty_name: Atari Jaguar - src: atari/jaguar/cd last: '' mister: '' retropie: '' batocera: jaguarcd recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: atari-jaguar-cd replayfpgaarcade: '' retrodeck: atarijaguarcd romm: atari-jaguar-cd pretty_name: Atari Jaguar CD - src: atari/lynx last: '' mister: AtariLynx retropie: '' batocera: lynx recalbox: lynx retroarch: Atari - Lynx ops2l: '' ps3netsrv: '' fspd: '' emuelec: atarilynx smdb: Atari Lynx SMDB.txt freestation: lynx analoguepocket: lynx emudeck: atarilynx igdb: lynx replayfpgaarcade: '' retrodeck: atarilynx romm: lynx pretty_name: Atari Lynx - src: atari/st last: '' mister: AtariST retropie: '' batocera: atarist recalbox: atarist retroarch: Atari - ST ops2l: '' ps3netsrv: '' fspd: '' emuelec: atarist smdb: '' freestation: '' analoguepocket: '' emudeck: atarist igdb: atari-st replayfpgaarcade: '' retrodeck: atarist romm: atari-st pretty_name: Atari ST - src: atari/st/flop last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Atari ST (flop) - src: atari/st/cart last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Atari ST (cart) - src: atari/vcs last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: atari-vcs pretty_name: Atari VCS - src: atari/xegs last: '' mister: '' retropie: '' batocera: xegs recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: atarixe igdb: '' replayfpgaarcade: '' retrodeck: atarixe romm: atari-xegs pretty_name: Atari XE - src: atmel/uzebox last: '' mister: '' retropie: '' batocera: uzebox recalbox: uzebox retroarch: Uzebox ops2l: '' ps3netsrv: '' fspd: '' emuelec: uzebox smdb: '' freestation: '' analoguepocket: '' emudeck: uzebox igdb: uzebox replayfpgaarcade: '' retrodeck: uzebox romm: uzebox pretty_name: Atmel Uzebox - src: audiosonic last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Audiosonic - src: bally/astrocade last: '' mister: Astrocade retropie: '' batocera: astrocade recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: astrocade analoguepocket: '' emudeck: astrocde igdb: astrocade replayfpgaarcade: '' retrodeck: astrocde romm: astrocade pretty_name: Bally Astrocade - src: bandai/rx78 last: '' mister: RX78 retropie: '' batocera: rx78 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Bandai RX78 - src: bandai/sumfami last: '' mister: '' retropie: '' batocera: sufami recalbox: sufami retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: sufami igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sufami-turbo pretty_name: Bandai Sumfami - src: bandai/wonderswan last: '' mister: WonderSwan retropie: '' batocera: wswan recalbox: wswan retroarch: Bandai - WonderSwan ops2l: '' ps3netsrv: '' fspd: '' emuelec: wonderswan smdb: Wonderswan SMDB.txt freestation: '' analoguepocket: wonderswan emudeck: wonderswan igdb: wonderswan replayfpgaarcade: '' retrodeck: wonderswan romm: wonderswan pretty_name: Bandai WonderSwan - src: bandai/wonderswancolor last: '' mister: WonderSwanColor retropie: '' batocera: wswanc recalbox: wswanc retroarch: Bandai - WonderSwan Color ops2l: '' ps3netsrv: '' fspd: '' emuelec: wonderswancolor smdb: Wonderswan SMDB.txt freestation: '' analoguepocket: '' emudeck: wonderswancolor igdb: wonderswan-color replayfpgaarcade: '' retrodeck: wonderswancolor romm: wonderswan-color pretty_name: Bandai WonderSwan Color - src: bandai/playdia last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: playdia replayfpgaarcade: '' retrodeck: '' romm: playdia pretty_name: Bandai Playdia - src: bandai/terebikko last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: terebikko-slash-see-n-say-video-phone replayfpgaarcade: '' retrodeck: '' romm: terebikko-slash-see-n-say-video-phone pretty_name: Bandai Terebikko - src: bandai/swancrystal last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: swancrystal replayfpgaarcade: '' retrodeck: '' romm: swancrystal pretty_name: Bandai WonderSwan Crystal - src: bandai/tamagotchi last: '' mister: '' retropie: '' batocera: '' recalbox: tamagotchi retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: tamagotchi_p1 emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Bandai Tamagotchi - src: bbc/bridgecompanion last: '' mister: BBCBridgeCompanion retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: BBC Bridge Companion - src: benesse/pocketchallengev2 last: '' mister: PocketChallengeV2 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pocket-challenge-v2 pretty_name: Benesse Pocket Challenge V2 - src: benesse/pocketchallengew last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pocket-challenge-w pretty_name: Benesse Pocket Challenge W - src: bitcorporation/gamate last: '' mister: Gamate retropie: '' batocera: gamate recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: gamate emudeck: '' igdb: gamate replayfpgaarcade: '' retrodeck: gamate romm: gamate pretty_name: Bit Corporation Gamate - src: bitcorporation/bit60 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Bit Corporation Bit-60 - src: bitcorporation/bit70 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Bit Corporation Bit-70 - src: bitcorporation/bit90 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: bit-90 pretty_name: Bit Corporation Bit-90 - src: cambridge/edsac last: other/cambridge_edsac mister: EDSAC retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: edsac pretty_name: Cambridge EDSAC - src: cambridgecomputer/z88 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: z88 pretty_name: Cambridge Z88 - src: camputers/lynx last: other/camputers_lynx mister: Lynx48 retropie: '' batocera: camplynx recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: camputers-lynx pretty_name: Camputers Lynx - src: casio/loopy last: '' mister: '' retropie: '' batocera: loopy recalbox: '' retroarch: Casio - Loopy ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: casio-loopy replayfpgaarcade: '' retrodeck: '' romm: casio-loopy pretty_name: Casio Loopy - src: casio/pv1000 last: '' mister: Casio_PV-1000 retropie: '' batocera: pv1000 recalbox: '' retroarch: Casio - PV-1000 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: pv1000 igdb: '' replayfpgaarcade: '' retrodeck: pv1000 romm: casio-pv-1000 pretty_name: Casio PV1000 - src: casio/pv2000 last: '' mister: Casio_PV-2000 retropie: '' batocera: pv2000 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: casio-pv-2000 pretty_name: Casio PV2000 - src: casio/cfx-9850 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: casio-cfx-9850 pretty_name: Casio CFX-9850 - src: casio/fp-1000 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: casio-fp-1000 pretty_name: Casio FP-1000 - src: casio/pb-1000 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: casio-pb-1000 pretty_name: Casio PB-1000 - src: cdc/cyber70 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: cdccyber70 replayfpgaarcade: '' retrodeck: '' romm: cdccyber70 pretty_name: CDC Cyber70 - src: coleco/colecovision last: other/coleco_colecovision mister: Coleco retropie: '' batocera: colecovision recalbox: colecovision retroarch: Coleco - ColecoVision ops2l: '' ps3netsrv: '' fspd: '' emuelec: colecovision smdb: Colecovision SMDB.txt freestation: coleco analoguepocket: coleco emudeck: colecovision igdb: colecovision replayfpgaarcade: '' retrodeck: colecovision romm: colecovision pretty_name: Coleco Colecovision - src: coleco/adam last: '' mister: Adam retropie: '' batocera: adam recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: adam romm: colecoadam pretty_name: Coleco Adam - src: coleco/telstararcade last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: telstar-arcade pretty_name: Coleco Telstar Arcade - src: commodore/amiga last: '' mister: Amiga retropie: '' batocera: amiga500 recalbox: amiga600 retroarch: Commodore - Amiga ops2l: '' ps3netsrv: '' fspd: '' emuelec: amiga smdb: '' freestation: amiga analoguepocket: amiga emudeck: amiga igdb: amiga replayfpgaarcade: '' retrodeck: amiga romm: amiga pretty_name: Commodore Amiga - src: commodore/amiga last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: ags igdb: '' replayfpgaarcade: '' retrodeck: ags romm: '' pretty_name: '' - src: commodore/amiga/iso last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: commodore/amiga1200 last: '' mister: '' retropie: '' batocera: amiga1200 recalbox: amiga1200 retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: amiga1200 igdb: '' replayfpgaarcade: '' retrodeck: amiga1200 romm: '' pretty_name: Commodore Amiga 1200 - src: commodore/amigacd32 last: '' mister: '' retropie: '' batocera: amigacd32 recalbox: amigacd32 retroarch: Commodore - CD32 ops2l: '' ps3netsrv: '' fspd: '' emuelec: amigacd32 smdb: '' freestation: '' analoguepocket: '' emudeck: amigacd32 igdb: amiga-cd32 replayfpgaarcade: '' retrodeck: amigacd32 romm: amiga-cd32 pretty_name: Commodore Amiga CD32 - src: commodore/amigacdtv last: '' mister: '' retropie: '' batocera: amigacdtv recalbox: amigacdtv retroarch: Commodore - CDTV ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: cdtv igdb: commodore-cdtv replayfpgaarcade: '' retrodeck: cdtv romm: commodore-cdtv pretty_name: Commodore Amiga CDTV - src: commodore/commodore16 last: '' mister: C16 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: c16 smdb: '' freestation: '' analoguepocket: '' emudeck: c16 igdb: c16 replayfpgaarcade: '' retrodeck: '' romm: c16 pretty_name: Commodore 16 - src: commodore/commodore64 last: '' mister: C64 retropie: '' batocera: c64 recalbox: c64 retroarch: Commodore - 64 ops2l: '' ps3netsrv: '' fspd: '' emuelec: c64 smdb: '' freestation: c64 analoguepocket: c64 emudeck: c64 igdb: c64 replayfpgaarcade: c64 retrodeck: c64 romm: c64 pretty_name: Commodore 64 - src: commodore/commodore128 last: '' mister: C128 retropie: '' batocera: c128 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: c128 smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: c128 pretty_name: Commodore 128 - src: commodore/pet last: '' mister: PET2001 retropie: '' batocera: pet recalbox: '' retroarch: Commodore - PET ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: cpet replayfpgaarcade: '' retrodeck: '' romm: cpet pretty_name: Commodore PET - src: commodore/vic20 last: '' mister: VIC20 retropie: '' batocera: c20 recalbox: vic20 retroarch: Commodore - VIC-20 ops2l: '' ps3netsrv: '' fspd: '' emuelec: vic20 smdb: '' freestation: '' analoguepocket: '' emudeck: vic20 igdb: vic-20 replayfpgaarcade: vic20 retrodeck: vic20 romm: vic-20 pretty_name: Commodore VIC20 - src: commodore/commodoreplus4 last: '' mister: '' retropie: '' batocera: cplus4 recalbox: '' retroarch: Commodore - Plus-4 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: c-plus-4 replayfpgaarcade: '' retrodeck: plus4 romm: c-plus-4 pretty_name: Commodore Plus 4 - src: compukit/uk101 last: other/compukit_uk101 mister: UK101 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: CompuKit UK101 - src: creatronic/megaduck last: '' mister: MegaDuck retropie: '' batocera: megaduck recalbox: megaduck retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: megaduck smdb: '' freestation: '' analoguepocket: mega_duck emudeck: megaduck igdb: mega-duck-slash-cougar-boy replayfpgaarcade: '' retrodeck: megaduck romm: mega-duck-slash-cougar-boy pretty_name: Creatronic Mega Duck - src: dec/pdp1 last: '' mister: PDP1 retropie: '' batocera: pdp1 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: pdp1 emudeck: '' igdb: pdp1 replayfpgaarcade: '' retrodeck: '' romm: pdp1 pretty_name: DEC PDP-1 - src: dec/pdp7 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pdp-7 pretty_name: DEC PDP-7 - src: dec/pdp8 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: pdp-8--1 replayfpgaarcade: '' retrodeck: '' romm: pdp-8 pretty_name: DEC PDP-8 - src: dec/pdp10 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: pdp10 replayfpgaarcade: '' retrodeck: '' romm: pdp10 pretty_name: DEC PDP-10 - src: dec/pdp11 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: pdp11 replayfpgaarcade: '' retrodeck: '' romm: pdp11 pretty_name: DEC PDP-11 - src: dec/gt40 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: gt40 pretty_name: DEC GT40 - src: dragon last: '' mister: '' retropie: '' batocera: dragon64 recalbox: dragon retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: dragon32 igdb: dragon-32-slash-64 replayfpgaarcade: '' retrodeck: dragon32 romm: dragon-32-slash-64 pretty_name: Dragon 32/64 - src: dragon last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: tanodragon igdb: '' replayfpgaarcade: '' retrodeck: tanodragon romm: '' pretty_name: '' - src: eaca/eg2000 last: '' mister: eg2000 retropie: '' batocera: cgenie recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: colour-genie pretty_name: EACA EG2000 Colour Genie - src: electronika/bk last: other/electronika_bk mister: BK0011M retropie: '' batocera: bk recalbox: bk retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: bk smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: bk pretty_name: Electronika Bk - src: elektor/tvgc last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: Elektor - TV Games Computer ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: elektor-tv-games-computer replayfpgaarcade: '' retrodeck: '' romm: elektor pretty_name: '' - src: emerson/arcadia2001 last: other/emerson_arcadia2001 mister: Arcadia retropie: '' batocera: arcadia recalbox: '' retroarch: Emerson - Arcadia 2001 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: arcadia emudeck: arcadia igdb: arcadia-2001 replayfpgaarcade: '' retrodeck: arcadia romm: arcadia-2001 pretty_name: Eemerson Arcadia 2001 - src: entex/adventurevision last: other/entex_adventurevision mister: AVision retropie: '' batocera: advision recalbox: '' retroarch: Entex - Adventure Vision ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: advision analoguepocket: avision emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: 'adventure-vision' pretty_name: Entex AdventureVision - src: epoch_co/scv last: '' mister: SCV retropie: '' batocera: scv recalbox: scv retroarch: Epoch - Super Cassette Vision ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: epoch-super-cassette-vision replayfpgaarcade: '' retrodeck: scv romm: epoch-super-cassette-vision pretty_name: Epoch Co Super Cassette Vision - src: epoch_co/cv last: '' mister: '' retropie: '' batocera: cassettevision recalbox: '' retroarch: Epoch - Cassette Vision ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: epoch-cassette-vision replayfpgaarcade: '' retrodeck: '' romm: epoch-cassette-vision pretty_name: Epoch Co Cassette Vision - src: epoch_co/galaxy2 last: '' mister: EpochGalaxyII retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Epoch Co Galaxy 2 - src: epoch_co/gamepocket last: '' mister: '' retropie: '' batocera: gamepock recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: epoch-game-pocket-computer pretty_name: Epoch Co Game Pocket - src: exidy/sorcerer last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: exidy-sorcerer replayfpgaarcade: '' retrodeck: '' romm: exidy-sorcerer pretty_name: Exidy Sorcerer - src: fairchild/channelf last: other/fairchild_channelf mister: ChannelF retropie: '' batocera: channelf recalbox: channelf retroarch: Fairchild - Channel F ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: channel_f emudeck: channelf igdb: fairchild-channel-f replayfpgaarcade: '' retrodeck: channelf romm: fairchild-channel-f pretty_name: Fairchild Channel F - src: fantasyconsole/pico8 last: '' mister: '' retropie: '' batocera: pico8 recalbox: pico8 retroarch: PICO-8 ops2l: '' ps3netsrv: '' fspd: '' emuelec: pico8 smdb: '' freestation: pico8 analoguepocket: '' emudeck: pico8 igdb: '' replayfpgaarcade: '' retrodeck: pico8 romm: '' pretty_name: Lexaloffle PICO-8 - src: fantasyconsole/tic80 last: '' mister: '' retropie: '' batocera: tic80 recalbox: tic80 retroarch: TIC-80 ops2l: '' ps3netsrv: '' fspd: '' emuelec: tic-80 smdb: '' freestation: '' analoguepocket: '' emudeck: tic80 igdb: '' replayfpgaarcade: '' retrodeck: tic80 romm: tic-80 pretty_name: TIC-80 - src: fantasyconsole/wasm4 last: '' mister: '' retropie: '' batocera: wasm4 recalbox: wasm4 retroarch: WASM-4 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: wasm4 igdb: '' replayfpgaarcade: '' retrodeck: wasm4 romm: wasm-4 pretty_name: '' - src: fantasyconsole/microw8 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: MicroW8 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: fantasyconsole/pyxel last: '' mister: '' retropie: '' batocera: pyxel recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: fantasyconsole/varvara last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: varvara emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: fantasyconsole/vircon32 last: '' mister: '' retropie: '' batocera: vircon32 recalbox: '' retroarch: Vircon32 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: fantasyconsole/lowresnx last: '' mister: '' retropie: '' batocera: lowresnx recalbox: lowresnx retroarch: LowRes NX ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: lowresnx romm: '' pretty_name: '' - src: ferranti/nimrod_computer last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: nimrod replayfpgaarcade: '' retrodeck: '' romm: nimrod pretty_name: Ferranti Nimrod Computer - src: fujitsu/fm-7 last: '' mister: '' retropie: '' batocera: fm7 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: fm-7 replayfpgaarcade: '' retrodeck: fm7 romm: fm-7 pretty_name: Fujitsu FM-7 - src: fujitsu/fmtowns last: '' mister: '' retropie: '' batocera: fmtowns recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: fmtowns smdb: '' freestation: '' analoguepocket: '' emudeck: fmtowns igdb: fm-towns replayfpgaarcade: '' retrodeck: fmtowns romm: fm-towns pretty_name: Fujitsu FM Towns - src: fujitsu/fmtownsmarty last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Fujitsu FM Towns Marty - src: funtech/superacan last: '' mister: '' retropie: '' batocera: supracan recalbox: '' retroarch: Funtech - Super Acan ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: super-acan replayfpgaarcade: '' retrodeck: supracan romm: super-acan pretty_name: Funtech Super ACan - src: gamepark/gp32 last: '' mister: '' retropie: '' batocera: gp32 recalbox: '' retroarch: GamePark - GP32 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: gp32 pretty_name: GamePark GP32 - src: gamepark/gp2x last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: gp2x pretty_name: GamePark GP2X - src: gamepark/gp2x-wiz last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: gp2x-wiz pretty_name: GamePark GP2X Wiz - src: generalinstruments/ay38500 last: other/generalinstrument_ay38500 mister: AY-3-8500 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: General Instruments AY38500 - src: generalinstruments/champion-2711 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: champion-2711 pretty_name: Champion 2711 - src: generalinstruments/gimini8600 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: gimini pretty_name: GIMINI 8600 - src: generalinstruments/gimini8900 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: GIMINI 8900 - src: generalinstruments/gimini8950 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: GIMINI 8950 - src: hartung/gamemaster last: '' mister: '' retropie: '' batocera: gmaster recalbox: '' retroarch: Hartung - Game Master ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: gmaster romm: hartung pretty_name: Hartung Game Master - src: homelab/homelab last: '' mister: Homelab retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Homelab - src: ibm/pcxt last: '' mister: PCXT retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: pc igdb: '' replayfpgaarcade: '' retrodeck: pc romm: '' pretty_name: IBM PCXT - src: ibm/pcjr last: '' mister: PCjr retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pc-jr pretty_name: IBM PCjr - src: ibm/5100 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: ibm-5100 pretty_name: IBM 5100 - src: infocom/zmachine last: '' mister: '' retropie: '' batocera: '' recalbox: zmachine retroarch: Infocom - Z-Machine ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: zmachine igdb: '' replayfpgaarcade: '' retrodeck: zmachine romm: z-machine pretty_name: Infocom Zmachine - src: intelligentsoftware/e128 last: '' mister: Enterprise retropie: '' batocera: enterprise recalbox: '' retroarch: Enterprise - 128 ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: enterprise pretty_name: Intelligent Software E128 - src: sri/500 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sri-5001000 pretty_name: SRI-500/1000 - src: intelligentsoftware/e64 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Intelligent Software E64 - src: interact/homecomputer last: other/interact_homecomputer mister: Interact retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: interact-model-one pretty_name: Interact Home Computer - src: interton/vc4000 last: other/interton_vc4000 mister: VC4000 retropie: '' batocera: vc4000 recalbox: '' retroarch: Interton - VC 4000 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: vc-4000 replayfpgaarcade: '' retrodeck: '' romm: interton-vc-4000 pretty_name: Interton VC4000 - src: interton/v2000 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: interton-video-2000 pretty_name: Interton Video 2000 - src: jupiter/ace last: other/jupiter_ace mister: Jupiter retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: jupiter-ace pretty_name: Jupiter ACE - src: leapfrog/clickstart last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: clickstart pretty_name: Leapfrog ClickStart - src: leapfrog/didj last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: didj pretty_name: Leapfrog Didj - src: leapfrog/leapster last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: LeapFrog - Leapster Learning Game System ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: leapster replayfpgaarcade: '' retrodeck: '' romm: leapster pretty_name: Leapfrog Leapster - src: leapfrog/explorer last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: leapster-explorer-slash-leadpad-explorer replayfpgaarcade: '' retrodeck: '' romm: leapfrog-explorer pretty_name: Leapfrog Explorer - src: leapfrog/leaptv last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: leaptv replayfpgaarcade: '' retrodeck: '' romm: leaptv pretty_name: Leapfrog LeapTV - src: magnavox/odyssey last: other/magnavox_odyssey mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: odyssey--1 replayfpgaarcade: '' retrodeck: '' romm: odyssey pretty_name: Magnavox Odyssey - src: magnavox/odyssey2 last: other/magnavox_odyssey2 mister: ODYSSEY2 retropie: '' batocera: odyssey2 recalbox: o2em retroarch: Magnavox - Odyssey2 ops2l: '' ps3netsrv: '' fspd: '' emuelec: odyssey2 smdb: '' freestation: '' analoguepocket: odyssey2 emudeck: odyssey2 igdb: odyssey-2-slash-videopac-g7000 replayfpgaarcade: '' retrodeck: odyssey2 romm: odyssey-2 pretty_name: Magnavox Odyssey 2 - src: mattel/aquarius last: '' mister: AQUARIUS retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: 'aquarius' pretty_name: Mattel Aquarius - src: mattel/intellivision last: '' mister: Intellivision retropie: '' batocera: intellivision recalbox: intellivision retroarch: Mattel - Intellivision ops2l: '' ps3netsrv: '' fspd: '' emuelec: intellivision smdb: '' freestation: '' analoguepocket: intv emudeck: intellivision igdb: intellivision replayfpgaarcade: '' retrodeck: intellivision romm: intellivision pretty_name: Mattel Intellivision - src: mattel/intellivision_amico last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: intellivision-amico replayfpgaarcade: '' retrodeck: '' romm: intellivision-amico pretty_name: Mattel Intellivision Amico - src: mattel/hyperscan last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: hyperscan replayfpgaarcade: '' retrodeck: '' romm: hyperscan pretty_name: Mattel Hyperscan - src: microsoft/msx last: '' mister: MSX retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: msx emudeck: msx igdb: msx replayfpgaarcade: '' retrodeck: msx romm: msx pretty_name: Microsoft MSX - src: microsoft/msx last: '' mister: MSX1 retropie: '' batocera: msx1 recalbox: msx1 retroarch: Microsoft - MSX ops2l: '' ps3netsrv: '' fspd: '' emuelec: msx smdb: '' freestation: msx analoguepocket: '' emudeck: msx1 igdb: '' replayfpgaarcade: '' retrodeck: msx1 romm: '' pretty_name: '' - src: microsoft/msx2 last: '' mister: '' retropie: '' batocera: msx2 recalbox: msx2 retroarch: Microsoft - MSX2 ops2l: '' ps3netsrv: '' fspd: '' emuelec: msx2 smdb: '' freestation: msx2 analoguepocket: '' emudeck: msx2 igdb: msx2 replayfpgaarcade: '' retrodeck: msx2 romm: msx2 pretty_name: Microsoft MSX2 - src: microsoft/msxplus last: '' mister: '' retropie: '' batocera: msx2+ recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: msx2plus pretty_name: Microsoft MSX2+ - src: microsoft/msxturbor last: '' mister: '' retropie: '' batocera: msxturbor recalbox: msxturbor retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: msxturbor igdb: '' replayfpgaarcade: '' retrodeck: msxturbor romm: msx-turbo pretty_name: Microsoft MSX Turbo R - src: microsoft/xbox last: '' mister: '' retropie: '' batocera: xbox recalbox: xbox retroarch: Microsoft - Xbox ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: xbox analoguepocket: '' emudeck: xbox igdb: xbox replayfpgaarcade: '' retrodeck: xbox romm: xbox pretty_name: Microsoft XBOX - src: microsoft/xbox/iso last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Microsoft XBOX (ISO) - src: microsoft/xbox/games last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Microsoft XBOX (Games) - src: microsoft/xbox360 last: '' mister: '' retropie: '' batocera: xbox360 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: x360 analoguepocket: '' emudeck: xbox360 igdb: xbox360 replayfpgaarcade: '' retrodeck: xbox360 romm: xbox360 pretty_name: Microsoft Xbox 360 - src: microsoft/xbox360/iso last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Microsoft Xbox 360 (ISO) - src: microsoft/xbox360/games last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Microsoft Xbox 360 (Games) - src: microsoft/xboxone last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: xboxone replayfpgaarcade: '' retrodeck: '' romm: xboxone pretty_name: Microsoft Xbox One - src: microsoft/xbox-series-x last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: series-x-s replayfpgaarcade: '' retrodeck: '' romm: series-x-s pretty_name: Microsoft Xbox Series-X - src: microsoft/windows last: '' mister: '' retropie: '' batocera: windows recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: win replayfpgaarcade: '' retrodeck: windows romm: win pretty_name: Microsoft Windows - src: microsoft/windows/installers last: '' mister: '' retropie: '' batocera: windows_installers recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: windows-apps pretty_name: Microsoft Windows (Installers) - src: microsoft/windows/windows3x last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: windows3x romm: win3x pretty_name: Microsoft Windows 3x - src: microsoft/windows/windows9x last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: windows9x romm: '' pretty_name: Microsoft Windows 9x - src: microsoft/dos last: '' mister: '' retropie: '' batocera: dos recalbox: dos retroarch: DOS ops2l: '' ps3netsrv: '' fspd: '' emuelec: pc smdb: '' freestation: dos analoguepocket: '' emudeck: dos igdb: dos replayfpgaarcade: '' retrodeck: dos romm: dos pretty_name: Microsoft MS-DOS - src: microsoft/windows-mobile last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: windows-mobile replayfpgaarcade: '' retrodeck: '' romm: windows-mobile pretty_name: Microsoft Windows Mobile - src: microsoft/windows-phone last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: winphone replayfpgaarcade: '' retrodeck: '' romm: winphone pretty_name: Microsoft Windows Phone - src: microsoft/zune last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: zune pretty_name: Microsoft Zune - src: milesgordon/samcoupe last: other/milesgordon_samcoupe mister: SAMCOUPE retropie: '' batocera: samcoupe recalbox: samcoupe retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: samcoupe igdb: '' replayfpgaarcade: '' retrodeck: samcoupe romm: sam-coupe pretty_name: Miles Gordon Sam Coupe - src: miltonbradley/microvision last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: microvision--1 replayfpgaarcade: '' retrodeck: '' romm: microvision pretty_name: Milton Bradley Microvision - src: mits/altair8800 last: other/mits_altair8800 mister: Altair8800 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: 'altair-8800' pretty_name: MITS Altair 8800 - src: mits/altair680 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: altair-680 pretty_name: MITS Altair 680 - src: nabu last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: NABU - src: nec/pc88 last: '' mister: PC8801 retropie: '' batocera: pc88 recalbox: pc88 retroarch: NEC - PC-8001 - PC-8801 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: pc88 igdb: pc-8800-series replayfpgaarcade: '' retrodeck: pc88 romm: pc-8800-series pretty_name: NEC PC88 - src: nec/pc98 last: '' mister: Zet98 retropie: '' batocera: pc98 recalbox: pc98 retroarch: NEC - PC-98 ops2l: '' ps3netsrv: '' fspd: '' emuelec: pc-9800 smdb: '' freestation: '' analoguepocket: '' emudeck: pc98 igdb: pc-9800-series replayfpgaarcade: '' retrodeck: pc98 romm: pc-9800-series pretty_name: NEC PC98 - src: nec/pcengine last: '' mister: '' retropie: '' batocera: pcengine recalbox: pcengine retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: pcengine smdb: Turbo EverDrive & Super SD System 3 SMDB.txt freestation: pce analoguepocket: pce emudeck: pcengine igdb: turbografx-16-slash-pc-engine-cd replayfpgaarcade: '' retrodeck: pcengine romm: '' pretty_name: NEC PC-Engine - src: nec/pcengine last: '' mister: TGFX16 retropie: '' batocera: '' recalbox: '' retroarch: NEC - PC Engine - TurboGrafx 16 ops2l: '' ps3netsrv: '' fspd: '' emuelec: tg16 smdb: Turbo EverDrive & Super SD System 3 SMDB.txt freestation: '' analoguepocket: '' emudeck: tg16 igdb: turbografx16--1 replayfpgaarcade: '' retrodeck: tg16 romm: tg16 pretty_name: '' - src: nec/pcenginecd last: '' mister: '' retropie: '' batocera: pcenginecd recalbox: pcenginecd retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: pcenginecd smdb: PC Engine CD Redump Supplement.txt freestation: pcecd analoguepocket: pcecd emudeck: pcenginecd igdb: '' replayfpgaarcade: '' retrodeck: pcenginecd romm: '' pretty_name: NEC PC-Engine CD - src: nec/pcenginecd last: '' mister: TGFX16-CD retropie: '' batocera: '' recalbox: '' retroarch: NEC - PC Engine CD - TurboGrafx-CD ops2l: '' ps3netsrv: '' fspd: '' emuelec: tg16cd smdb: PC Engine CD Redump Supplement.txt freestation: '' analoguepocket: '' emudeck: tg-cd igdb: '' replayfpgaarcade: '' retrodeck: '' romm: turbografx-cd pretty_name: '' - src: nec/pcengine/supergrafx last: '' mister: '' retropie: '' batocera: supergrafx recalbox: supergrafx retroarch: NEC - PC Engine SuperGrafx ops2l: '' ps3netsrv: '' fspd: '' emuelec: supergrafx smdb: '' freestation: '' analoguepocket: '' emudeck: supergrafx igdb: supergrafx replayfpgaarcade: '' retrodeck: supergrafx romm: supergrafx pretty_name: NEX SuperGrafx - src: nec/pcfx last: '' mister: '' retropie: '' batocera: pcfx recalbox: pcfx retroarch: NEC - PC-FX ops2l: '' ps3netsrv: '' fspd: '' emuelec: pcfx smdb: '' freestation: '' analoguepocket: '' emudeck: pcfx igdb: pc-fx replayfpgaarcade: '' retrodeck: pcfx romm: pc-fx pretty_name: NEC PCFX - src: nec/pc6000 last: '' mister: '' retropie: '' batocera: pc60 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: nec-pc-6000-series replayfpgaarcade: '' retrodeck: '' romm: nec-pc-6000-series pretty_name: NEC PC6000 - src: nec/pc6001 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pc-6001 pretty_name: NEC PC6001 - src: nec/pc8000 last: '' mister: '' retropie: '' batocera: pc80 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pc-8000 pretty_name: NEC PC8000 - src: nintendo/3ds last: '' mister: '' retropie: '' batocera: 3ds recalbox: '' retroarch: Nintendo - Nintendo 3DS ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: 3ds analoguepocket: '' emudeck: '' igdb: 3ds replayfpgaarcade: '' retrodeck: n3ds romm: 3ds pretty_name: Nintendo 3DS - src: nintendo/3ds last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: new-3ds replayfpgaarcade: '' retrodeck: '' romm: new-nintendo-3ds pretty_name: '' - src: nintendo/ds last: '' mister: '' retropie: '' batocera: nds recalbox: nds retroarch: Nintendo - Nintendo DS ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: nds igdb: nds replayfpgaarcade: '' retrodeck: nds romm: nds pretty_name: Nintendo DS - src: nintendo/dsi last: '' mister: '' retropie: '' batocera: nds recalbox: nds retroarch: Nintendo - Nintendo DSi ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: nintendo-dsi replayfpgaarcade: '' retrodeck: '' romm: nintendo-dsi pretty_name: Nintendo DSi - src: nintendo/ereader last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: Nintendo - e-Reader ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: e-reader-slash-card-e-reader replayfpgaarcade: '' retrodeck: '' romm: e-reader-slash-card-e-reader pretty_name: Nintendo eReader - src: nintendo/famicom last: '' mister: NES retropie: '' batocera: nes recalbox: nes retroarch: Nintendo - Nintendo Entertainment System ops2l: '' ps3netsrv: '' fspd: '' emuelec: nes smdb: NES2.0 SMDB.txt freestation: nes analoguepocket: nes emudeck: famicom igdb: famicom replayfpgaarcade: '' retrodeck: famicom romm: famicom pretty_name: Nintendo Famicom - src: nintendo/famicom last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: famicom smdb: '' freestation: '' analoguepocket: '' emudeck: nes igdb: nes replayfpgaarcade: '' retrodeck: nes romm: nes pretty_name: '' - src: nintendo/famicom/disk last: '' mister: '' retropie: '' batocera: fds recalbox: fds retroarch: Nintendo - Family Computer Disk System ops2l: '' ps3netsrv: '' fspd: '' emuelec: fds smdb: Famicom Disk System SMDB.txt freestation: '' analoguepocket: '' emudeck: fds igdb: fds replayfpgaarcade: '' retrodeck: fds romm: fds pretty_name: Nintendo Famicom Disk - src: nintendo/gameandwatch last: '' mister: GameNWatch retropie: '' batocera: gameandwatch recalbox: gw retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: gameandwatch smdb: '' freestation: '' analoguepocket: gameandwatch emudeck: gameandwatch igdb: g-and-w replayfpgaarcade: '' retrodeck: gameandwatch romm: g-and-w pretty_name: Nintendo Game & Watch - src: nintendo/gameboy last: '' mister: GAMEBOY retropie: '' batocera: gb recalbox: gb retroarch: Nintendo - Game Boy ops2l: '' ps3netsrv: '' fspd: '' emuelec: gb smdb: Game Boy SMDB.txt freestation: '' analoguepocket: gb emudeck: gb igdb: gb replayfpgaarcade: '' retrodeck: gb romm: gb pretty_name: Nintendo Game Boy - src: nintendo/gameboy last: '' mister: '' retropie: '' batocera: gb2players recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: nintendo/gameboyadvance last: '' mister: GBA retropie: '' batocera: gba recalbox: gba retroarch: Nintendo - Game Boy Advance ops2l: '' ps3netsrv: '' fspd: '' emuelec: gba smdb: EverDrive GBA SMDB.txt freestation: gba analoguepocket: gba emudeck: gba igdb: gba replayfpgaarcade: '' retrodeck: gba romm: gba pretty_name: Nintendo Game Boy Advance - src: nintendo/gameboycolor last: '' mister: GBC retropie: '' batocera: gbc recalbox: gbc retroarch: Nintendo - Game Boy Color ops2l: '' ps3netsrv: '' fspd: '' emuelec: gbc smdb: Game Boy Color SMDB.txt freestation: gbc analoguepocket: gbc emudeck: gbc igdb: gbc replayfpgaarcade: '' retrodeck: gbc romm: gbc pretty_name: Nintendo Game Boy Color - src: nintendo/gameboycolor last: '' mister: '' retropie: '' batocera: gbc2players recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: nintendo/gamecube/iso last: '' mister: '' retropie: '' batocera: gamecube recalbox: gamecube retroarch: Nintendo - GameCube ops2l: '' ps3netsrv: '' fspd: games emuelec: gamecube smdb: '' freestation: ngc analoguepocket: '' emudeck: '' igdb: ngc replayfpgaarcade: '' retrodeck: gc romm: ngc pretty_name: Nintendo - Gamecube (ISO) - src: nintendo/nintendo64 last: '' mister: N64 retropie: '' batocera: n64 recalbox: n64 retroarch: Nintendo - Nintendo 64 ops2l: '' ps3netsrv: '' fspd: '' emuelec: n64 smdb: EverDrive 64 & 64drive SMDB.txt freestation: n64 analoguepocket: '' emudeck: n64 igdb: n64 replayfpgaarcade: '' retrodeck: n64 romm: n64 pretty_name: Nintendo 64 - src: nintendo/nintendo64dd last: '' mister: '' retropie: '' batocera: n64dd recalbox: 64dd retroarch: Nintendo - Nintendo 64DD ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: n64dd igdb: 64dd replayfpgaarcade: '' retrodeck: n64dd romm: 64dd pretty_name: Nintendo 64DD - src: nintendo/pokemini last: '' mister: PokemonMini retropie: '' batocera: pokemini recalbox: pokemini retroarch: Nintendo - Pokemon Mini ops2l: '' ps3netsrv: '' fspd: '' emuelec: pokemini smdb: '' freestation: '' analoguepocket: poke_mini emudeck: pokemini igdb: pokemon-mini replayfpgaarcade: '' retrodeck: pokemini romm: pokemon-mini pretty_name: Nintendo Pokemini - src: nintendo/satellaview last: '' mister: '' retropie: '' batocera: satellaview recalbox: satellaview retroarch: Nintendo - Satellaview ops2l: '' ps3netsrv: '' fspd: '' emuelec: satellaview smdb: '' freestation: '' analoguepocket: '' emudeck: satellaview igdb: satellaview replayfpgaarcade: '' retrodeck: satellaview romm: satellaview pretty_name: Nintendo SatellaView - src: nintendo/superfamicom/msu1 last: '' mister: '' retropie: '' batocera: snes-msu1 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: snesmsu1 smdb: '' freestation: snes analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Nintendo Super Famicom (MSU1) - src: nintendo/superfamicom/sufami last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: Nintendo - Sufami Turbo ops2l: '' ps3netsrv: '' fspd: '' emuelec: sufami smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: sufami romm: '' pretty_name: Nintendo Super Famicom (Sufami) - src: nintendo/superfamicom last: '' mister: SNES retropie: '' batocera: snes recalbox: snes retroarch: Nintendo - Super Nintendo Entertainment System ops2l: '' ps3netsrv: '' fspd: '' emuelec: snes smdb: Super EverDrive & SD2SNES SMDB.txt freestation: snes analoguepocket: snes emudeck: snes igdb: snes replayfpgaarcade: '' retrodeck: snes romm: snes pretty_name: Nintendo Super Famicom - src: nintendo/superfamicom last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: sfc smdb: '' freestation: '' analoguepocket: '' emudeck: sfc igdb: sfam replayfpgaarcade: '' retrodeck: sfc romm: sfam pretty_name: '' - src: nintendo/supergameboy last: '' mister: SGB retropie: '' batocera: sgb recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: sgb emudeck: sgb igdb: '' replayfpgaarcade: '' retrodeck: sgb romm: '' pretty_name: Nintendo Super Game Boy - src: nintendo/supergameboy/msu1 last: '' mister: '' retropie: '' batocera: sgb-msu1 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Nintendo Super Game Boy (MSU1) - src: nintendo/virtualboy last: '' mister: '' retropie: '' batocera: virtualboy recalbox: virtualboy retroarch: Nintendo - Virtual Boy ops2l: '' ps3netsrv: '' fspd: '' emuelec: virtualboy smdb: '' freestation: '' analoguepocket: '' emudeck: virtualboy igdb: virtualboy replayfpgaarcade: '' retrodeck: virtualboy romm: virtualboy pretty_name: Nintendo Virtual Boy - src: nintendo/virtualconsole last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: vc replayfpgaarcade: '' retrodeck: '' romm: vc pretty_name: Nintendo Virtual Console - src: nintendo/wii last: '' mister: '' retropie: '' batocera: wii recalbox: wii retroarch: Nintendo - Wii ops2l: '' ps3netsrv: '' fspd: '' emuelec: wii smdb: '' freestation: wii analoguepocket: '' emudeck: wii igdb: wii replayfpgaarcade: '' retrodeck: wii romm: wii pretty_name: Nintendo Wii - src: nintendo/wiid last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: Nintendo - Wii (Digital) ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: wiiu analoguepocket: '' emudeck: wiiu igdb: wiiu replayfpgaarcade: '' retrodeck: wiiu romm: wiiu pretty_name: Nintendo Wii (Digital) - src: nintendo/wiiu last: '' mister: '' retropie: '' batocera: wiiu recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: wiiu analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Nintendo Wii-U - src: nintendo/nintendo-playstation last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: super-nes-cd-rom-system replayfpgaarcade: '' retrodeck: '' romm: super-nes-cd-rom-system pretty_name: Nintendo PlayStation - src: nichibutsu/myvision last: '' mister: MyVision retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Nichibutsu MyVision - src: nokia/n-gage last: '' mister: '' retropie: '' batocera: ngage recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ngage replayfpgaarcade: '' retrodeck: ngage romm: ngage pretty_name: Nokia N-Gage - src: nokia/n-gage2 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: ngage2 pretty_name: Nokia N-Gage (Service) - src: oric/atmos last: '' mister: '' retropie: '' batocera: oricatmos recalbox: oricatmos retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: atmos pretty_name: Oric ATMOS - src: oric/tangerine last: '' mister: Oric retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: oric igdb: '' replayfpgaarcade: '' retrodeck: oric romm: '' pretty_name: Oric Tangerine - src: oric/telestrat last: '' mister: TeleStrat retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: oric pretty_name: Oric Telestrat - src: ouya/ouya last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ouya replayfpgaarcade: '' retrodeck: '' romm: ouya pretty_name: OUYA - src: panic/playdate last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: playdate replayfpgaarcade: '' retrodeck: '' romm: playdate pretty_name: Panic Playdate - src: panasonic/3do last: other/3do mister: '' retropie: '' batocera: 3do recalbox: 3do retroarch: The 3DO Company - 3DO ops2l: '' ps3netsrv: '' fspd: '' emuelec: 3do smdb: '' freestation: '' analoguepocket: '' emudeck: 3do igdb: 3do replayfpgaarcade: '' retrodeck: 3do romm: 3do pretty_name: Panasonic 3DO - src: panasonic/jungle last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: panasonic-jungle pretty_name: Panasonic Jungle - src: pelvarazdin/orao last: other/pelvarazdin_orao mister: ORAO retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: panasonic-jungle replayfpgaarcade: '' retrodeck: '' romm: orao pretty_name: Pelvarazdin Orao - src: philips/cdi last: '' mister: CD-i retropie: '' batocera: cdi recalbox: cdi retroarch: Philips - CD-i ops2l: '' ps3netsrv: '' fspd: '' emuelec: phillips-cdi smdb: '' freestation: '' analoguepocket: '' emudeck: cdimono1 igdb: philips-cdi replayfpgaarcade: '' retrodeck: cdimono1 romm: philips-cd-i pretty_name: Philips CDI - src: philips/videopacplus last: '' mister: '' retropie: '' batocera: videopacplus recalbox: videopacplus retroarch: Philips - Videopac+ ops2l: '' ps3netsrv: '' fspd: '' emuelec: videopac smdb: '' freestation: '' analoguepocket: '' emudeck: videopac igdb: '' replayfpgaarcade: '' retrodeck: videopac romm: videopac-g7400 pretty_name: Philips Videopac+ - src: philips/vg5000 last: '' mister: '' retropie: '' batocera: '' recalbox: vg5000 retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: philips-vg-5000 pretty_name: Philips VG5000 - src: sega/32x last: '' mister: S32X retropie: '' batocera: sega32x recalbox: sega32x retroarch: Sega - 32X ops2l: '' ps3netsrv: '' fspd: '' emuelec: sega32x smdb: '' freestation: 32x analoguepocket: '' emudeck: sega32x igdb: sega32 replayfpgaarcade: '' retrodeck: sega32x romm: sega32 pretty_name: SEGA 32X - src: sega/aicomputer last: '' mister: '' retropie: '' batocera: segaai recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: SEGA AI Computer - src: sega/atomiswave last: '' mister: '' retropie: '' batocera: atomiswave recalbox: atomiswave retroarch: Atomiswave ops2l: '' ps3netsrv: '' fspd: '' emuelec: atomiswave smdb: '' freestation: '' analoguepocket: '' emudeck: atomiswave igdb: '' replayfpgaarcade: '' retrodeck: atomiswave romm: '' pretty_name: SEGA Atomiswave - src: sega/advancedpicobeena last: '' mister: '' retropie: '' batocera: beena recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: advanced-pico-beena replayfpgaarcade: '' retrodeck: '' romm: advanced-pico-beena pretty_name: SEGA Advanced Pico Beena - src: sega/chihiro last: '' mister: '' retropie: '' batocera: chihiro recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: SEGA Chihiro - src: sega/dreamcast last: '' mister: '' retropie: '' batocera: dreamcast recalbox: dreamcast retroarch: Sega - Dreamcast ops2l: '' ps3netsrv: '' fspd: '' emuelec: dreamcast smdb: '' freestation: dc analoguepocket: '' emudeck: dreamcast igdb: dc replayfpgaarcade: '' retrodeck: dreamcast romm: dc pretty_name: SEGA Dreamcast - src: sega/dreamcast/vmu last: '' mister: '' retropie: '' batocera: vemulator recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: visual-memory-unit-slash-visual-memory-system replayfpgaarcade: '' retrodeck: '' romm: vmu pretty_name: SEGA Dreamcast VMU - src: sega/gamegear last: '' mister: GameGear retropie: '' batocera: gamegear recalbox: gamegear retroarch: Sega - Game Gear ops2l: '' ps3netsrv: '' fspd: '' emuelec: gamegear smdb: EverDrive GG SMDB.txt freestation: gg analoguepocket: gg emudeck: gamegear igdb: gamegear replayfpgaarcade: '' retrodeck: gamegear romm: gamegear pretty_name: SEGA Game Gear - src: sega/hikaru last: '' mister: '' retropie: '' batocera: hikaru recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: hikaru pretty_name: SEGA Hikaru - src: sega/mastersystem last: '' mister: SMS retropie: '' batocera: mastersystem recalbox: mastersystem retroarch: Sega - Master System - Mark III ops2l: '' ps3netsrv: '' fspd: '' emuelec: mastersystem smdb: Master EverDrive SMDB.txt freestation: sms analoguepocket: sms emudeck: '' igdb: sms replayfpgaarcade: '' retrodeck: mastersystem romm: sms pretty_name: SEGA Master System - src: sega/megacd last: '' mister: MegaCD retropie: '' batocera: megacd recalbox: segacd retroarch: Sega - Mega-CD - Sega CD ops2l: '' ps3netsrv: '' fspd: '' emuelec: segacd smdb: SegaCD.txt freestation: mcd analoguepocket: '' emudeck: megacd igdb: sega-cd replayfpgaarcade: '' retrodeck: megacd romm: segacd pretty_name: SEGA Mega CD - src: sega/megacd32x last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: sega-cd-32x replayfpgaarcade: '' retrodeck: '' romm: segacd32 pretty_name: SEGA Mega CD + 32x - src: sega/megadrive last: '' mister: Genesis retropie: '' batocera: megadrive recalbox: megadrive retroarch: Sega - Mega Drive - Genesis ops2l: '' ps3netsrv: '' fspd: '' emuelec: genesis smdb: Mega EverDrive SMDB.txt freestation: smd analoguepocket: genesis emudeck: megadrive igdb: genesis-slash-megadrive replayfpgaarcade: '' retrodeck: genesis romm: genesis pretty_name: SEGA Mega Drive - src: sega/megadrive last: '' mister: MegaDrive retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: megadrive smdb: '' freestation: '' analoguepocket: '' emudeck: genesiswide igdb: '' replayfpgaarcade: '' retrodeck: megadrive romm: '' pretty_name: '' - src: sega/megadrive/msu last: '' mister: '' retropie: '' batocera: megadrive-msu recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: megadrivemsu smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: SEGA Mega Drive (MSU) - src: sega/megadrive last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: megadrive-japan smdb: '' freestation: smd analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: sega/model1 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: model1 pretty_name: SEGA Model 1 - src: sega/model2 last: '' mister: '' retropie: '' batocera: model2 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: model2 igdb: '' replayfpgaarcade: '' retrodeck: model2 romm: model2 pretty_name: SEGA Model 2 - src: sega/model3 last: '' mister: '' retropie: '' batocera: model3 recalbox: model3 retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: model3 analoguepocket: '' emudeck: model3 igdb: '' replayfpgaarcade: '' retrodeck: model3 romm: model3 pretty_name: SEGA Model 3 - src: sega/naomi last: '' mister: '' retropie: '' batocera: naomi recalbox: naomi retroarch: Sega - Naomi ops2l: '' ps3netsrv: '' fspd: '' emuelec: naomi smdb: '' freestation: '' analoguepocket: '' emudeck: naomi igdb: '' replayfpgaarcade: '' retrodeck: naomi romm: '' pretty_name: SEGA Naomi - src: sega/naomi2 last: '' mister: '' retropie: '' batocera: naomi2 recalbox: naomi2 retroarch: Sega - Naomi 2 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: naomi2 igdb: '' replayfpgaarcade: '' retrodeck: naomi2 romm: '' pretty_name: SEGA Naomi 2 - src: sega/naomigd last: '' mister: '' retropie: '' batocera: '' recalbox: naomigd retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: naomigd igdb: '' replayfpgaarcade: '' retrodeck: naomigd romm: '' pretty_name: '' - src: sega/pico last: '' mister: '' retropie: '' batocera: pico recalbox: pico retroarch: Sega - PICO ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: sega-pico replayfpgaarcade: '' retrodeck: '' romm: sega-pico pretty_name: SEGA Pico - src: sega/saturn last: '' mister: Saturn retropie: '' batocera: saturn recalbox: saturn retroarch: Sega - Saturn ops2l: '' ps3netsrv: '' fspd: '' emuelec: saturn smdb: Saturn Redump Supplement.txt freestation: sat analoguepocket: '' emudeck: saturn igdb: saturn replayfpgaarcade: '' retrodeck: saturn romm: saturn pretty_name: SEGA Saturn - src: sega/sg1000 last: '' mister: SG1000 retropie: '' batocera: sg1000 recalbox: sg1000 retroarch: Sega - SG-1000 ops2l: '' ps3netsrv: '' fspd: '' emuelec: sg-1000 smdb: Sega SG-1000 SMDB.txt freestation: sg1000 analoguepocket: sg1000 emudeck: sg-1000 igdb: sg1000 replayfpgaarcade: '' retrodeck: sg-1000 romm: sg1000 pretty_name: SEGA SG-1000 - src: sega/triforce last: '' mister: '' retropie: '' batocera: triforce recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: triforce romm: '' pretty_name: SEGA Triforce - src: sega/sc3000 last: '' mister: '' retropie: '' batocera: sc3000 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: sc-3000 smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sc3000 pretty_name: SEGA SC-3000 - src: sega/systemsp last: '' mister: '' retropie: '' batocera: systemsp recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: SEGA System SP - src: sega/stv last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: stv romm: stv pretty_name: SEGA STV - src: sega/system16 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: system16 pretty_name: SEGA System 16 - src: sega/system32 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: system32 pretty_name: SEGA System 32 - src: sega/lindbergh last: '' mister: '' retropie: '' batocera: lindbergh recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: SEGA Lindbergh - src: sharp/mz last: '' mister: SharpMZ retropie: '' batocera: mz80k recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sharp-mz-80k7008001500 pretty_name: Sharp MZ 80k/700/800/1500 - src: sharp/mzb last: '' mister: '' retropie: '' batocera: mz2000 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sharp-mz-80b20002500 pretty_name: Sharp MZ-80B/2000/2500 - src: sharp/mz2200 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: sharp-mz-2200 replayfpgaarcade: '' retrodeck: '' romm: sharp-mz-2200 pretty_name: Sharp MZ-2200 - src: sharp/x1 last: '' mister: '' retropie: '' batocera: x1 recalbox: x1 retroarch: Sharp - X1 ops2l: '' ps3netsrv: '' fspd: '' emuelec: x1 smdb: '' freestation: '' analoguepocket: '' emudeck: x1 igdb: x1 replayfpgaarcade: '' retrodeck: x1 romm: x1 pretty_name: Sharp X1 - src: sharp/x68000 last: '' mister: X68000 retropie: '' batocera: x68000 recalbox: x68000 retroarch: Sharp - X68000 ops2l: '' ps3netsrv: '' fspd: '' emuelec: x68000 smdb: '' freestation: x86k analoguepocket: '' emudeck: x68000 igdb: sharp-x68000 replayfpgaarcade: '' retrodeck: x68000 romm: sharp-x68000 pretty_name: Sharp X68000 - src: sharp/zaurus last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sharp-zaurus pretty_name: Sharp Zaurus - src: sinclair/ql last: '' mister: QL retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: sinclair-ql replayfpgaarcade: '' retrodeck: '' romm: sinclair-ql pretty_name: Sinclair QL - src: sinclair/zx80 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: zx80 pretty_name: Sinclair ZX80 - src: sinclair/zx81 last: '' mister: ZX81 retropie: '' batocera: zx81 recalbox: zx81 retroarch: Sinclair - ZX 81 ops2l: '' ps3netsrv: '' fspd: '' emuelec: zx81 smdb: '' freestation: '' analoguepocket: '' emudeck: zx81 igdb: sinclair-zx81 replayfpgaarcade: '' retrodeck: zx81 romm: zx81 pretty_name: Sinclair ZX81 - src: sinclair/zxspectrum last: '' mister: Spectrum retropie: '' batocera: zxspectrum recalbox: zxspectrum retroarch: Sinclair - ZX Spectrum ops2l: '' ps3netsrv: '' fspd: '' emuelec: zxspectrum smdb: '' freestation: '' analoguepocket: zxspectrum emudeck: zxspectrum igdb: zxs replayfpgaarcade: '' retrodeck: zxspectrum romm: zxs pretty_name: Sinclair ZX Spectrum - src: sinclair/zxspectrum last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: Sinclair - ZX Spectrum +3 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: sinclair/zxspectrum last: '' mister: zx48 retropie: '' batocera: zxspectrum recalbox: zxspectrum retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: sinclair/zxspectrum last: '' mister: ZXNext retropie: '' batocera: zxspectrum recalbox: zxspectrum retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: zxnext romm: zx-spectrum-next pretty_name: '' - src: vectrex last: other/vectrex mister: VECTREX retropie: '' batocera: vectrex recalbox: vectrex retroarch: GCE - Vectrex ops2l: '' ps3netsrv: '' fspd: '' emuelec: vectrex smdb: Vectrex SMDB.txt freestation: '' analoguepocket: vectrex emudeck: vectrex igdb: vectrex replayfpgaarcade: '' retrodeck: vectrex romm: vectrex pretty_name: Vectrex - src: snk/neogeo last: '' mister: NEOGEO retropie: '' batocera: neogeo recalbox: neogeo retroarch: SNK - Neo Geo ops2l: '' ps3netsrv: '' fspd: '' emuelec: neogeo smdb: MiSTer Neo Geo Add-On.txt freestation: neogeo analoguepocket: ng emudeck: neogeo igdb: neogeoaes replayfpgaarcade: '' retrodeck: neogeo romm: neogeoaes pretty_name: SNK NEO-GEO - src: snk/neogeox last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: neo-geo-x pretty_name: SNK NEO-GEO X - src: snk/neogeopocket last: '' mister: NeoGeoPocket retropie: '' batocera: ngp recalbox: ngp retroarch: SNK - Neo Geo Pocket ops2l: '' ps3netsrv: '' fspd: '' emuelec: ngp smdb: NGPC RetroHQ SMDB.txt freestation: '' analoguepocket: jtngp emudeck: ngp igdb: neo-geo-pocket replayfpgaarcade: '' retrodeck: ngp romm: neo-geo-pocket pretty_name: SNK NEO-GEO Pocket - src: snk/neogeopocketcolor last: '' mister: '' retropie: '' batocera: ngpc recalbox: ngpc retroarch: SNK - Neo Geo Pocket Color ops2l: '' ps3netsrv: '' fspd: '' emuelec: ngpc smdb: NGPC RetroHQ SMDB.txt freestation: '' analoguepocket: jtngpc emudeck: ngpc igdb: neo-geo-pocket-color replayfpgaarcade: '' retrodeck: ngpc romm: neo-geo-pocket-color pretty_name: SNK NEO-GEO Pocket Color - src: snk/neogeocd last: '' mister: NeoGeo-CD retropie: '' batocera: neogeocd recalbox: neogeocd retroarch: SNK - Neo Geo CD ops2l: '' ps3netsrv: '' fspd: '' emuelec: neocd smdb: '' freestation: neocd analoguepocket: '' emudeck: neogeocd igdb: neo-geo-cd replayfpgaarcade: '' retrodeck: neogeocd romm: neo-geo-cd pretty_name: SNK NEO-GEO CD - src: sony/playstation1 last: '' mister: PSX retropie: '' batocera: psx recalbox: psx retroarch: Sony - PlayStation ops2l: '' ps3netsrv: '' fspd: '' emuelec: psx smdb: PlayStation Redump Supplement.txt freestation: ps1 analoguepocket: '' emudeck: '' igdb: ps replayfpgaarcade: '' retrodeck: psx romm: psx pretty_name: Sony PlayStation - src: sony/playstation1/iso last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: PSXISO fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation (ISO) - src: sony/playstation1/vcd last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: POPS ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation (VCD) - src: sony/playstation2 last: '' mister: '' retropie: '' batocera: ps2 recalbox: ps2 retroarch: Sony - PlayStation 2 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: ps2 analoguepocket: '' emudeck: ps2 igdb: ps2 replayfpgaarcade: '' retrodeck: ps2 romm: ps2 pretty_name: Sony PlayStation 2 - src: sony/playstation2/cd last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: CD ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation 2 (CD) - src: sony/playstation2/dvd last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: DVD ps3netsrv: PS2ISO fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation 2 (DVD) - src: sony/playstation3 last: '' mister: '' retropie: '' batocera: ps3 recalbox: '' retroarch: Sony - PlayStation 3 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: ps3 analoguepocket: '' emudeck: ps3 igdb: ps3 replayfpgaarcade: '' retrodeck: ps3 romm: ps3 pretty_name: Sony PlayStation 3 - src: sony/playstation3/games last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: GAMES fspd: '' emuelec: '' smdb: '' freestation: ps3 analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation 3 (Games) - src: sony/playstation3/iso last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: PS3ISO fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation 3 (ISO) - src: sony/playstation3/psn last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: Sony - PlayStation 3 (PSN) ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation 3 (PSN) - src: sony/playstation4 last: '' mister: '' retropie: '' batocera: ps4 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: ps4 igdb: ps4--1 replayfpgaarcade: '' retrodeck: ps4 romm: ps4 pretty_name: Sony PlayStation 4 - src: sony/playstation4/pkg last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation 4 (PKG) - src: sony/playstationportable last: '' mister: '' retropie: '' batocera: psp recalbox: psp retroarch: Sony - PlayStation Portable ops2l: '' ps3netsrv: '' fspd: '' emuelec: psp smdb: '' freestation: '' analoguepocket: '' emudeck: psp igdb: psp replayfpgaarcade: '' retrodeck: psp romm: psp pretty_name: Sony PlayStation Portable - src: sony/playstationportable/iso last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: PSPISO fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation Portable (ISO) - src: sony/playstationportable/minis last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: pspminis smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: psp-minis pretty_name: Sony PlayStation Portable (Minis) - src: sony/playstationportable/psn last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: Sony - PlayStation Portable (PSN) ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sony PlayStation Portable (PSN) - src: sony/playstationvita last: '' mister: '' retropie: '' batocera: psvita recalbox: '' retroarch: Sony - PlayStation Vita ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: psvita igdb: psvita replayfpgaarcade: '' retrodeck: psvita romm: psvita pretty_name: Sony PlayStation Vita - src: sony/pocketstation last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: pocketstation replayfpgaarcade: '' retrodeck: '' romm: pocketstation pretty_name: Sony PocketStation - src: sony/smc777 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: smc-777 pretty_name: Sony SMC-777 - src: sord/m5 last: other/sord_m5 mister: Sord M5 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sord-m5 pretty_name: Sord M5 - src: spectravideo/sv328 last: other/spectravideo_sv328 mister: SVI328 retropie: '' batocera: spectravideo recalbox: spectravideo retroarch: Spectravideo - SVI-318 - SVI-328 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: spectravideo igdb: '' replayfpgaarcade: '' retrodeck: spectravideo romm: spectravideo pretty_name: SpectraVideo SV328 - src: tandy/vis last: '' mister: '' retropie: '' batocera: vis recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: tandy-vis pretty_name: Tandy VIS - src: tandy/trs80 last: '' mister: TRS-80 retropie: '' batocera: trs80 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: trs-80 igdb: trs-80 replayfpgaarcade: '' retrodeck: trs-80 romm: trs-80 pretty_name: Tandy TRS-80 - src: tandy/trs80colorcomputer1 last: '' mister: '' retropie: '' batocera: coco recalbox: trs80coco retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: coco igdb: trs-80-color-computer replayfpgaarcade: '' retrodeck: coco romm: trs-80-color-computer pretty_name: Tandy Color Computer 1 - src: tandy/trs80colorcomputer2 last: '' mister: CoCo2 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Tandy Color Computer 2 - src: tandy/trs80colorcomputer3 last: '' mister: COCO3 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Tandy Color Computer 3 - src: tandy/trs80mc10 last: '' mister: AliceMC10 retropie: '' batocera: mc10 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: trs-80-mc-10 pretty_name: Tandy TRS-80 MC10 - src: tandy/trs80model100 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: trs-80-model-100 pretty_name: Tandy TRS-80 Model 100 - src: tandy/1000 last: '' mister: Tandy1000 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Tandy 1000 - src: tapwave/zodiac last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: zod replayfpgaarcade: '' retrodeck: '' romm: zodiac pretty_name: Tapwave Zodiac - src: tatung/einstein last: other/tatung_einstein mister: TatungEinstein retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: tatung-einstein replayfpgaarcade: '' retrodeck: '' romm: tatung-einstein pretty_name: Tatung Einstein - src: telstar/ay-3-8500 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ay-3-8500 replayfpgaarcade: '' retrodeck: '' romm: ay-3-8500 pretty_name: Telstar AY-3-8500 - src: telstar/ay-3-8603 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ay-3-8603 replayfpgaarcade: '' retrodeck: '' romm: ay-3-8603 pretty_name: Telstar AY-3-8603 - src: telstar/ay-3-8605 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ay-3-8605 replayfpgaarcade: '' retrodeck: '' romm: ay-3-8605 pretty_name: Telstar AY-3-8605 - src: telstar/ay-3-8606 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ay-3-8606 replayfpgaarcade: '' retrodeck: '' romm: ay-3-8606 pretty_name: Telstar AY-3-8606 - src: telstar/ay-3-8607 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ay-3-8607 replayfpgaarcade: '' retrodeck: '' romm: ay-3-8607 pretty_name: Telstar AY-3-8607 - src: telstar/ay-3-8610 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ay-3-8610 replayfpgaarcade: '' retrodeck: '' romm: ay-3-8610 pretty_name: Telstar AY-3-8610 - src: telstar/ay-3-8710 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ay-3-8710 replayfpgaarcade: '' retrodeck: '' romm: ay-3-8710 pretty_name: Telstar AY-3-8710 - src: telstar/ay-3-8760 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ay-3-8760 replayfpgaarcade: '' retrodeck: '' romm: ay-3-8760 pretty_name: Telstar AY-3-8760 - src: tesla/ondraspo186 last: other/tesla_ondraspo186 mister: Ondra_SPO186 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Tesla Ondraspo18 - src: tesla/pmd85 last: other/tesla_pmd85 mister: PMD85 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Tesla PMD85 - src: texas_instruments/ti82 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: ti-82 pretty_name: Texas Instruments TI-82 - src: texas_instruments/ti83 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: ti-83 pretty_name: Texas Instruments TI-83 - src: texas_instruments/ti99 last: '' mister: '' retropie: '' batocera: ti99 recalbox: ti994a retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: ti99 igdb: ti-99 replayfpgaarcade: '' retrodeck: ti99 romm: ti-99 pretty_name: Texas Instruments TI-99 - src: texas_instruments/ti994a last: '' mister: TI-99_4A retropie: '' batocera: '' recalbox: ti994a retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: ti-994a pretty_name: Texas Instruments TI-99/4A - src: thomson/thomson last: '' mister: '' retropie: '' batocera: thomson recalbox: thomson retroarch: Thomson - MOTO ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: moto igdb: '' replayfpgaarcade: '' retrodeck: moto romm: thomson-to pretty_name: Thomson - src: thomson/to8 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: to8 igdb: '' replayfpgaarcade: '' retrodeck: to8 romm: '' pretty_name: Thomson TO8 - src: thomson/mo5 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: thomson-mo5 replayfpgaarcade: '' retrodeck: '' romm: thomson-mo5 pretty_name: Thomson MO5 - src: tiger/gamecom last: gamecom mister: '' retropie: '' batocera: gamecom recalbox: '' retroarch: Tiger - Game.com ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: gamecom igdb: game-dot-com replayfpgaarcade: '' retrodeck: gamecom romm: game-dot-com pretty_name: Tiger Game.com - src: tiger/r-zone last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: r-zone replayfpgaarcade: '' retrodeck: '' romm: r-zone pretty_name: Tiger R-Zone - src: timetop/gameking last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: game_king emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Timetop GameKing - src: tomytronic/scramble last: '' mister: TomyScramble retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: TomyTronic Scramble - src: tomytronic/tutor last: '' mister: TomyTutor retropie: '' batocera: tutor recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: tomy-tutor-slash-pyuta-slash-grandstand-tutor replayfpgaarcade: '' retrodeck: '' romm: tomy-tutor pretty_name: TomyTronic Tutor - src: tsukuda/othellomultivision last: '' mister: '' retropie: '' batocera: multivision recalbox: multivision retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: multivision igdb: '' replayfpgaarcade: '' retrodeck: multivision romm: multivision pretty_name: Tsukuda Othello Multivision - src: umtech/videobrain last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: videobrain emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: videobrain pretty_name: Umtech VideoBrain - src: rca/cosmac last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: fred-cosmac pretty_name: COSMAC - src: rca/cosmacelf last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: COSMAC Elf - src: rca/cosmacvip last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: COSMAC VIP - src: researchmachines/380z last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: research-machines-380z pretty_name: Research Machines 380Z - src: rca/studioii last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: RCA - Studio II ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: studio2 emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: rca-studio-ii pretty_name: RCA Studio II - src: vmlabs/nuon last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: nuon replayfpgaarcade: '' retrodeck: '' romm: nuon pretty_name: VMLabs Nuon - src: vector/06c last: other/vector06c mister: VECTOR06 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: 06c pretty_name: Vector 06c - src: videos/bdiso last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: BDISO fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Videos BD - src: videos/dvdiso last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: DVDISO fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Videos DVD - src: videotechnology/creativision last: vtech/creativision mister: CreatiVision retropie: '' batocera: crvision recalbox: '' retroarch: VTech - CreatiVision ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: creativision emudeck: crvision igdb: '' replayfpgaarcade: '' retrodeck: crvision romm: creativision pretty_name: VTech CreatiVision - src: videotechnology/vtechlaser200 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: laser200 pretty_name: VTech Laser 200 - src: videotechnology/vtechlaser last: other/videotechnology_vtechlaser mister: Laser retropie: '' batocera: laser310 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: VTech Laser - src: videotechnology/vsmile last: '' mister: '' retropie: '' batocera: vsmile recalbox: '' retroarch: VTech - V.Smile ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: vsmile igdb: vsmile replayfpgaarcade: '' retrodeck: vsmile romm: vsmile pretty_name: VTech vSmile - src: videotechnology/socrates last: '' mister: '' retropie: '' batocera: socrates recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: socrates pretty_name: VTech Socrates - src: videotechnology/vflash last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: vflash pretty_name: VTech V.Flash - src: videoton/tvcomputer last: '' mister: '' retropie: '' batocera: tvc recalbox: '' retroarch: Videoton - TV-Computer ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Videoton TV-Computer - src: watara/supervision last: '' mister: SuperVision retropie: '' batocera: supervision recalbox: supervision retroarch: Watara - Supervision ops2l: '' ps3netsrv: '' fspd: '' emuelec: supervision smdb: Watara Supervision SMDB.txt freestation: '' analoguepocket: supervision emudeck: supervision igdb: watara-slash-quickshot-supervision replayfpgaarcade: '' retrodeck: supervision romm: supervision pretty_name: Watara Supervision - src: bandai/supervision8000 last: '' mister: SuperVision8000 retropie: '' batocera: sv8000 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: super-vision-8000 pretty_name: Super Vision 800 - src: pebble last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pebble pretty_name: Pebble Watch - src: pinball/fpinball last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: fpinball romm: '' pretty_name: Future Pinball - src: pinball/vpinball last: '' mister: '' retropie: '' batocera: vpinball recalbox: vpinball retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: vpinball romm: pinball pretty_name: Virtual Pinball - src: plex/arcade last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: plex-arcade pretty_name: Plex Arcade - src: pokitto last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pokitto pretty_name: pokitto - src: polymorphicsystems/poly-88 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: poly-88 pretty_name: Poly 88 - src: polymorphicsystems/system-8813 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Polymega - src: playmaji/polymega last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: polymega replayfpgaarcade: '' retrodeck: '' romm: polymega pretty_name: Polymega - src: capcom/cps1 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: cps1 smdb: '' freestation: '' analoguepocket: '' emudeck: cps1 igdb: '' replayfpgaarcade: '' retrodeck: cps1 romm: cps1 pretty_name: Capcom CPS-1 - src: capcom/cps2 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: cps2 smdb: '' freestation: '' analoguepocket: '' emudeck: cps2 igdb: '' replayfpgaarcade: '' retrodeck: cps2 romm: cps2 pretty_name: Capcom CPS-2 - src: capcom/cps3 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: cps3 smdb: '' freestation: '' analoguepocket: '' emudeck: cps3 igdb: '' replayfpgaarcade: '' retrodeck: cps3 romm: cps3 pretty_name: Capcom CPS-3 - src: symbian/symbianos last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: symbian igdb: '' replayfpgaarcade: '' retrodeck: symbian romm: symbian pretty_name: SymbianOS - src: palm/palmos last: '' mister: '' retropie: '' batocera: '' recalbox: palm retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: palm igdb: palm-os replayfpgaarcade: '' retrodeck: palm romm: palm-os pretty_name: Palm OS - src: zeebo/zeebo last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: zeebo replayfpgaarcade: '' retrodeck: '' romm: zeebo pretty_name: Zeebo - src: zpa/iq151 last: '' mister: IQ151 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: IQ151 - src: dist/image last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: dist/iso last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: dist/project last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: engine/cannonball last: '' mister: '' retropie: '' batocera: cannonball recalbox: outrun retroarch: Cannonball ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Cannonball - src: engine/devilutionx last: '' mister: '' retropie: '' batocera: devilutionx recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: DevolutionX - src: engine/dxx last: '' mister: '' retropie: '' batocera: dxx-rebirth recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: DXX - src: engine/easyrpg last: '' mister: '' retropie: '' batocera: easyrpg recalbox: easyrpg retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: easyrpg smdb: '' freestation: '' analoguepocket: '' emudeck: easyrpg igdb: '' replayfpgaarcade: '' retrodeck: easyrpg romm: '' pretty_name: EasyRPG - src: engine/eduke last: '' mister: '' retropie: '' batocera: eduke32 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: EDuke - src: engine/etlegacy last: '' mister: '' retropie: '' batocera: etlegacy recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: ETLegacy - src: engine/fury last: '' mister: '' retropie: '' batocera: fury recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Fury - src: engine/ikemen last: '' mister: '' retropie: '' batocera: ikemen recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: ikemen smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: IKEMen - src: engine/mugen last: '' mister: '' retropie: '' batocera: mugen recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: mugen igdb: '' replayfpgaarcade: '' retrodeck: mugen romm: mugen pretty_name: Mugen - src: engine/openbor last: '' mister: '' retropie: '' batocera: openbor recalbox: openbor retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: openbor smdb: '' freestation: '' analoguepocket: '' emudeck: openbor igdb: '' replayfpgaarcade: '' retrodeck: openbor romm: openbor pretty_name: OpenBOR - src: engine/openlara last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: OpenLara - src: engine/puzzlescript last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: PuzzleScript ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Puzzle Script - src: engine/raze last: '' mister: '' retropie: '' batocera: raze recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Raze - src: engine/rpgmaker last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: RPG Maker ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: RPG Maker - src: engine/smbx last: '' mister: '' retropie: '' batocera: thextech recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: SMBX - src: engine/solarus last: '' mister: '' retropie: '' batocera: solarus recalbox: solarus retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: solarus smdb: '' freestation: '' analoguepocket: '' emudeck: solarus igdb: '' replayfpgaarcade: '' retrodeck: solarus romm: '' pretty_name: Solarus - src: engine/sonicretro last: '' mister: '' retropie: '' batocera: sonicretro recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Sonic Retro - src: engine/stratagus last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: stratagus igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Stratagus - src: engine/theforceengine last: '' mister: '' retropie: '' batocera: theforceengine recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Force Engine - src: engine/xash3d last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: XHash3D - src: idstuff/catacomb last: '' mister: '' retropie: '' batocera: catacomb recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: idstuff/doom last: '' mister: '' retropie: '' batocera: gzdoom recalbox: doom retroarch: DOOM ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: doom analoguepocket: '' emudeck: doom igdb: '' replayfpgaarcade: '' retrodeck: doom romm: '' pretty_name: DOOM - src: idstuff/doom3 last: '' mister: '' retropie: '' batocera: doom3 recalbox: doom3 retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: DOOM3 - src: idstuff/ecwolf last: '' mister: '' retropie: '' batocera: ecwolf recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: ecwolf smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: ECWolf - src: idstuff/prboom last: '' mister: '' retropie: '' batocera: prboom recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: prboom smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: PRBOOM - src: idstuff/quake last: '' mister: '' retropie: '' batocera: quake recalbox: quake retroarch: Quake ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: quake analoguepocket: '' emudeck: quake igdb: '' replayfpgaarcade: '' retrodeck: quake romm: '' pretty_name: Quake - src: idstuff/quake2 last: '' mister: '' retropie: '' batocera: quake2 recalbox: quake2 retroarch: Quake II ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Quake 2 - src: idstuff/quake3 last: '' mister: '' retropie: '' batocera: quake3 recalbox: quake3 retroarch: Quake III ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Quake 3 - src: idstuff/rtcw last: '' mister: '' retropie: '' batocera: rtcw recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: RTCW - src: idstuff/wolfenstein3d last: '' mister: '' retropie: '' batocera: '' recalbox: wolfenstein3d retroarch: Wolfenstein 3D ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Wolf3D - src: media/vgmplay last: '' mister: '' retropie: '' batocera: vgmplay recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: VGMPlay - src: media/karaoke last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: karaoke smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: media/mplayer last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: mplayer smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: media/imageviewer last: '' mister: '' retropie: '' batocera: imageviewer recalbox: imageviewer retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: imageviewer smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: media/library last: '' mister: '' retropie: '' batocera: library recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: media/screenshots last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: media/recordings last: '' mister: '' retropie: '' batocera: recordings recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: other/arduboy last: '' mister: Arduboy retropie: '' batocera: arduboy recalbox: arduboy retroarch: Arduboy Inc - Arduboy ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: arduboy emudeck: arduboy igdb: arduboy replayfpgaarcade: '' retrodeck: arduboy romm: arduboy pretty_name: Arduboy - src: other/chip8 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: CHIP-8 ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: CHIP-8 - src: other/flash last: '' mister: '' retropie: '' batocera: flash recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: flash igdb: '' replayfpgaarcade: '' retrodeck: flash romm: '' pretty_name: Flash - src: other/flashback last: '' mister: '' retropie: '' batocera: reminiscence recalbox: flashback retroarch: Flashback ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: other/galaksija last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: galaksija pretty_name: Galaksija - src: other/games last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: other/intel_x86 last: '' mister: AO486 retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: pc igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Intel X86 - src: other/pc-50x-family last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: pc-50x-family replayfpgaarcade: '' retrodeck: '' romm: pc-50x-family pretty_name: PC-50x-family - src: other/radio_86rk last: '' mister: APOGEE retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Radio 86RK - src: other/scummvm last: '' mister: '' retropie: '' batocera: scummvm recalbox: scummvm retroarch: ScummVM ops2l: '' ps3netsrv: '' fspd: '' emuelec: scummvm smdb: '' freestation: '' analoguepocket: '' emudeck: scummvm igdb: '' replayfpgaarcade: '' retrodeck: scummvm romm: scummvm pretty_name: ScummVM - src: other/searle_multicomp last: '' mister: MultiComp retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Searle Multicomp - src: other/specialist_mx last: '' mister: SPMX retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Specialist MX - src: other/zxevolution last: '' mister: TSConf retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: ZX Evolution - src: platform/chailove last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: ChaiLove ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: chailove igdb: '' replayfpgaarcade: '' retrodeck: chailove romm: '' pretty_name: ChailLove - src: platform/amazon/fire-tv last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: firetv replayfpgaarcade: '' retrodeck: '' romm: amazon-fire-tv pretty_name: '' - src: platform/android last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: android igdb: android replayfpgaarcade: '' retrodeck: android romm: android pretty_name: Android - src: platform/android/apps last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: androidapps romm: '' pretty_name: Android (Apps) - src: platform/android/games last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: androidgames romm: '' pretty_name: Android (Games) - src: platform/blackberry last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: blackberry replayfpgaarcade: '' retrodeck: '' romm: blackberry pretty_name: Blackberry - src: platform/browser last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: browser replayfpgaarcade: '' retrodeck: '' romm: browser pretty_name: '' - src: platform/cpm last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: cpm pretty_name: CP/M - src: platform/doja last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: doja pretty_name: DoJa - src: platform/dangeros last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: danger-os pretty_name: Danger OS - src: platform/evercade last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: evercade replayfpgaarcade: '' retrodeck: '' romm: evercade pretty_name: Evercade - src: platform/exen last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: exen pretty_name: ExEn - src: platform/gamemaker last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: gmloader smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Gamemaker - src: platform/glulx last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: glulx pretty_name: Glulx - src: platform/google/stadia last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: stadia replayfpgaarcade: '' retrodeck: '' romm: stadia pretty_name: Google Stadia - src: platform/handheld last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: Handheld Electronic Game ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: handheld replayfpgaarcade: '' retrodeck: '' romm: handheld-electronic-lcd pretty_name: Handheld - src: platform/ios last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ios replayfpgaarcade: '' retrodeck: '' romm: ios pretty_name: iOS - src: platform/java last: '' mister: '' retropie: '' batocera: j2me recalbox: '' retroarch: Mobile - J2ME ops2l: '' ps3netsrv: '' fspd: '' emuelec: freej2me smdb: '' freestation: '' analoguepocket: '' emudeck: j2me igdb: '' replayfpgaarcade: '' retrodeck: j2me romm: j2me pretty_name: Java - src: platform/kaios last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: kaios pretty_name: KaiOS - src: platform/lcdgames last: '' mister: '' retropie: '' batocera: lcdgames recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: lcdgames igdb: '' replayfpgaarcade: '' retrodeck: lcdgames romm: '' pretty_name: LCD Games - src: platform/legacy-computer last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: legacy-computer replayfpgaarcade: '' retrodeck: '' romm: legacy-computer pretty_name: '' - src: platform/linux last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: linux replayfpgaarcade: '' retrodeck: '' romm: linux pretty_name: '' - src: platform/maemo last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: maemo pretty_name: Maemo - src: platform/meego last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: meego pretty_name: MeeGo - src: platform/mobile last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: mobile replayfpgaarcade: '' retrodeck: '' romm: mobile pretty_name: '' - src: platform/mophun last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: mophun pretty_name: Mophun - src: platform/mre last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: mre pretty_name: MediaTek MRE - src: platform/onlive-game-system last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: onlive replayfpgaarcade: '' retrodeck: '' romm: onlive-game-system pretty_name: '' - src: platform/os2 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: os2 pretty_name: IBM OS/2 - src: platform/pc-booter last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pc-booter pretty_name: PC Booter - src: platform/plugnplay last: '' mister: '' retropie: '' batocera: tvgames recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: plug-and-play replayfpgaarcade: '' retrodeck: '' romm: plug-and-play pretty_name: '' - src: platform/pygame last: '' mister: '' retropie: '' batocera: pygame recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: PyGame - src: platform/steam last: '' mister: '' retropie: '' batocera: steam recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: platform/thepowdertoy last: '' mister: '' retropie: '' batocera: '' recalbox: thepowdertoy retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Powder Toy - src: platform/gvm last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: gvm pretty_name: GVM - src: platform/scmp last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: scmp pretty_name: SC/MP - src: platform/signetics2650 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: signetics-2650 pretty_name: Signetics 2650 - src: platform/skvm last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sk-vm pretty_name: SK-VM - src: platform/tads last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: tads pretty_name: TADS Interpreter - src: platform/zinc last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: zinc pretty_name: ZiNc Interpreter - src: platform/gnex last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: gnex pretty_name: GNEX - src: platform/hugo last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: hugo pretty_name: Hugo - src: ports last: '' mister: '' retropie: '' batocera: ports recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: ports smdb: '' freestation: '' analoguepocket: '' emudeck: ports igdb: '' replayfpgaarcade: '' retrodeck: ports romm: '' pretty_name: '' - src: ports/2048 last: '' mister: '' retropie: '' batocera: '' recalbox: '2048' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/abuse last: '' mister: '' retropie: '' batocera: abuse recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/bomberman last: '' mister: '' retropie: '' batocera: mrboom recalbox: mrboom retroarch: MrBoom ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/cave3rd last: '' mister: '' retropie: '' batocera: cave3rd recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/cavestory last: '' mister: '' retropie: '' batocera: cavestory recalbox: cavestory retroarch: Cave Story ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: cavestory igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/cdogs last: '' mister: '' retropie: '' batocera: cdogs recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/commanderkeen last: '' mister: '' retropie: '' batocera: cgenius recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/corsixth last: '' mister: '' retropie: '' batocera: corsixth recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/dinothawr last: '' mister: '' retropie: '' batocera: '' recalbox: dinothawr retroarch: Dinothawr ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/dungeoncrawlstonesoup last: '' mister: '' retropie: '' batocera: '' recalbox: dungeoncrawlstonesoup retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/fallout1 last: '' mister: '' retropie: '' batocera: fallout1-ce recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/fallout2 last: '' mister: '' retropie: '' batocera: fallout2-ce recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/flappybird last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: flappybird emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/hcl last: '' mister: '' retropie: '' batocera: hcl recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/hurrican last: '' mister: '' retropie: '' batocera: hurrican recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/jazzjackrabbit last: '' mister: '' retropie: '' batocera: openjazz recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/jazzjackrabbit2 last: '' mister: '' retropie: '' batocera: jazz2 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/jumpnbump last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: "Jump 'n Bump" ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/lutro last: '' mister: '' retropie: '' batocera: lutro recalbox: lutro retroarch: Lutro ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: lutro igdb: '' replayfpgaarcade: '' retrodeck: lutro romm: '' pretty_name: '' - src: ports/minecraft last: '' mister: '' retropie: '' batocera: '' recalbox: minecraft retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/pong last: '' mister: '' retropie: '' batocera: gong recalbox: gong retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: pong emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/princeofpersia last: '' mister: '' retropie: '' batocera: sdlpop recalbox: princeofpersia retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/rickdangerous last: '' mister: '' retropie: '' batocera: xrick recalbox: rickdangerous retroarch: Rick Dangerous ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/sonic3 last: '' mister: '' retropie: '' batocera: sonic3-air recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/sonicmania last: '' mister: '' retropie: '' batocera: sonic-mania recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/superbroswar last: '' mister: '' retropie: '' batocera: superbroswar recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/tombraider last: '' mister: '' retropie: '' batocera: traider1 recalbox: tombraider retroarch: Tomb Raider ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/tombraider2 last: '' mister: '' retropie: '' batocera: traider2 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/tyrian last: '' mister: '' retropie: '' batocera: tyrian recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/urquan-masters last: '' mister: '' retropie: '' batocera: uqm recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/zeldaclassic last: '' mister: '' retropie: '' batocera: zc210 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: tools/240ptestsuite last: '' mister: '' retropie: '' batocera: '' recalbox: 240ptestsuite retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: 240p Test Suite - src: tools/flatpak last: '' mister: '' retropie: '' batocera: flatpak recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: tools/moonlight last: '' mister: '' retropie: '' batocera: moonlight recalbox: moonlight retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: moonlight igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: tools/odcommander last: '' mister: '' retropie: '' batocera: odcommander recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: other/lightgun last: '' mister: '' retropie: '' batocera: namco2x6 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: technosys_research_labs/aamber-pegasus last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: pegasus pretty_name: 'Aamber Pegasus' - src: abc/80 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: abc-80 pretty_name: 'ABC 80' - src: 'worlds-of-wonder/action-max' last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: action-max pretty_name: WoW Action Max - src: matra-and-hachetter-ordinateur/alice last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: alice-3290 pretty_name: 'Alice 32/90' - src: ports/halflife last: '' mister: '' retropie: '' batocera: halflife recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: 'Half Life' - src: other/laseractive last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: laseractive replayfpgaarcade: '' retrodeck: '' romm: laseractive pretty_name: 'LaserActive' - src: other/blacknut last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: blacknut pretty_name: Blacknut - src: computer_power_and_light/compal80 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: compal-80 pretty_name: Compal 80 - src: compucolor/compucolor8001 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: compucolor-i pretty_name: Compucolor 8001 - src: compucolor/compucolorii last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: compucolor-ii pretty_name: Compucolor II - src: compucorp/100-series last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: compucorp-programmable-calculator pretty_name: Compucorp 100 Series Calculator - src: compucorp/200-series last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Compucorp 200 Series Calculator - src: compucorp/300-series last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Compucorp 300 Series Calculator - src: compucorp/400-series last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Compucorp 400 Series Calculator - src: cybervision/2001 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: cybervision pretty_name: CyberVision 2001 - src: grey_innovation/digiblast last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: digiblast replayfpgaarcade: '' retrodeck: '' romm: digiblast pretty_name: digiBlast - src: ecd/micromind last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: ecd-micromind pretty_name: ECD Micromind - src: bgr/excalibur64 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: excalibur-64 pretty_name: Excalibur 64 - src: exelvision/exl100 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: exelvision pretty_name: Exelvision EXL100 - src: zapitigames/gamewave last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: game-wave pretty_name: Game Wave - src: playjam/gamestick last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: gamestick pretty_name: GameStick - src: tigertelmatics/gizmondo last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: gizmondo replayfpgaarcade: '' retrodeck: '' romm: gizmondo pretty_name: Gizmondo - src: heathkit/h11 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: heathkit-h11 pretty_name: Heathkit H11 - src: heathkit/h8 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: heathzenith pretty_name: Heath/Zenith H8/H89 - src: hitachi/s1 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: hitachi-s1 pretty_name: Hitachi S1 - src: hp/hp-9800 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: hp-9800 pretty_name: HP 9800 - src: hp/hp3000 last: hp3000 mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: hp3000 replayfpgaarcade: '' retrodeck: '' romm: hp3000 pretty_name: HP 3000 - src: hp/hp2100 last: hp2100 mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: hp2100 replayfpgaarcade: '' retrodeck: '' romm: hp2100 pretty_name: HP 2100 - src: iircade last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: iircade pretty_name: iiRcade - src: imlac/pds1 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: imlac-pds1 pretty_name: Imlac PDS-1 - src: jolt last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: jolt pretty_name: Jolt - src: mos/kim1 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: kim-1 pretty_name: KIM-1 - src: matsushita/jr last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: matsushitapanasonic-jr pretty_name: Matsushita/Panasonic JR - src: memotech/mtx last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: memotech-mtx pretty_name: Memotech MTX - src: memotech/mtx512 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: mtx512 pretty_name: Memotech MTX512 - src: meraelzab/meritum last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: meritum pretty_name: Mera-Elzab Meritum - src: appliedtechnology/microbee last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: microbee pretty_name: Microbee - src: tangeringcomputersystems/microtan65 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: microtan-65 pretty_name: Microtan 65 - src: nascom/1 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: nascom pretty_name: Nascom 1 - src: grundybusinesssystem/newbrain last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: newbrain pretty_name: NewBrain - src: northstarcomputers/northstar last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: northstar pretty_name: NorthStar - src: noval/760 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: noval-760 pretty_name: Noval 760 - src: ohioscientific last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: ohio-scientific pretty_name: Ohio Scientific - src: namco/system22 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: system-32 pretty_name: Namco System 22 - src: soundic/sd2x0 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sd-200270290 pretty_name: Soundic Soundicvision SD-200/270/290 - src: taito/type-x last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: type-x pretty_name: Taito Type X - src: taito/x55 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: taito-x-55 pretty_name: Taito X-55 - src: tektronix/4050 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: tektronix-4050 pretty_name: Tektronix 4050 - src: nvphilipsgloeilampenfabrieken/telespieles2201 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: tele-spiel pretty_name: Tele-Spiel ES-2201 - src: tikidata/tiki100 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: tiki-100 pretty_name: Tiki-100 - src: timex/sinclair2068 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: timex-sinclair-2068 pretty_name: Timex Sinclair 2068 - src: fuze/tomahawkf1 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: tomahawk-f1 pretty_name: Tomahawk F1 - src: computerdatasystems/versatile last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: versatile pretty_name: Versatile - src: wang/2200 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: wang2200 pretty_name: Wang 2200 - src: ssd/xavixport last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: xavixport pretty_name: XaviXPORT - src: xerox/alto last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: xerox-alto pretty_name: Xerox Alto - src: transam/triton last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: triton pretty_name: Transam Triton - src: samsung/tizen last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: tizen pretty_name: Samsung Tizen - src: samsung/bada last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: bada pretty_name: Samsung Bada - src: idealcomputer last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: ideal-computer pretty_name: Ideal-Computer - src: platform/brew last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: brew pretty_name: BREW - src: brightthings/bubble last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: bubble pretty_name: Bright Things Bubble - src: micronique/hector1 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Hector 1 - src: micronique/hector2hr last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Hector 2 HR - src: micronique/hector2hrplus last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Hector 2HR+ - src: micronique/hectorhrx last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: hrx pretty_name: Hector HRX - src: micronique/hectormx last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Hector MX - src: superfunfun/sureshothd last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sure-shot-hd pretty_name: Sure Shot HD - src: gakken/compactvisiontvboy last: '' mister: '' retropie: '' batocera: ctvboy recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: Compact Vision TV Boy system_unsupported: - src: dvd-player last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: dvd-player replayfpgaarcade: '' retrodeck: '' romm: dvd-player pretty_name: '' - src: hd-dvd-player last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: hd-dvd-player pretty_name: '' - src: blu-ray-player last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: blu-ray-player replayfpgaarcade: '' retrodeck: '' romm: blu-ray-player pretty_name: '' - src: meta-quest-2 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: meta-quest-2 replayfpgaarcade: '' retrodeck: '' romm: meta-quest-2 pretty_name: '' - src: meta-quest-3 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: meta-quest-3 replayfpgaarcade: '' retrodeck: '' romm: meta-quest-3 pretty_name: '' - src: oculus-go last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: oculus-go replayfpgaarcade: '' retrodeck: '' romm: oculus-go pretty_name: '' - src: oculus-quest last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: oculus-quest replayfpgaarcade: '' retrodeck: '' romm: oculus-quest pretty_name: '' - src: oculus-rift last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: oculus-rift replayfpgaarcade: '' retrodeck: '' romm: oculus-rift pretty_name: '' - src: sony/playstation-vr last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: psvr replayfpgaarcade: '' retrodeck: '' romm: psvr pretty_name: '' - src: sony/psvr2 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: psvr2 replayfpgaarcade: '' retrodeck: '' romm: psvr2 pretty_name: '' - src: gear-vr last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: gear-vr replayfpgaarcade: '' retrodeck: '' romm: gear-vr pretty_name: '' - src: airconsole last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: airconsole replayfpgaarcade: '' retrodeck: '' romm: airconsole pretty_name: '' - src: donner30 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: donner30 replayfpgaarcade: '' retrodeck: '' romm: donner30 pretty_name: '' - src: ooparts last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: ooparts replayfpgaarcade: '' retrodeck: '' romm: ooparts pretty_name: '' - src: sol-20 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: sol-20 replayfpgaarcade: '' retrodeck: '' romm: sol-20 pretty_name: '' - src: plato last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: plato--1 replayfpgaarcade: '' retrodeck: '' romm: plato pretty_name: '' - src: sdssigma7 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: sdssigma7 replayfpgaarcade: '' retrodeck: '' romm: sdssigma7 pretty_name: '' - src: edsac last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: edsac--1 replayfpgaarcade: '' retrodeck: '' romm: edsac pretty_name: '' - src: sri/500 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: sri-5001000 pretty_name: SRI-500/1000 - src: swtpc/6800 last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: swtpc-6800 pretty_name: SWTPC 6800 - src: timeshare last: '' mister: '' retropie: '' batocera: '' recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: call-a-computer replayfpgaarcade: '' retrodeck: '' romm: call-a-computer pretty_name: '' - src: pcv2 last: '' mister: '' retropie: '' batocera: '' recalbox: pcv2 retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: startrekvoyager last: '' mister: '' retropie: '' batocera: '' recalbox: startrekvoyager retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: vvvvvv last: '' mister: '' retropie: '' batocera: '' recalbox: vvvvvv retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: 8bit-productions/commanderx16 last: '' mister: '' retropie: '' batocera: commanderx16 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: commander-x16 pretty_name: 'Commander X16' - src: ports/rott last: '' mister: '' retropie: '' batocera: rott recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/bstone last: '' mister: '' retropie: '' batocera: bstone recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/jkdf2 last: '' mister: '' retropie: '' batocera: jkdf2 recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/jknight last: '' mister: '' retropie: '' batocera: jknight recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/mohaa last: '' mister: '' retropie: '' batocera: mohaa recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/bennugd last: '' mister: '' retropie: '' batocera: bennugd recalbox: '' retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/julius last: '' mister: '' retropie: '' batocera: '' recalbox: caesar3 retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: '' - src: ports/corsixth last: '' mister: '' retropie: '' batocera: '' recalbox: themehospital retroarch: '' ops2l: '' ps3netsrv: '' fspd: '' emuelec: '' smdb: '' freestation: '' analoguepocket: '' emudeck: '' igdb: '' replayfpgaarcade: '' retrodeck: '' romm: '' pretty_name: 'Theme Hospital' ================================================ FILE: ansible/retronas_update_user.yml ================================================ --- - hosts: localhost gather_facts: false tasks: - name: "Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "update user" ansible.builtin.user: user: "{{ retronas_user }}" groups: "disk" append: true ================================================ FILE: ansible/retronas_vars.yml.default ================================================ retronas_path: "/data/retronas" retronas_user: "retronas" retronas_group: "retronas" retronas_root: "/opt/retronas" retronas_net_retro_interface: "eth0" retronas_net_retro_ip: "10.99.1.1" retronas_net_retro_subnet: "23" retronas_net_retro_dhcprange: "10.99.1.150,10.99.1.200,6h" retronas_net_retro_router: "10.99.1.1" retronas_net_retro_ntp: "10.99.1.1" retronas_net_retro_dns: "10.99.1.1" retronas_net_modern_interface: "wlan0" retronas_etherdfs_interface: "eth0" retronas_net_upstream_dns1: "8.8.8.8" retronas_net_upstream_dns2: "8.8.4.4" retronas_net_wifi_interface: "wlan0" retronas_net_wifi_ssid: "" retronas_net_wifi_channel: 6 retronas_net_wifi_hwmode: bg retronas_net_wifi_countrycode: AU retronas_net_wifi_ip: "10.99.2.1" retronas_net_wifi_subnet: "23" retronas_net_wifi_dhcprange: "10.99.2.150,10.99.2.200,6h" retronas_net_wifi_router: "10.99.2.1" retronas_net_wifi_ntp: "10.99.2.1" retronas_net_wifi_dns: "10.99.1.1" retronas_net_3dsqr_interface: "eth0" ================================================ FILE: ansible/roles/retronas.role.apt-backports/tasks/main.yaml ================================================ --- - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - install prerequisite packages" ansible.builtin.package: name: "{{ packages }}" state: latest - name: "{{ my_name }} - discover signing key" ansible.builtin.shell: cmd: curl -skL http://ftp.debian.org/debian/pool/main/d/debian-archive-keyring/ | grep -oP "href=\"debian-archive-keyring.+.deb\">" | sed -r 's/href=\"(debian-archive.+all.deb)\">/\1/' | tail -n1 register: debian_signing_key when: ansible_distribution == "Debian" - name: "{{ my_name }} - download Debian signing keys" ansible.builtin.shell: chdir: "/tmp" cmd: "aria2c --allow-overwrite=true http://ftp.debian.org/debian/pool/main/d/debian-archive-keyring/{{ debian_signing_key.stdout }} https://mirror.aarnet.edu.au/pub/debian/pool/main/d/debian-archive-keyring/{{ debian_signing_key.stdout }}" when: ansible_distribution == "Debian" and debian_signing_key is defined - name: "{{ my_name }} - install Debian signing keys" ansible.builtin.shell: chdir: "/tmp" cmd: "dpkg -i {{ debian_signing_key.stdout }}" when: ansible_distribution == "Debian" - name: "{{ my_name }} - Configure APT repo" ansible.builtin.apt_repository: repo: deb http://deb.debian.org/debian {{ ansible_distribution_release }}-backports main contrib non-free state: present filename: debian-backports update_cache: false when: ansible_distribution == "Debian" - name: "{{ my_name }} - Configure APT repo for Ubuntu x86_64" ansible.builtin.apt_repository: repo: deb http://archive.ubuntu.com/ubuntu/ {{ ansible_distribution_release }}-backports main restricted universe multiverse state: present filename: "{{ ansible_distribution_release }}-backports" update_cache: false when: ansible_distribution == "Ubuntu" and ansible_architecture == "x86_64" - name: "{{ my_name }} - Configure APT repo for Ubuntu non x86_64 (ports)" ansible.builtin.apt_repository: repo: deb http://ports.ubuntu.com/ {{ ansible_distribution_release }}-backports main restricted universe multiverse state: present filename: "{{ ansible_distribution_release }}-backports" update_cache: false when: ansible_distribution == "Ubuntu" and ansible_architecture != "x86_64" - name: "{{ my_name }} - Force update repo cache" ansible.builtin.shell: cmd: "/usr/bin/apt update || exit 0" when: ansible_distribution == "Ubuntu" or ansible_distribution == "Debian" ================================================ FILE: ansible/roles/retronas.role.apt-backports/vars/main.yaml ================================================ --- my_name: "Apt Backports" my_file: "install_apt-backports" packages: - gnupg - aria2 - curl ================================================ FILE: ansible/roles/retronas.role.cache/tasks/main.yaml ================================================ - name: "{{ my_name }} - Gather required facts" ansible.builtin.setup: gather_subset: - date_time - name: "{{ my_name }} - Check Ansible cache age" ansible.builtin.stat: path: "{{ retronas_cache_file }}" register: ansible_cache_age - name: "{{ my_name }} - Check retronas_systems age" ansible.builtin.stat: path: "{{ retronas_systems_file }}" register: retronas_system_age - name: "{{ my_name }} - Remove ansible cache if older than retronas_systems" ansible.builtin.file: path: "{{ retronas_cache_file }}" state: absent become: yes when: - ansible_cache_age.stat.exists is true - ansible_cache_age.stat.mtime < retronas_system_age.stat.mtime ================================================ FILE: ansible/roles/retronas.role.cache/vars/main.yaml ================================================ retronas_cache_file: "{{ retronas_root }}/cache/s1_localhost" retronas_systems_file: "{{ retronas_root }}/ansible/retronas_systems.yml" ================================================ FILE: ansible/roles/retronas.role.cockpit/handlers/main.yaml ================================================ - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ my_service }}" state: restarted daemon_reload: yes ================================================ FILE: ansible/roles/retronas.role.cockpit/tasks/main.yaml ================================================ - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Install from backports repo" ansible.builtin.apt: name: "{{ packages }}" state: latest default_release: "{{ ansible_distribution_release }}-backports" notify: "{{ my_name }} - Restart service" when: (ansible_distribution == 'Debian' and ansible_distribution_major_version | int < 13) or ansible_distribution == 'Ubuntu' - name: "{{ my_name }} - Install from repo" ansible.builtin.apt: name: "{{ packages }}" state: latest notify: "{{ my_name }} - Restart service" when: ansible_distribution == 'Debian' and ansible_distribution_major_version | int >= 13 - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ my_service }}" state: started enabled: true daemon_reload: true # # FIREWALL # - name: "{{ my_name }} - checking firewall rule" ansible.builtin.stat: path: /etc/firewalld/services register: firewalld_services - name: "{{ my_name }} - enable firewall rule" ansible.posix.firewalld: zone: "{{ item.zone | default('retro') }}" service: "{{ item.service | default('cockpit') }}" permanent: true state: enabled immediate: true with_items: "{{ firewalld_rules }}" when: firewalld_services.stat.exists ================================================ FILE: ansible/roles/retronas.role.cockpit/vars/main.yaml ================================================ my_name: "Cockpit" my_file: "install_cockpit" my_service: "cockpit" packages: - cockpit - cockpit-storaged - cockpit-networkmanager firewalld_rules: - { zone: "retro" } - { zone: "modern" } ================================================ FILE: ansible/roles/retronas.role.cockpit-packages/tasks/main.yaml ================================================ - name: "{{ my_name }} - install prerequisite packages" ansible.builtin.package: name: "{{ package_tools }}" state: latest - name: "{{ my_name }} - install cockpit packages inplace" ansible.builtin.copy: src: "templates/{{ my_file }}/{{ item }}.j2" dest: "{{ retronas_root }}/scripts/{{ item }}" owner: root group: root mode: 0750 with_items: "{{ package_data }}" - name: "{{ my_name }} - get packages" ansible.builtin.command: cmd: "{{ retronas_root }}/scripts/{{ my_name }}.sh" ================================================ FILE: ansible/roles/retronas.role.cockpit-packages/templates/install_cockpit-packages/cockpit-packages.sh.j2 ================================================ #!/bin/bash # # Clone down additional Cockpit Packages # set -u RNTMP=/tmp/rn_cpack COCKPIT=/usr/share/cockpit # clean up old stuff [ -d "${RNTMP}" ] && rm -Rf "${RNTMP}/" # make out temp dir [ ! -d ${RNTMP} ] && mkdir ${RNTMP} function get_github { local ACCOUNT=$1 local REPO=$2 local FOLDER=$3 if [ ! -d "${RNTMP}/${FOLDER}" ] then cd ${RNTMP} git clone https://github.com/${ACCOUNT}/${REPO}.git $FOLDER else cd ${RNTMP}/${FOLDER} git pull fi cd ${RNTMP}/${FOLDER} RELEASE=$(git tag | tail -n1) [ ! -z "${RELEASE}" ] && git checkout $RELEASE } function install_package { local FOLDER=$1 [ ! -d "${RNTMP}/${FOLDER}" ] && echo "Can't find my temp dir man, boooo!" && exit 1 cp -R "${RNTMP}/${FOLDER}" "${COCKPIT}/" } ### there'll be a better way to approach this function get_45drives { PACKAGES=( "cockpit-navigator|navigator" #"cockpit-zfs-manager|zfs" #"cockpit-file-sharing|file-sharing" ) for ITEM in ${PACKAGES[@]} do PACKAGE=$(echo ${ITEM} | cut -d '|' -f1) FOLDER=$(echo ${ITEM} | cut -d'|' -f2) get_github 45Drives $PACKAGE $FOLDER install_package $FOLDER/$FOLDER done } ### get sensors function get_sensors { PACKAGE=cockpit-sensors-plugin FOLDER=$(echo ${PACKAGE} | sed -r 's/^cockpit-(.+)-plugin/\1/' ) get_github JamesGKent $PACKAGE $FOLDER install_package $FOLDER } get_45drives get_sensors # clean up [ -d "${RNTMP}" ] && rm -Rf "${RNTMP}/" ================================================ FILE: ansible/roles/retronas.role.cockpit-packages/vars/main.yaml ================================================ my_name: "cockpit-packages" my_file: "install_cockpit-packages" package_tools: - lm-sensors package_data: - cockpit-packages.sh ================================================ FILE: ansible/roles/retronas.role.createdirs/tasks/main.yaml ================================================ --- - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - stat our path" ansible.builtin.stat: path: "{{ retronas_path }}" register: rn_path - name: "{{ my_name }} - create our base" ansible.builtin.shell: cmd: "mkdir -p {{ rn_path }}" changed_when: false when: rn_path is defined and rn_path.stat.exists is false - name: "{{ my_name }} - perms" ansible.builtin.shell: cmd: "chown -R {{ retronas_user }}:{{ retronas_group }} {{ rn_path }}" changed_when: false when: rn_path is defined and rn_path.stat.exists is false - name: "{{ my_name }} - stat top level paths" ansible.builtin.stat: path: "{{ retronas_path }}/{{ item }}" loop: [ "roms", "bios", "saves", "savestates" ] register: tl_paths - name: "{{ my_name }} - create our missing paths" ansible.builtin.file: path: "{{ retronas_path }}/{{ item.item }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory mode: '0755' loop: "{{ tl_paths.results }}" when: tl_paths is defined and item.stat.exists is false - name: "{{ my_name }} - build layout list (set fact)" ansible.builtin.set_fact: path_list: "{{ path_list|default([]) + [ retronas_path + '/' + pl.1.name|lower + '/' + pl.0.src if pl.1.systems is true else '' ] }}" loop: "{{ system_map|product(top_level_paths)|list }}" loop_control: loop_var: pl label: "{{ pl.0.src }}" when: pl.1.enabled is true - name: "{{ my_name }} - build layout" ansible.builtin.shell: cmd: mkdir -p {{ path_list|flatten|join(' ') }} become: true become_user: "{{ retronas_user }}" when: path_list is defined changed_when: false - name: "{{ my_name }} - build systems directory layout (set fact)" ansible.builtin.set_fact: link_list: "{{ link_list|default([]) + [ 'ln -sfT ' + retronas_path + '/' + ll.1.name|lower + '/' + ll.0.src + ' ' + retronas_path + '/' + ll.1.name + '/' + ll.0.dest + ';' ] }}" loop: "{{ system_links|product(top_level_paths)|list }}" loop_control: loop_var: ll label: "{{ ll.0.src }}" when: - ll.1.enabled is true - ll.1.systems is true - name: "{{ my_name }} - build systems directory layout (createdirs)" ansible.builtin.shell: cmd: "{{ link_list|join('') }}" when: link_list is defined changed_when: false - name: "{{ my_name }} - add top level directory info" ansible.builtin.copy: dest: "{{ item.stat.path }}/dir.txt" content: | this folder structure is the responsiblity of the user to populate owner: "{{ retronas_user }}" group: "{{ retronas_group }}" mode: "0644" loop: "{{ tl_paths.results }}" when: tl_paths is defined and item.stat.exists is true ================================================ FILE: ansible/roles/retronas.role.curlftpfs/tasks/main.yaml ================================================ - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - templates" ansible.builtin.template: src: "{{ item.name }}.j2" dest: "{{ item.dest }}/{{ item.name }}" owner: "{{ item.owner|default('root') }}" group: "{{ item.group|default('root') }}" mode: "{{ item.mode|default('0644') }}" force: "{{ item.force|default('yes') }}" with_items: "{{ templates }}" - name: "{{ my_name }} - Install from source code" ansible.builtin.shell: "{{ retronas_root }}/scripts/{{ my_file }}.sh 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" args: creates: "/usr/local/bin/curlftpfs" ================================================ FILE: ansible/roles/retronas.role.curlftpfs/templates/install_curlftpfs.sh.j2 ================================================ # curlftpfs set -u VERS=${1:-0.9.2} APPNAME=curlftpfs-${VERS} REPO=https://ixpeering.dl.sourceforge.net/project/curlftpfs/curlftpfs/${VERS}/${APPNAME}.tar.gz?viasf=1 BUILDPATH={{ retronas_root }}/src [ ! -d ${BUILDPATH} ] && mkdir -p ${BUILDPATH} cd ${BUILDPATH} if $(curl -O $REPO) then tar xvf ${APPNAME}.tar.gz cd ${APPNAME} ./configure make make install fi rm -rf ${BUILDPATH} ================================================ FILE: ansible/roles/retronas.role.curlftpfs/vars/main.yaml ================================================ my_name: "curlftpfs" my_file: "install_{{ my_name }}" packages: - curl - build-essential - libglib2.0-dev - libfuse-dev - libcurl4-openssl-dev templates: - { name: "{{ my_file }}.sh", dest: "{{ retronas_root }}/scripts", mode: "0755"} ================================================ FILE: ansible/roles/retronas.role.dotnetcore3/tasks/main.yaml ================================================ - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - clean up old installs" ansible.builtin.file: path: "{{ srcdir }}" force: yes state: absent - name: "{{ my_name }} - create build dirs" ansible.builtin.file: path: "{{ srcdir }}" owner: root group: root mode: 0755 state: directory - name: "{{ my_name }} - Download SDK installer" ansible.builtin.get_url: url: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh dest: "{{ srcdir }}" owner: root group: root mode: 0755 - name: "{{ my_name }} - Install DotNet SDK" ansible.builtin.shell: cmd: "./dotnet-install.sh --version {{ version }} 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ srcdir }}" executable: /bin/bash environment: DOTNET_ROOT: "{{ retronas_root }}/bin/dotnetcore3" DOTNET_INSTALL_DIR: "{{ retronas_root }}/bin/dotnetcore3" TMPDIR: "{{ srcdir }}" ================================================ FILE: ansible/roles/retronas.role.dotnetcore3/vars/main.yaml ================================================ my_name: "DotNet Core 3.X SDK" my_file: "install_dotnetcore3" packages: - wget - curl - aria2 - coreutils srcdir: "{{ retronas_root }}/src/{{ my_file }}" version: 3.1.415 arch: x64 ================================================ FILE: ansible/roles/retronas.role.dotnetcore6/tasks/main.yaml ================================================ - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - clean up old installs" ansible.builtin.file: path: "{{ srcdir }}" force: yes state: absent - name: "{{ my_name }} - create build dirs" ansible.builtin.file: path: "{{ srcdir }}" owner: root group: root mode: 0755 state: directory - name: "{{ my_name }} - Download SDK installer" ansible.builtin.get_url: url: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh dest: "{{ srcdir }}" owner: root group: root mode: 0755 - name: "{{ my_name }} - Install DotNet SDK" ansible.builtin.shell: cmd: "./dotnet-install.sh --version {{ version }} 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ srcdir }}" executable: /bin/bash environment: DOTNET_ROOT: "{{ retronas_root }}/bin/dotnetcore6" DOTNET_INSTALL_DIR: "{{ retronas_root }}/bin/dotnetcore6" TMPDIR: "{{ srcdir }}" ================================================ FILE: ansible/roles/retronas.role.dotnetcore6/vars/main.yaml ================================================ my_name: "DotNet Core 6.X SDK" my_file: "install_dotnetcore6" packages: - wget - curl - aria2 - coreutils srcdir: "{{ retronas_root }}/src/{{ my_file }}" version: 6.0.400 arch: x64 ================================================ FILE: ansible/roles/retronas.role.dotnetcore8/tasks/main.yaml ================================================ - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - clean up old installs" ansible.builtin.file: path: "{{ srcdir }}" force: yes state: absent - name: "{{ my_name }} - create build dirs" ansible.builtin.file: path: "{{ srcdir }}" owner: root group: root mode: 0755 state: directory - name: "{{ my_name }} - Download SDK installer" ansible.builtin.get_url: url: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh dest: "{{ srcdir }}" owner: root group: root mode: 0755 - name: "{{ my_name }} - Install DotNet SDK" ansible.builtin.shell: cmd: "./dotnet-install.sh --version {{ version }} 2>&1 | tee {{ retronas_root }}/log/{{ my_file }}.log" chdir: "{{ srcdir }}" executable: /bin/bash environment: DOTNET_ROOT: "{{ retronas_root }}/bin/dotnetcore8" DOTNET_INSTALL_DIR: "{{ retronas_root }}/bin/dotnetcore8" TMPDIR: "{{ srcdir }}" ================================================ FILE: ansible/roles/retronas.role.dotnetcore8/vars/main.yaml ================================================ my_name: "DotNet Core 8.X SDK" my_file: "install_dotnetcore8" packages: - wget - curl - aria2 - coreutils srcdir: "{{ retronas_root }}/src/{{ my_file }}" version: 8.0.416 arch: x64 ================================================ FILE: ansible/roles/retronas.role.extradirs/tasks/main.yaml ================================================ - ansible.builtin.import_role: name: retronas.role.createdirs ================================================ FILE: ansible/roles/retronas.role.extradirs/vars/main.yaml ================================================ my_name: "Generic Extra dir(s)" my_file: "install_romdir" module_name: "extradirs" top_level_paths: - { name: "saves", enabled: yes, systems: yes } - { name: "savestates", enabled: yes, systems: yes } - { name: "bios", enabled: yes, systems: yes } - { name: "wallpapers", enabled: yes, systems: no } ================================================ FILE: ansible/roles/retronas.role.filesystems/tasks/main.yaml ================================================ - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest ================================================ FILE: ansible/roles/retronas.role.filesystems/vars/main.yaml ================================================ my_name: "RetroNAS filesystems" my_file: "install_filesystems" packages: - btrfs-progs - ntfs-3g - exfatprogs - exfat-fuse - hfsplus - xfsprogs - nfs-common - e2fsprogs - dosfstools #- curlftpfs - sshfs - udisks2 - udisks2-btrfs - udisks2-lvm2 #- udisks2-zram ================================================ FILE: ansible/roles/retronas.role.firewalld.port/tasks/main.yaml ================================================ # # FIREWALL # - name: "{{ my_name }} - checking firewall rule" ansible.builtin.stat: path: /etc/firewalld/services register: firewalld_services - name: "{{ my_name }} - reload to pick up any new config" ansible.builtin.service: name: "firewalld" state: reloaded when: firewalld_services.stat.exists - name: "{{ my_name }} - enable firewall rule (port)" ansible.posix.firewalld: zone: "{{ item.zone | default('retro') }}" port: "{{ item.port }}/{{ item.protocol }}" permanent: "{{ item.permanent | default('true') }}" state: "{{ item.state | default('enabled') }}" immediate: true loop: "{{ firewalld_ports }}" when: firewalld_ports is defined and firewalld_services.stat.exists - name: "{{ my_name }} - enable firewall rule (service)" ansible.posix.firewalld: zone: "{{ item.zone | default('retro') }}" service: "{{ item.service | default('ssh') }}" permanent: true state: enabled immediate: true with_items: "{{ firewalld_rules }}" when: firewalld_rules is defined and firewalld_services.stat.exists ================================================ FILE: ansible/roles/retronas.role.htpasswd/tasks/main.yaml ================================================ --- - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - manage htpasswd" ansible.builtin.file: path: "{{ retronas_htpasswd }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: touch mode: "0640" ================================================ FILE: ansible/roles/retronas.role.htpasswd/vars/main.yml ================================================ --- retronas_htpasswd: "/etc/retronas.htpasswd" ================================================ FILE: ansible/roles/retronas.role.nfs/handlers/main.yaml ================================================ - name: "{{ my_name }} - Restart service" ansible.builtin.service: name: "{{ item }}" state: restarted with_items: - nfs-kernel-server ================================================ FILE: ansible/roles/retronas.role.nfs/tasks/main.yaml ================================================ - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - retrieve {{ retronas_user }} user info" ansible.builtin.getent: database: passwd key: "{{ retronas_user }}" - ansible.builtin.set_fact: retronas_user_id: "{{ getent_passwd[retronas_user][1] }}" - name: "{{ my_name }} - retrieve {{ retronas_group }} group info" ansible.builtin.getent: database: group key: "{{ retronas_group }}" - ansible.builtin.set_fact: retronas_group_id: "{{ getent_group[retronas_group][1] }}" - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item }}" state: started enabled: yes with_items: - nfs-kernel-server - ansible.builtin.import_role: name: retronas.role.firewalld.port ================================================ FILE: ansible/roles/retronas.role.nfs/vars/main.yaml ================================================ my_name: "NFS" my_file: "install_nfs" module_name: "nfs" packages: - nfs-common - nfs-kernel-server paths: - { name: "exports.d", dest: "/etc" } templates: - { name: "nfs-kernel-server", dest: "/etc/default" } - { name: "exports", dest: "/etc/" } firewalld_rules: - { zone: retro, service: nfs } - { zone: modern, service: nfs } ================================================ FILE: ansible/roles/retronas.role.nginx/handlers/main.yaml ================================================ - name: "restart nginx" ansible.builtin.service: name: "{{ item.name }}" state: restarted with_items: "{{ systemd_units }}" when: item.restart == "yes" ================================================ FILE: ansible/roles/retronas.role.nginx/tasks/main.yaml ================================================ --- - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.sslcert - name: "{{ my_name }} - manage packages" ansible.builtin.package: name: "{{ item.name }}" state: "{{ item.state }}" with_items: "{{ packages }}" notify: "restart nginx" - ansible.builtin.import_role: name: retronas.role.paths - name: "{{ my_name }} - remove old config" ansible.builtin.file: path: "{{ item }}/99-retronas.conf" state: absent with_items: - "{{ nginx_sites_available }}" - "{{ nginx_sites_enabled }}" - name: "{{ my_name }} - config dirs" ansible.builtin.file: path: "/etc/{{ my_name }}/{{ item.path }}" owner: "{{ item.owner|default('root') }}" group: "{{ item.group|default('root') }}" mode: "{{ item.mode|default('0750') }}" state: directory loop: "{{ lookup('filetree', 'templates/' + my_file + '/conf', wantlist=True) }}" when: item.state == 'directory' notify: "restart nginx" - name: "{{ my_name }} - config files" ansible.builtin.template: src: "{{ item.src }}" dest: "/etc/{{ my_name }}/{{ item.path }}" owner: "{{ item.owner|default('root') }}" group: "{{ item.group|default('root') }}" mode: "{{ item.mode|default('0644') }}" force: "{{ item.force|default('yes') }}" loop: "{{ lookup('filetree', 'templates/' + my_file + '/conf', wantlist=True) }}" when: item.state == 'file' notify: "restart nginx" - name: "{{ my_name }} - www dirs" ansible.builtin.file: path: "{{ retronas_path }}/www/{{ item.path }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" mode: "{{ item.mode|default('0750') }}" state: directory loop: "{{ lookup('filetree', 'templates/' + my_file +' /www', wantlist=True) }}" when: item.state == 'directory' notify: "restart nginx" - name: "{{ my_name }} - www files" ansible.builtin.template: src: "{{ item.src }}" dest: "{{ retronas_path }}/www/{{ item.path }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" mode: "{{ item.mode|default('0644') }}" force: "{{ item.force|default('yes') }}" loop: "{{ lookup('filetree', 'templates/' + my_file + '/www', wantlist=True) }}" when: item.state == 'file' notify: "restart nginx" - name: "{{ my_name }} - enable sites" ansible.builtin.file: src: "{{ nginx_sites_available }}/{{ item.name }}" dest: "{{ nginx_sites_enabled }}/{{ item.name }}" state: "link" with_items: "{{ templates }}" when: item.enable is defined and item.enable == "yes" notify: "restart nginx" - name: "{{ my_name }} - enable this site" ansible.builtin.file: src: "{{ nginx_sites_available }}/{{ site_enable }}" dest: "{{ nginx_sites_enabled }}/{{ site_enable }}" state: "link" when: site_enable | length > 0 notify: "restart nginx" - name: "{{ my_name }} - disable sites" ansible.builtin.file: path: "{{ nginx_sites_enabled }}/{{ item }}" state: "absent" with_items: "{{ sites_disable }}" notify: "restart nginx" - name: "{{ my_name }} - update runas user" ansible.builtin.lineinfile: path: /etc/{{ my_name }}/{{ my_name }}.conf regexp: '^user\s[a-z-]+;$' line: user {{ retronas_user }}; state: present notify: "restart nginx" - name: "{{ my_name }} - enable startup services" ansible.builtin.service: name: "{{ item.name }}" state: "{{ item.state }}" enabled: "{{ item.enabled }}" with_items: "{{ systemd_units }}" # # FIREWALL # - name: "{{ my_name }} - checking firewall rule" ansible.builtin.stat: path: /etc/firewalld/services register: firewalld_services - name: "{{ my_name }} - enable firewall rule" ansible.posix.firewalld: zone: retro service: "{{ item }}" permanent: true state: enabled immediate: true with_items: - http - https when: firewalld_services.stat.exists ================================================ FILE: ansible/roles/retronas.role.nginx/templates/install_nginx/conf/includes/autoindex.conf ================================================ autoindex on; autoindex_exact_size off; autoindex_format html; autoindex_localtime on; ================================================ FILE: ansible/roles/retronas.role.nginx/templates/install_nginx/conf/includes/listen-80.conf ================================================ listen 80; listen [::]:80; ================================================ FILE: ansible/roles/retronas.role.nginx/templates/install_nginx/conf/includes/ssl.conf ================================================ listen 443 ssl; listen [::]:443 ssl; ssl_certificate /etc/ssl/private/retronas.crt; ssl_certificate_key /etc/ssl/private/retronas.key; ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; ssl_ciphers HIGH:!aNULL:!MD5; ================================================ FILE: ansible/roles/retronas.role.nginx/templates/install_nginx/conf/sites-available/10-retronas.conf ================================================ server { server_name retronas; server_name retro; server_name www.*; include includes/listen-80.conf; include includes/ssl.conf; location / { root {{ retronas_path }}/www; } location /files { alias {{ retronas_path }}; index index.html; include includes/autoindex.conf; } location /3ds { alias {{ retronas_path }}/3ds; index index.html; include includes/autoindex.conf; } } ================================================ FILE: ansible/roles/retronas.role.nginx/templates/install_nginx/conf/sites-available/99-retronas-files.conf ================================================ server { server_name files.*; include includes/listen-80.conf; include includes/ssl.conf; location / { root {{ retronas_path }}; index index.html; include includes/autoindex.conf; } } ================================================ FILE: ansible/roles/retronas.role.nginx/templates/install_nginx/www/index.html ================================================ retroNAS files
nas
fenrir
cockpit
deluge
syncthing
xlink
================================================ FILE: ansible/roles/retronas.role.nginx/vars/main.yaml ================================================ my_name: "nginx" my_file: "install_{{ my_name }}" nginx_sites_available: "/etc/{{ my_name }}/sites-available" nginx_sites_enabled: "/etc/{{ my_name }}/sites-enabled" paths: - { name: "www", dest: "/{{ retronas_path }}" } packages: - { name: "lighttpd", state: "absent" } - { name: "{{ my_name }}", state: "latest" } templates: - { name: "10-retronas.conf", dest: "{{ nginx_sites_available }}", mode: "0640", enable: "yes" } - { name: "99-retronas-files.conf", dest: "{{ nginx_sites_available }}", mode: "0640", enable: "yes" } sites_disable: - "default" systemd_units: - { name: "{{ my_name }}", type: 'service', state: "started", enabled: "yes", restart: "yes", instance: "no" } site_enable: "" ================================================ FILE: ansible/roles/retronas.role.package.latest/tasks/main.yaml ================================================ - name: "{{ my_name }} - Install packages" ansible.builtin.package: name: "{{ packages }}" state: latest update_cache: true become: true ================================================ FILE: ansible/roles/retronas.role.paths/tasks/main.yaml ================================================ - name: "{{ my_name }} - paths" ansible.builtin.file: src: "{{ item.src | default(omit) }}" dest: "{{ item.dest + '/' | default(omit) }}{{ item.name }}" owner: "{{ item.owner|default('root') }}" group: "{{ item.group|default('root') }}" mode: "{{ item.mode|default('0755') }}" state: "{{ item.state|default('directory') }}" loop: "{{ paths }}" when: paths is defined ================================================ FILE: ansible/roles/retronas.role.romdir/tasks/main.yaml ================================================ --- - ansible.builtin.import_role: name: retronas.role.createdirs ================================================ FILE: ansible/roles/retronas.role.romdir/vars/main.yaml ================================================ --- my_name: "Generic ROM dir" my_file: "install_romdir" module_name: "romdir" top_level_paths: - { name: "roms", enabled: yes, systems: yes } ================================================ FILE: ansible/roles/retronas.role.samba/handlers/main.yaml ================================================ - name: "restart samba" ansible.builtin.service: name: "{{ item }}" state: restarted loop: "{{ my_services }}" ================================================ FILE: ansible/roles/retronas.role.samba/tasks/main.yaml ================================================ --- - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates - name: "{{ my_name }} - configure samba config" ansible.builtin.ini_file: path: /etc/samba/smb.conf section: "{{ item.section }}" option: "{{ item.option }}" value: "{{ item.value }}" loop: "{{ config_opts }}" - name: "{{ my_name }} - restarted/enabled" ansible.builtin.service: name: "{{ item }}" state: restarted enabled: true loop: "{{ my_services }}" - ansible.builtin.import_role: name: retronas.role.firewalld.port ================================================ FILE: ansible/roles/retronas.role.samba/templates/retronas.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. comment = retronas path = {{ retronas_path }} guest ok = no browseable = yes write list = {{ retronas_user }} writeable = yes force user = {{ retronas_user }} force group = {{ retronas_group }} create mask = 0775 directory mask = 0775 follow symlinks = yes wide links = yes ================================================ FILE: ansible/roles/retronas.role.samba/vars/main.yaml ================================================ --- my_name: "Samba" my_file: "" # required to clear out any play set var packages: - avahi-daemon - samba - samba-vfs-modules my_services: - avahi-daemon - smbd - nmbd config_opts: - { section: "global", option: "min protocol", value: "CORE"} - { section: "global", option: "netbios name", value: "retrosmb"} - { section: "global", option: "lanman auth", value: "yes"} - { section: "global", option: "client lanman auth", value: "yes"} - { section: "global", option: "ntlm auth", value: "yes"} - { section: "global", option: "client ntlm auth", value: "yes"} - { section: "global", option: "ntlmv2 auth", value: "yes"} - { section: "global", option: "client ntlmv2 auth", value: "yes"} - { section: "global", option: "unix extensions", value: "no"} - { section: "global", option: "allow insecure wide links", value: "yes"} - { section: "global", option: "socket options", value: "TCP_NODELAY IPTOS_LOWDELAY SO_KEEPALIVE"} - { section: "global", option: "strict locking", value: "no"} - { section: "global", option: "strict sync", value: "no"} - { section: "global", option: "sync always", value: "no"} - { section: "global", option: "deadtime", value: "1560"} - { section: "retronas", option: "include", value: "/etc/samba/retronas.conf"} templates: - { name: "retronas.conf", dest: "/etc/samba" } firewalld_rules: - { zone: "retro", service: "samba" } - { zone: "modern", service: "samba-modern" } changed: false ================================================ FILE: ansible/roles/retronas.role.samba.system/tasks/link.yml ================================================ --- - name: "{{ my_name }} - build layout list (set fact) (links)" ansible.builtin.set_fact: path_list_ll: "{{ path_list_ll|default([]) + [ 'ln -sfT ../roms/' + item.src + ' \"' + retronas_path + '/' + system_key + '/' + item[system_key] + '\";' ] }}" loop: "{{ system_map }}" loop_control: label: "{{ item.src }}" when: top_level_paths is not defined and item[system_key] is defined and item[system_key] | length > 0 - name: "{{ my_name }} - build internal directory layout (links)" ansible.builtin.file: src: "../roms/{{ item.src }}" dest: "{{ retronas_path }}/{{ system_key }}/{{ item.dest }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: link loop: "{{ internal_symlinks }}" loop_control: label: "{{ item.src }}" when: internal_symlinks is defined and top_level_paths is not defined - name: "{{ my_name }} - build layout list (set fact) (top level paths) (links)" ansible.builtin.set_fact: path_list_tl: "{{ path_list_tl|default([]) + [ 'ln -sfT ../../' + item.1.generic|lower + '/' + item.0.src + ' \"' + retronas_path + '/' + system_key + '/' + item.1.name + '/' + item.0[system_key] + '\";' ] }}" loop: "{{ system_map|product(top_level_paths)|list }}" loop_control: label: "{{ item.0.src }}" when: top_level_paths is defined and item.1.enabled is true and item.0[system_key] is defined and item.0[system_key] | length > 0 and item.1.systems is true - name: "{{ my_name }} - build internal directory layout (top level paths) (links)" ansible.builtin.file: src: "../../{{ item.1.generic }}/{{ item.0.src }}" dest: "{{ retronas_path }}/{{ system_key }}/{{ item.1.name }}/{{ item.0.dest }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: link loop: "{{ internal_symlinks|product(top_level_paths)|list }}" loop_control: label: "{{ item.0.src }}" when: internal_symlinks is defined and top_level_paths is defined ================================================ FILE: ansible/roles/retronas.role.samba.system/tasks/main.yaml ================================================ --- - name: "{{ my_name }} - Include systems map" ansible.builtin.include_vars: "retronas_systems.yml" - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - build top level" ansible.builtin.file: path: "{{ retronas_path }}/{{ system_key }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory mode: "0775" - name: "{{ my_name }} - build top level share paths" ansible.builtin.file: path: "{{ retronas_path }}/{{ system_key }}/{{ item.name }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory mode: "0775" loop: "{{ top_level_paths }}" when: top_level_paths is defined and item.enabled is true - name: "{{ my_name }} - setup directories with symlinks" include_tasks: link.yml when: nolink is not defined or nolink is false - name: "{{ my_name }} - setup directories without symlinks" include_tasks: nolink.yml when: nolink is defined and nolink is true - name: "{{ my_name }} - configure includes file" ansible.builtin.ini_file: path: /etc/samba/smb.conf section: "{{ system_key }}" option: "include" value: "/etc/samba/retronas_{{ system_key }}.conf" - name: "{{ my_name }} - configure retro shares" ansible.builtin.template: src: "retronas_system.conf.j2" dest: /etc/samba/retronas_{{ system_key }}.conf owner: root group: root mode: "0644" - name: "{{ my_name }} - build systems directory layout (systems)" ansible.builtin.shell: cmd: "{{ path_list_ll|join('') }}" when: path_list_ll is defined changed_when: false - name: "{{ my_name }} - build systems directory layout (systems) (top_level)" ansible.builtin.shell: cmd: "{{ path_list_tl|join('') }}" when: path_list_tl is defined changed_when: false ================================================ FILE: ansible/roles/retronas.role.samba.system/tasks/nolink.yml ================================================ --- - name: "{{ my_name }} - build layout nolink list (set fact) (dir)" ansible.builtin.set_fact: path_list_ll: "{{ path_list_ll|default([]) + [ 'mkdir -p ' + retronas_path + '/' + system_key + '/' + item[system_key] + ';' ] }}" loop: "{{ system_map }}" loop_control: label: "{{ item[system_key] }}" when: top_level_paths is not defined and item[system_key] is defined and item[system_key] | length > 0 - name: "{{ my_name }} - build layout nolink list (set fact) (top level paths) (dir)" ansible.builtin.set_fact: path_list_tl: "{{ path_list_tl|default([]) + [ 'mkdir -p ' + retronas_path + '/' + system_key + '/' + item.1.name + '/' + item.0[system_key] + ';' ] }}" loop: "{{ system_map|product(top_level_paths)|list }}" loop_control: label: "{{ item.0[system_key] }}" when: top_level_paths is defined and item.1.enabled is true and item.0[system_key] is defined and item.0[system_key] | length > 0 and item.1.systems is true ================================================ FILE: ansible/roles/retronas.role.samba.system/templates/retronas_system.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. comment = {{ system_key }} path = {{ retronas_path }}/{{ system_key }} guest ok = no browseable = yes write list = {{ retronas_user }} writeable = {{ writable | default('yes') }} valid users = {{ retronas_user }} create mask = 0775 directory mask = 0775 follow symlinks = yes wide links = yes ================================================ FILE: ansible/roles/retronas.role.sslcert/tasks/main.yaml ================================================ - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - ansible.builtin.import_role: name: retronas.role.package.latest - name: "{{ my_name }} - check self-signed cert" ansible.builtin.stat: path: "{{ my_cert }}" register: self_signed_cert - name: "{{ my_name }} - create self-signed cert" ansible.builtin.shell: cmd: /usr/bin/openssl req -nodes -new -x509 -keyout {{ my_key }} -out {{ my_cert }} -subj "/C=AU/ST=Sydney/L=retronas/O=retronas/OU=retronas/CN=retronas" -days 3660 when: self_signed_cert is defined and self_signed_cert.stat.exists is false ================================================ FILE: ansible/roles/retronas.role.sslcert/vars/main.yaml ================================================ my_name: "sslcert" my_file: "install_{{ my_name }}" my_cert: /etc/ssl/private/retronas.crt my_key: /etc/ssl/private/retronas.key packages: - "openssl" ================================================ FILE: ansible/roles/retronas.role.system-config/tasks/main.yaml ================================================ --- - name: "{{ my_name }} - Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "{{ my_name }} - Gather required facts" ansible.builtin.setup: gather_subset: - date_time - architecture - default_ipv4 - name: "{{ my_name }} - Create retronas user system dirs" ansible.builtin.file: path: "{{ retronas_path }}/{{ item }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: directory mode: "0755" with_items: "{{ system_user_dirs }}" - name: "{{ my_name }} - Log General Entry" ansible.builtin.ini_file: path: "{{ retronas_path }}/config/{{ ini_filename }}" section: "general" option: "{{ item.option }}" value: "{{ item.value }}" state: present with_items: "{{ general_options }}" when: general_options is defined - name: "{{ my_name }} - Log Platform info" ansible.builtin.ini_file: path: "{{ retronas_path }}/config/{{ ini_filename }}" section: "platform" option: "{{ item.option }}" value: "{{ item.value }}" state: present with_items: "{{ platform_info }}" when: platform_info is defined - name: "{{ my_name }} - RetroNAS runtime info - git branch" ansible.builtin.shell: cmd: git rev-parse --abbrev-ref HEAD chdir: "{{ retronas_root }}" register: retronas_git_branch - name: "{{ my_name }} - RetroNAS runtime info - git commit" ansible.builtin.shell: cmd: git rev-parse HEAD chdir: "{{ retronas_root }}" register: retronas_git_commit - name: "{{ my_name }} - Log RetroNAS git branch" ansible.builtin.ini_file: path: "{{ retronas_path }}/config/{{ ini_filename }}" section: "retronas" option: "branch" value: "{{ retronas_git_branch.stdout }}" state: present when: retronas_git_branch is defined - name: "{{ my_name }} - Log RetroNAS git commit" ansible.builtin.ini_file: path: "{{ retronas_path }}/config/{{ ini_filename }}" section: "retronas" option: "commit" value: "{{ retronas_git_commit.stdout }}" state: present when: retronas_git_commit is defined - name: "{{ my_name }} - Log Package Entry" ansible.builtin.ini_file: path: "{{ retronas_path }}/config/{{ ini_filename }}" section: "package" option: "{{ module_name }}" value: "{{ module_state }}" state: "{{ module_state }}" when: module_name is defined and module_state is defined - name: "{{ my_name }} - fix config perms" ansible.builtin.file: path: "{{ retronas_path }}/config/{{ ini_filename }}" owner: "{{ retronas_user }}" group: "{{ retronas_group }}" state: file mode: "0644" ================================================ FILE: ansible/roles/retronas.role.system-config/vars/main.yaml ================================================ --- my_name: "retronas user config setup" module_state: "present" system_user_dirs: - config - config/modules general_options: - { option: "title", value: "RetroNAS Packages"} - { option: "author", value: "Generated by RetroNAS"} - { option: "last_updated", value: "{{ ansible_date_time.date }}" } platform_info: - { option: "architecture", value: "{{ ansible_architecture }}" } - { option: "ipv4addr", value: "{{ ansible_default_ipv4.address }}" } - { option: "ipv4iface", value: "{{ ansible_default_ipv4.interface }}" } ini_filename: "retronas_packages.ini" ================================================ FILE: ansible/roles/retronas.role.templates/tasks/main.yaml ================================================ --- - name: "{{ my_name }} - templates" ansible.builtin.template: src: "templates/{{ my_file }}/{{ tmpl.sub + '/' if tmpl.sub is defined else '' }}{{ tmpl.name }}.j2" dest: "{{ tmpl.dest }}/{{ tmpl.name }}" owner: "{{ tmpl.owner|default('root') }}" group: "{{ tmpl.group|default('root') }}" mode: "{{ tmpl.mode|default('0644') }}" force: "{{ tmpl.force|default('yes') }}" loop: "{{ templates }}" loop_control: loop_var: "tmpl" ================================================ FILE: ansible/roles/retronas.role.update-user/tasks/main.yaml ================================================ - name: "Load RetroNAS config" ansible.builtin.include_vars: retronas_vars.yml - name: "update user" ansible.builtin.user: user: "{{ retronas_user }}" groups: "{{ append_user_group }}" append: true when: append_user_group is defined ================================================ FILE: ansible/roles/retronas.role.x11vnc/tasks/main.yaml ================================================ - ansible.builtin.import_role: name: retronas.role.package.latest - ansible.builtin.import_role: name: retronas.role.templates ================================================ FILE: ansible/roles/retronas.role.x11vnc/templates/install_x11vnc/x11vnc_wrapper.sh.j2 ================================================ #!/bin/bash XDISPLAY=$1 XAUTH=$2 PORT=$3 RFBAUTH=/etc/vncpasswd_retronas # use a local auth file if it exists if [ -f /home/$USER/vncpasswd_retronas ] then RFBAUTH=/home/$USER/vncpasswd_retronas fi x11vnc -quiet -display $XDISPLAY -auth $XAUTH -listen 0.0.0.0 -rfbport $PORT -rfbauth $RFBAUTH -forever ================================================ FILE: ansible/roles/retronas.role.x11vnc/vars/main.yaml ================================================ my_name: "x11vnc" my_file: "install_{{ my_name }}" packages: - xvfb - x11vnc templates: - { name: "x11vnc_wrapper.sh", dest: "/usr/local/bin", mode: "0755"} ================================================ FILE: ansible/templates/install_3ds_qr_codes/3ds_qr.sh.j2 ================================================ #!/bin/bash ## RetroNAS autogenerated FLUSH="" OPTSTRING="f" while getopts $OPTSTRING ARG do case $ARG in f) FLUSH=1 ;; esac done MYIP=$(ip -4 -br a show dev {{ retronas_net_3dsqr_interface }} | awk '!/127/{sub(/\/[0-9].+$/, ""); print $3}' | head -n1) if [ -z "${MYIP}" ] then echo "Failed to find ip address from interface, fix interface in retronas config" echo "Press any key to continue" read -s exit 1 fi MYURL="http://${MYIP}/3ds" umask 002 generate_qr () { # Build path mkdir -p "${QRDIR}" 2>/dev/null # Convert URLs to HTML safe encoding: CIAURL=$( echo "${MYURL}/cia/$RELDIR/${BASENAME}" | sed 's/\ /%20/g' ) QRURL=$( echo "${MYURL}/qr/$RELDIR/${BARENAME}.png" | sed 's/\ /%20/g' ) # Generate QR code echo "Generating QR for ${BARENAME} ..." qrencode -o "${QRDIR}/${BARENAME}.png" -s 10 -8 "${CIAURL}" # Generate HTML file echo "\ \
\

\ "${CIAURL}"\

\ \

" > "${QRDIR}/${BARENAME}".html } flush() { echo "Flushing QR codes" rm -f {{ retronas_path }}/3ds/qr/* } clean() { ## Clean QR codes echo "Cleaning out QR codes..." find "{{ retronas_path }}/3ds/qr/" -type f -iname '*.png' | while read QRFILE do BASENAME=$( basename "${QRFILE}" ) BARENAME="${BASENAME%.*}" BASEDIR=$( dirname "${QRFILE}" ) RELDIR=$( echo "${BASEDIR}" | sed 's#{{ retronas_path }}/3ds/qr##g' ) CIADIR="{{ retronas_path }}/3ds/cia/${RELDIR}" test -f "${CIADIR}/${BARENAME}".cia || test -f "${CIADIR}/${BARENAME}".CIA || rm -vf "${BASEDIR}/${BARENAME}.png" "${BASEDIR}/${BARENAME}.html" done } [ ! -z $FLUSH ] && flush clean ## Find CIA files to scan echo "Scanning for new CIA files, generating QR codes..." find "{{ retronas_path }}/3ds/cia/" -type f -iname '*.cia' | while read CIAFILE do BASENAME=$( basename "${CIAFILE}" ) BARENAME="${BASENAME%.*}" BASEDIR=$( dirname "${CIAFILE}" ) RELDIR=$( echo "${BASEDIR}" | sed 's#{{ retronas_path }}/3ds/cia##g' ) QRDIR="{{ retronas_path }}/3ds/qr/${RELDIR}" test -f "${QRDIR}/${BARENAME}".png || generate_qr done echo "All done" read -s ================================================ FILE: ansible/templates/install_3ds_qr_codes/retronas_3ds_qr.cron.j2 ================================================ # RetroNAS automatically generated # Every 15 minutes check for new 3DS titles and generate a QR code to match */15 * * * * {{ retronas_user }} {{ retronas_root }}/scripts/3ds_qr.sh >/dev/null 2>&1 ================================================ FILE: ansible/templates/install_adtpro/ADTPro.properties.j2 ================================================ #ADTPro.properties AudioHardwareIndex=0 AudioPortIndex=0 Client01xCompatibleProtocol=false CommPort=/dev/ttyUSB0 CommPortBootstrapPacing=250 CommPortBootstrapSpeed=9600 CommPortSpeed=9600 HardwareHandshaking=false SerialIPHost=0.0.0.0 SerialIPPort=1977 TraceEnabled=false UDPServerPort=6502 WorkingDirectory={{ retronas_path }}/adtpro ================================================ FILE: ansible/templates/install_adtpro/adtpro.service.j2 ================================================ [Unit] Description=ADTPro %i StartLimitIntervalSec=60 StartLimitBurst=4 [Service] WorkingDirectory={{ my_dir }} ExecStart={{ my_dir }}/adtpro_retronas.sh %i Restart=on-failure RestartSec=2 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_adtpro/adtpro_retronas.sh.j2 ================================================ #!/bin/bash MODE=${1:-localhost} PORT=${2:-60000} PARENTPID=$(ps -ef | grep -E "xvfb-run.*adtpro.*$MODE" | grep -v grep | head -n1 | awk '{print $2}') cd {{ my_dir }} ./adtpro.sh headless $MODE &> {{ retronas_root }}/log/adtpro_$MODE.log & # get atpro runtime details sleep 3 SESSION=$(ps -ef | grep -E "$PARENTPID.*Xvfb" | head -n1 | awk '{print $9,$16}') XDISPLAY=$(echo $SESSION | cut -d' ' -f1 ) XAUTH=$(echo $SESSION | cut -d' ' -f2 ) /usr/local/bin/x11vnc_wrapper.sh $XDISPLAY $XAUTH $PORT ================================================ FILE: ansible/templates/install_adtpro/install_adtpro.sh.j2 ================================================ #!/bin/bash set -u BINDIR="/opt/adtpro" DLDIR=$(mktemp -d) echo "Downloading adtpro release..." RELEASE=$( curl -kLs https://api.github.com/repos/ADTPro/adtpro/releases | jq -r ".[0].assets | map(select(.name | match (\".tar.gz\")))[-1] | .browser_download_url" ) [ -z "$RELEASE" ] && echo "Couldn't get release file" && exit 1 cd $DLDIR curl -OJL "${RELEASE}" RELFILE=$(basename $RELEASE) if [ -f $RELFILE ] then echo "install dir" [ -d $BINDIR ] && mkdir -p $BINDIR echo "unpacking" tar xvf $DLDIR/$RELFILE echo "moving" mv ADTPro-*/* $BINDIR/ echo "cleaning up" rm -rf "${DLDIR}" if [ -d $BINDIR/disks ] then echo "copying disks to storage" chown -R {{ retronas_user }}: "${BINDIR}/disks/" cp --no-clobber -p "${BINDIR}/disks/"* "{{ retronas_path }}/roms/apple/appleii/" fi else echo "file is not present" exit 1 fi echo "All done!" ================================================ FILE: ansible/templates/install_affstools/install_affstools.sh.j2 ================================================ #!/bin/bash APP=affstools SRCDIR="{{ retronas_root }}/src" BINDIR="/usr/local/sbin" BINS=( affsck mkaffs ) echo "Configuring build directories..." rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Downloading source code..." git clone https://github.com/kdave/${APP} cd ${APP} ./configure make echo "Moving binary to ${BINDIR}..." for BIN in ${BINS[@]} do chmod +x ${BIN} mv -vf ${BIN} "${BINDIR}"/ done echo "Cleaning up..." rm -rf "${SRCDIR}" echo "All done!" ================================================ FILE: ansible/templates/install_amitools/install_amitools.sh.j2 ================================================ #!/bin/bash APP=amitools mv /usr/lib/python3*/EXTERNALLY-MANAGED /usr/lib/python3/EXTERNALLY-MANAGED.old 2> /dev/null pip3 install cython pip3 install -U git+https://github.com/cnvogelg/${APP}.git mv /usr/lib/python3*/EXTERNALLY-MANAGED.old /usr/lib/python3/EXTERNALLY-MANAGED 2> /dev/null echo "All done!" ================================================ FILE: ansible/templates/install_apfs-fuse/install_apfs-fuse.sh.j2 ================================================ #!/bin/bash set -u SRCDIR="{{ retronas_root }}/src" BINDIR="/usr/local/bin" REPO=https://github.com/sgan81/apfs-fuse.git if [ ! -x "${BINDIR}/apfs-fuse" ] then echo "apfs-fuse not found, so we'll build it!" echo "Configuring build directories..." [ -d ${SRCDIR} ] && rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Downloading git source ..." git clone $REPO cd "${SRCDIR}/$(basename $REPO .git)" echo "Processing submodules" git submodule init git submodule update echo "Building" mkdir build cd build cmake .. ccmake . # Only if you want to change build options make echo "Moving binary to RetroNAS bin dir..." mkdir -p "${BINDIR}" 2>/dev/null mv -vf apfs-fuse "${BINDIR}/" echo "Cleaning up..." [ -d ${SRCDIR} ] && rm -rf "${SRCDIR}" echo "All done!" fi ================================================ FILE: ansible/templates/install_assembly64/assembly64.service.j2 ================================================ [Unit] Description={{ my_name }} StartLimitIntervalSec=60 StartLimitBurst=4 [Service] User={{ retronas_user }} WorkingDirectory={{ my_dir }} ExecStart={{ my_dir }}/{{ my_name }}_retronas.sh start Restart=on-failure RestartSec=2 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_assembly64/assembly64_retronas.sh.j2 ================================================ #!/bin/bash MODE=${1:-localhost} PORT=${2:-60001} export DISPLAY=:100 export JAVA_HOME=/opt/java/jdk-22.0.2 export JFX_HOME=/opt/java/javafx-sdk-22.0.2 PARENTPID=$(ps -ef | grep -E "xvfb-run.*assembly64.*" | grep -v grep | head -n1 | awk '{print $2}') cd {{ my_dir }} Xvfb $DISPLAY -screen 0 1024x768x16 & ./assembly64.sh $1 & # get assembly64 runtime details sleep 3 SESSION=$(ps -ef | grep -E "$PARENTPID.*Xvfb" | head -n1 | awk '{print $9,$16}') XDISPLAY=$(echo $SESSION | cut -d' ' -f1 ) XAUTH=$(echo $SESSION | cut -d' ' -f2 ) /usr/local/bin/x11vnc_wrapper.sh $XDISPLAY $XAUTH $PORT ================================================ FILE: ansible/templates/install_assembly64/install_assembly64.sh.j2 ================================================ #!/bin/bash ARCH=$(uname -m) DLARCH=aarch64 JAVA_VERS=22.0.2 case $ARCH in x86_64) DLARCH=x64 ;; aarch64) DLARCH=aarch64 ;; *) DLARCH=x86_64 esac [ ! -d /opt/java ] && mkdir -p /opt/java cd /tmp ### DEPS ## OPENJDK if [ ! -d /opt/java/jdk-${JAVA_VERS} ] then OPENJDK="https://download.java.net/java/GA/jdk${JAVA_VERS}/c9ecb94cd31b495da20a27d4581645e8/9/GPL/openjdk-${JAVA_VERS}_linux-${DLARCH}_bin.tar.gz" curl -sLk -oopenjdk.tar.gz $OPENJDK tar -xv -f openjdk.tar.gz -C /opt/java rm -f openjdk.tar.gz else echo "jdk ${JAVA_VERS} already installed" fi ## OPENJFX if [ ! -d /opt/java/javafx-sdk-${JAVA_VERS} ] then OPENJFX="https://download2.gluonhq.com/openjfx/${JAVA_VERS}/openjfx-${JAVA_VERS}_linux-${DLARCH}_bin-sdk.zip" curl -sLk -oopenjfx.zip $OPENJFX unzip -qq -d /opt/java openjfx.zip rm -f openjfx.zip else echo "jfx ${JAVA_VERS} already installed" fi ## ASSEMBLY64 if [ ! -f /opt/assembly64/assembly64.sh ] then ASSEMBLY="https://assembly64.hackerswithstyle.se/assembly/assembly64-shell.zip" curl -sLk -oassembly64.zip $ASSEMBLY unzip -qq -d /opt assembly64.zip rm -f assembly64.zip else echo "assembly64 already installed" fi ================================================ FILE: ansible/templates/install_atarist-sidecart/99-retronas-sidecart.conf.j2 ================================================ ================================================ FILE: ansible/templates/install_atarist-sidecart/atarist-sidecart-generate-roms.sh.j2 ================================================ #!/bin/bash MYURL="http://$(ip -4 -br a | awk '!/127/{sub(/\/[0-9].+$/, ""); print $3}')/files/atarist/roms" umask 002 cd {{ retronas_path }}/atarist/sidecart python {{ script_dest }} --path {{ retronas_path }}/atarist/roms --url ${MYURL} mv {{ retronas_path }}/atarist/roms/roms.json {{ retronas_path }}/atarist/sidecart/ chown {{ retronas_user }}:{{ retronas_group }} {{ retronas_path }}/atarist/sidecart/* ================================================ FILE: ansible/templates/install_atarist-sidecart/atarist-sidecart-mirrordb.sh.j2 ================================================ #!/bin/bash # grab a local copy of the the sidecart db BASE_URL=http://ataristdb.sidecart.xyz DBDIR={{ base_path }}/sidecart/db WAIT=1 _dlfile() { [ -f ${1}.csv ] && rm ${1}.csv wget -c -nc -nH -x "${BASE_URL}/${1}" } # Update db first {{ retronas_root }}/scripts/atarist-sidecart-updatedb.sh # Process Floppies DB cd {{ base_path }}/floppies for ENTRY in $(ls ${DBDIR}) do for ITEM in $(cat "${DBDIR}/${ENTRY}" | awk -F';' '{print $6}' | sed 's/"//g' | sed 's/\r$//' ) do _dlfile $ITEM sleep ${WAIT} done done # Process ROMs json data cd /tmp _dlfile https://raw.githubusercontent.com/diegoparrilla/atarist-sidecart-raspberry-pico/main/roms/roms.json # dl ROMs cd {{ base_path }}/roms for URL in $(cat /tmp/roms.json | jq -r '.[].url') do _dlfile $ITEM sleep ${WAIT} done [ -f /tmp/roms.json ] && rm -f /tmp/roms.json chown -R {{ retronas_user }}:{{ retronas_group }} {{ base_path }} ================================================ FILE: ansible/templates/install_atarist-sidecart/atarist-sidecart-updatedb.sh.j2 ================================================ #!/bin/bash # grab a local copy of the the sidecart db BASE_URL=http://ataristdb.sidecart.xyz OUTPUTDIR={{ base_path }}/sidecart/db cd $OUTPUTDIR _dlfile() { [ -f ${1}.csv ] && rm ${1}.csv wget -c -w1 "${BASE_URL}/db/${1}" } for LETTER in {a..z} do _dlfile ${LETTER}.csv done for NUMBER in {0..9} do _dlfile ${NUMBER}.csv done chown -R {{ retronas_user }}:{{ retronas_group }} {{ retronas_path }}/atarist/db ================================================ FILE: ansible/templates/install_atarist-sidecart/index.html.j2 ================================================ sidecart

Sidecart - Atari ST

Configurator Settings

Option Setting
FLOPPY_DB_URLhttp://retronas/files/atarist/sidecart
ROMS_YAML_URLhttp://retronas/files/atarist/sidecart/roms.json

Paths

================================================ FILE: ansible/templates/install_atarist-sidecart/retronas_atarist.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. comment = atarist path = {{ retronas_path }}/atarist guest ok = no browseable = yes write list = {{ retronas_user }} writeable = yes valid users = {{ retronas_user }} create mask = 0775 directory mask = 0775 follow symlinks = yes wide links = yes ================================================ FILE: ansible/templates/install_cockpit-retronas/install_cockpit-retronas.sh.j2 ================================================ #!/bin/bash # # Clone down additional Cockpit Packages # # eventually combine with cockpit-packages RNTMP=/tmp/rn_cpack COCKPIT=/usr/share/cockpit # make out temp dir [ ! -d ${RNTMP} ] && mkdir ${RNTMP} function get_github { local ACCOUNT=$1 local REPO=$2 local FOLDER=$3 cd $RNTMP git clone https://github.com/${ACCOUNT}/${REPO}.git $FOLDER cd $FOLDER git checkout menu-changes } ### there'll be a better way to approach this function get_retronas { PACKAGES=( cockpit-retronas ) for PACKAGE in ${PACKAGES} do FOLDER=$(echo ${PACKAGE} | sed 's/^cockpit-//') get_github retronas $PACKAGE $FOLDER [ ! -d "${RNTMP}/${FOLDER}" ] && echo "Can't find my temp dir man, boooo!" && exit 1 cd "${RNTMP}/${FOLDER}" RELEASE=$(git tag | tail -n1) git checkout $RELEASE cd .. cp -R "${FOLDER}" "${COCKPIT}/" rm -Rf "${RNTMP}/${FOLDER}/" done } get_retronas ================================================ FILE: ansible/templates/install_cue2pops/install_cue2pops.sh.j2 ================================================ #!/bin/bash ### SETUP APP=cue2pops APPREPO=makefu LOCALDIR=/opt/${APP} LOCALSCRIPT=/usr/local/bin/${APP} if [ -f ${LOCALDIR}/${APP} ] then echo "Already compiled, nothing to do" exit fi cd /opt git clone https://github.com/${APPREPO}/${APP}-linux.git $APP cd ${APP} make if [ $? -eq 0 ] then ln -sf ${LOCALDIR}/${APP} $LOCALSCRIPT else echo "Compilation failed" fi ================================================ FILE: ansible/templates/install_deluge/auth.j2 ================================================ deluge:deluge:10 ================================================ FILE: ansible/templates/install_deluge/autoadd.conf.j2 ================================================ { "file": 2, "format": 1 }{ "next_id": 2, "watchdirs": { "1": { "abspath": "{{ retronas_path }}/bittorrent/auto-add", "add_paused": false, "add_paused_toggle": false, "append_extension": ".added", "append_extension_toggle": false, "auto_managed": true, "auto_managed_toggle": false, "copy_torrent": "{{ retronas_path }}/bittorrent/torrents", "copy_torrent_toggle": false, "delete_copy_torrent_toggle": false, "download_location": "{{ retronas_path }}/bittorrent/downloading", "download_location_toggle": false, "enabled": true, "label": "", "label_toggle": false, "max_connections": 0, "max_connections_toggle": false, "max_download_speed": 0, "max_download_speed_toggle": false, "max_upload_slots": 0, "max_upload_slots_toggle": false, "max_upload_speed": 0, "max_upload_speed_toggle": false, "move_completed": true, "move_completed_path": "{{ retronas_path }}/bittorrent/complete", "move_completed_toggle": false, "owner": "{{ retronas_user }}", "path": "{{ retronas_path }}/bittorrent/auto-add", "queue_to_top": true, "queue_to_top_toggle": false, "remove_at_ratio": false, "remove_at_ratio_toggle": false, "seed_mode": false, "stop_at_ratio": false, "stop_at_ratio_toggle": false, "stop_ratio": 0, "stop_ratio_toggle": false } } } ================================================ FILE: ansible/templates/install_deluge/core.conf.j2 ================================================ { "file": 1, "format": 1 }{ "add_paused": false, "allow_remote": true, "auto_manage_prefer_seeds": false, "auto_managed": true, "autoadd_enable": true, "autoadd_location": "{{ retronas_path }}/bittorrent/auto-add", "cache_expiry": 60, "cache_size": 512, "compact_allocation": false, "copy_torrent_file": true, "daemon_port": 58846, "del_copy_torrent_file": false, "dht": true, "dont_count_slow_torrents": false, "download_location": "{{ retronas_path }}/bittorrent/downloading", "download_location_paths_list": [], "enabled_plugins": [ "AutoAdd" ], "enc_in_policy": 1, "enc_level": 2, "enc_out_policy": 1, "enc_prefer_rc4": true, "geoip_db_location": "/usr/share/GeoIP/GeoIP.dat", "ignore_limits_on_local_network": true, "info_sent": 0.0, "listen_interface": "", "listen_ports": [ 46000, 46000 ], "listen_random_port": null, "listen_reuse_port": true, "listen_use_sys_port": false, "lsd": true, "max_active_downloading": -1, "max_active_limit": -1, "max_active_seeding": -1, "max_connections_global": -1, "max_connections_per_second": 50, "max_connections_per_torrent": -1, "max_download_speed": -1.0, "max_download_speed_per_torrent": -1, "max_half_open_connections": 50, "max_upload_slots_global": -1, "max_upload_slots_per_torrent": -1, "max_upload_speed": -1.0, "max_upload_speed_per_torrent": -1, "move_completed": true, "move_completed_path": "{{ retronas_path }}/bittorrent/complete", "move_completed_paths_list": [], "natpmp": true, "new_release_check": false, "outgoing_interface": "", "outgoing_ports": [ 44000, 45000 ], "path_chooser_accelerator_string": "Tab", "path_chooser_auto_complete_enabled": true, "path_chooser_max_popup_rows": 20, "path_chooser_show_chooser_button_on_localhost": true, "path_chooser_show_hidden_files": false, "peer_tos": "0x00", "plugins_location": "/usr/lib/python3/dist-packages/deluge/plugins", "pre_allocate_storage": true, "prioritize_first_last_pieces": false, "proxy": { "anonymous_mode": false, "force_proxy": false, "hostname": "", "password": "", "port": 2525, "proxy_hostnames": true, "proxy_peer_connections": true, "proxy_tracker_connections": true, "type": 0, "username": "" }, "queue_new_to_top": false, "random_outgoing_ports": true, "random_port": false, "rate_limit_ip_overhead": true, "remove_seed_at_ratio": false, "seed_time_limit": -1, "seed_time_ratio_limit": -1.0, "send_info": false, "sequential_download": false, "share_ratio_limit": -1.0, "shared": false, "stop_seed_at_ratio": true, "stop_seed_ratio": -1.0, "super_seeding": false, "torrentfiles_location": "{{ retronas_path }}/bittorrent/torrents", "upnp": true, "utpex": true } ================================================ FILE: ansible/templates/install_deluge/deluge-web.service.j2 ================================================ [Unit] Description=Deluge Bittorrent Client Web Interface After=network-online.target [Service] Type=simple User={{ retronas_user }} Group={{ retronas_user }} UMask=007 ExecStart=/usr/bin/deluge-web -d -c /var/lib/deluged/config Restart=on-failure [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_deluge/deluged.j2 ================================================ # Defaults for deluged initscript # sourced by /etc/init.d/deluged ENABLE_DELUGED=1 ================================================ FILE: ansible/templates/install_deluge/deluged.service.j2 ================================================ [Unit] Description=Deluge Daemon After=network-online.target [Service] Type=simple User={{ retronas_user }} Group={{ retronas_user }} UMask=007 ExecStart=/usr/bin/deluged --do-not-daemonize --config /var/lib/deluged/config Restart=on-failure [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_deluge/upgrade_deluge.sh.j2 ================================================ #!/bin/bash ENDPOINT=http://ftp.us.debian.org/debian/pool/main/d/deluge/ VERSION=${1:-2.1.2~dev0+20240910-5_all.deb} PACKAGES=( deluge-common deluge-web deluge-console deluged ) DTMPDIR=$(mktemp -d) DEBFILES=() cd $DTMPDIR for PACKAGE in ${PACKAGES[@]} do PNAME=${PACKAGE}_${VERSION} curl -s -O${PNAME} $ENDPOINT/${PNAME} DEBFILES+=" ./${PNAME}" done DEP=python3-legacy-cgi_2.6.2-1_all.deb curl -sO http://ftp.us.debian.org/debian/pool/main/p/python-legacy-cgi/${DEP} DEBFILES+=" ./${DEP}" apt update apt install -y ${DEBFILES} rm -f ${DEBFILES} sed -i 's/debian-deluged/{{ retronas_user }}/' /usr/lib/systemd/system/deluged.service sed -i 's/debian-deluged/{{ retronas_user }}/' /usr/lib/systemd/system/deluge-web.service #usermod -a -G debian-deluged {{ retronas_user }} chown {{ retronas_user }}:{{ retronas_group }} -R /var/lib/deluged/ systemctl daemon-reload sleep 2 systemctl stop deluge* systemctl restart deluge* ================================================ FILE: ansible/templates/install_disable-laptop-lid/retronas.conf.j2 ================================================ [Login] HandleLidSwitch=ignore HandleLidSwitchExternalPower=ignore HandleLidSwitchDocked=ignore IdleAction=ignore ================================================ FILE: ansible/templates/install_disc-image-creator/install_disc-image-creator.sh.j2 ================================================ #!/bin/bash ### SETUP APP=DiscImageCreator APPREPO=saramibreak APPLOW=$(echo $APP | tr [:upper:] [:lower:]) APPEXEC=${APP} ECCEDC=/opt/eccedc/EccEdc_linux.out DVDAUTH=/opt/dvdauth/DVDAuth_linux.out LOCALTMP=$( mktemp -d /tmp/${APPLOW}-XXXX ) LOCALFILE=/${LOCALTMP}/${APPLOW}.zip LOCALDIR=/opt/${APPLOW} LOCALSCRIPT=/usr/local/bin/${APPLOW} APPFILES=${LOCALDIR}/* PATTERN=*archive.*zip GITHRELS=https://github.com/${APPREPO}/${APP}/tags ### DISCOVERY #REDIRECT=$( curl -k -s ${GITHRELS} | awk -F '"' '{print $2}' ) RELEASE=$( curl -Lks "${GITHRELS}" | awk -F '"' /href.*${PATTERN}/'{print $4}' | head -n1 ) ### DOWNLOAD # -- Download [ ! -f ${LOCALFILE} ] && curl -k -L -o ${LOCALFILE} "https://github.com/${RELEASE}" [ $? -ne 0 ] && echo "Sadness getting ${APP}" && exit 1 ### LOCAL [ ! -d ${LOCALDIR} ] && /bin/mkdir ${LOCALDIR} || echo "Missing ${LOCALDIR}" ### UNPACK [ -f ${LOCALFILE} ] && /usr/bin/unzip -o ${LOCALFILE} -d ${LOCALTMP} || echo "Missing: ${LOCALFILE}" ### BUILD cd ${LOCALTMP}/${APP}-*/${APP} make ### INSTALL [ -f ${LOCALTMP}/${APP}-*/${APP}/${APPEXEC} ] && mv ${LOCALTMP}/${APP}-*/${APP}/${APPEXEC} ${LOCALDIR}/ cat << EOST > ${LOCALSCRIPT} #!/bin/bash cd ${LOCALDIR} ${LOCALDIR}/${APPEXEC} $* EOST ### PERMISSIONS chmod +x ${LOCALSCRIPT} chmod 755 ${LOCALSCRIPT} ### TOOL DEPS (EccEdc, DVDAuth) ln -sf ${ECCEDC} ${LOCALDIR}/ ln -sf ${DVDAUTH} ${LOCALDIR}/ ### ASSETS ASSET_DIR=${LOCALTMP}/${APP}-*/Release_ANSI cp ${ASSET_DIR}/*.txt ${LOCALDIR}/ cp -R ${ASSET_DIR}/Doc ${LOCALDIR}/ ### CLEANUP rm -rf ${LOCALTMP} ================================================ FILE: ansible/templates/install_dnsmasq-retro/dnsmasq-retro.service.j2 ================================================ [Unit] Description=DNS caching server retro. Requires=network.target Wants=nss-lookup.target After=network.target [Service] ExecStart=/usr/sbin/dnsmasq -k --conf-dir=/etc/dnsmasq.d/retro --pid-file=/var/run/dnsmasq-retro.pid RestartSec=10s TimeoutStartSec=8s Restart=on-failure [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_dnsmasq-retro/retro/dhcp-retro-ethernet.conf.j2 ================================================ interface={{ retronas_net_retro_interface }} dhcp-range={{ retronas_net_retro_interface }},{{ retronas_net_retro_dhcprange }} dhcp-option={{ retronas_net_retro_interface }},option:router,{{ retronas_net_retro_router }} dhcp-option={{ retronas_net_retro_interface }},option:ntp-server,{{ retronas_net_retro_ntp }} ================================================ FILE: ansible/templates/install_dnsmasq-retro/retro/dhcp-retro-wifi.conf.j2 ================================================ interface={{ retronas_net_wifi_interface }} dhcp-range={{ retronas_net_wifi_interface }},{{ retronas_net_wifi_dhcprange }} dhcp-option={{ retronas_net_wifi_interface }},option:router,{{ retronas_net_wifi_router }} dhcp-option={{ retronas_net_wifi_interface }},option:ntp-server,{{ retronas_net_wifi_ntp }} ================================================ FILE: ansible/templates/install_dnsmasq-retro/retro/dhcp.conf.j2 ================================================ dhcp-authoritative dhcp-leasefile=/tmp/dnsmasq-retro.leases dhcp-lease-max=50 ================================================ FILE: ansible/templates/install_dnsmasq-retro/retro/dns.conf.j2 ================================================ # google server={{ retronas_net_upstream_dns1 }} server={{ retronas_net_upstream_dns1 }} ================================================ FILE: ansible/templates/install_dnsmasq-retro/retro/dnsmasq.conf.j2 ================================================ user=root group=root bogus-priv domain-needed no-resolv all-servers expand-hosts domain=retro local=/retro/ log-queries no-poll ================================================ FILE: ansible/templates/install_dnsmasq-retro/retro/interfaces.conf.j2 ================================================ interface=lo bind-interfaces ================================================ FILE: ansible/templates/install_dnsmasq-retro/retro/ipv6.conf.j2 ================================================ listen-address=::1 ================================================ FILE: ansible/templates/install_dreampi/dreampi.conf.j2 ================================================ domain-needed bogus-priv server=46.101.91.123 server=209.50.50.129 no-resolv no-hosts cache-size=500 log-queries ================================================ FILE: ansible/templates/install_dreampi/install_dreampi.sh.j2 ================================================ #!/bin/bash set -e # based on https://github.com/Kazade/dreampi/issues/17 DPITMP=$(mktemp -d) # clone the repo and switch to the python3 branch cd $DPITMP git clone https://github.com/Kazade/dreampi.git cd dreampi git checkout python3 # add arch armhf dpkg --add-architecture armhf apt-get update # workaround for if a previous install was broken due to missing arch apt-get --fix-missing -y install # install dependancies dpkg -i arm/*.deb # pull python3 requirements curl -O https://raw.githubusercontent.com/sairuk/dreampi/master/requirements.txt if [ ! -f /usr/lib/python3*/EXTERNALLY-MANAGED ] then python3 -m pip install -r requirements.txt else apt-get install -y python3-serial python3-sh python3-iptables python3-miniupnpc # there are no system packages for this so ignore warning python3 -m pip install http-server-base --break-system-packages fi # install dreampi [ ! -d /usr/local/share/dreampi ] && mkdir /usr/local/share/dreampi cp -f *.py dial-tone.wav /usr/local/share/dreampi ln -sf /usr/local/share/dreampi/dreampi.py /usr/local/bin/dreampi chown -R root:root /usr/local/share/dreampi/ # create startup scripts cp -f etc/init.d/dreampi /etc/init.d/ cp -f etc/systemd/system/dreampi.service /etc/systemd/system/ ================================================ FILE: ansible/templates/install_dvdauth/install_dvdauth.sh.j2 ================================================ #!/bin/bash ### SETUP APP=DVDAuth APPREPO=saramibreak APPLOW=$(echo $APP | tr [:upper:] [:lower:]) APPEXEC=${APP}.out LOCALTMP=$( mktemp -d /tmp/${APPLOW}-XXXX ) LOCALFILE=${LOCALTMP}/${APPLOW}.zip LOCALDIR=/opt/${APPLOW} LOCALSCRIPT=/usr/local/bin/${APPLOW} APPFILES=${LOCALDIR}/* ### DISCOVERY cd ${LOCALTMP} git clone https://github.com/${APPREPO}/${APP} cd ${LOCALTMP}/${APP} RELEASE=$(git tag | tail -n1) ### LOCAL [ ! -d ${LOCALDIR} ] && /bin/mkdir ${LOCALDIR} || echo "Missing ${LOCALDIR}" ### BUILD cd ${LOCALTMP}/${APP}/${APP} #git checkout ${RELEASE} ### can't do this yet, linux makefile isn't in a release make ### INSTALL [ -f ${LOCALTMP}/${APP}/${APP}/${APPEXEC} ] && mv ${LOCALTMP}/${APP}/${APP}/${APPEXEC} ${LOCALDIR}/ cat << EOST > ${LOCALSCRIPT} #!/bin/bash cd ${LOCALDIR} ${LOCALDIR}/${APPEXEC} \$* EOST ### PERMISSIONS chmod +x ${LOCALSCRIPT} chmod 755 ${LOCALSCRIPT} ### CLEANUP rm -rf ${LOCALTMP} ================================================ FILE: ansible/templates/install_eccedc/install_eccedc.sh.j2 ================================================ #!/bin/bash ### SETUP APP=EccEdc APPREPO=saramibreak APPLOW=$(echo $APP | tr [:upper:] [:lower:]) APPEXEC=${APP}.out LOCALTMP=$( mktemp -d /tmp/${APPLOW}-XXXX ) LOCALFILE=${LOCALTMP}/${APPLOW}.zip LOCALDIR=/opt/${APPLOW} LOCALSCRIPT=/usr/local/bin/${APPLOW} APPFILES=${LOCALDIR}/* PATTERN=*archive.*zip GITHRELS=https://github.com/${APPREPO}/${APP}/tags ### DISCOVERY #REDIRECT=$( curl -k -s ${GITHRELS} | awk -F '"' '{print $2}' ) RELEASE=$( curl -Lks "${GITHRELS}" | awk -F '"' /href.*${PATTERN}/'{print $4}' | head -n1 ) ### DOWNLOAD # -- Download [ ! -f ${LOCALFILE} ] && curl -k -L -o ${LOCALFILE} "https://github.com/${RELEASE}" [ $? -ne 0 ] && echo "Sadness getting ${APP}" && exit 1 ### LOCAL [ ! -d ${LOCALDIR} ] && /bin/mkdir ${LOCALDIR} || echo "Missing ${LOCALDIR}" ### UNPACK [ -f ${LOCALFILE} ] && /usr/bin/unzip -o ${LOCALFILE} -d ${LOCALTMP} || echo "Missing: ${LOCALFILE}" ### BUILD cd ${LOCALTMP}/${APP}-*/${APP} make ### INSTALL [ -f ${LOCALTMP}/${APP}-*/${APP}/${APPEXEC} ] && mv ${LOCALTMP}/${APP}-*/${APP}/${APPEXEC} ${LOCALDIR}/ cat << EOST > ${LOCALSCRIPT} #!/bin/bash cd ${LOCALDIR} ${LOCALDIR}/${APPEXEC} $* EOST ### PERMISSIONS chmod +x ${LOCALSCRIPT} chmod 755 ${LOCALSCRIPT} ### CLEANUP rm ${LOCALFILE} rm -rf ${LOCALTMP} ================================================ FILE: ansible/templates/install_etherdfs/etherdfs.service.j2 ================================================ [Unit] Description=EtherDFS lightweight file server for MS-DOS After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] Umask=0000 User={{ retronas_user }} ExecStart={{ retronas_root }}/bin/ethersrv-linux -f {{ retronas_etherdfs_interface }} {{ retronas_path}}/dos Restart=on-failure RestartSec=1 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_etherdfs/install_etherdfs.sh.j2 ================================================ #!/bin/bash SRCDIR="{{ retronas_root }}/src" BINDIR="{{ retronas_root }}/bin" echo "Configuring build directories..." rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Downloading EtherDFS source..." git clone 'https://github.com/BrianHoldsworth/etherdfs-server.git' cd etherdfs-server make echo "Moving binary to bindir..." mv -vf ethersrv-linux "${BINDIR}"/ echo "Setting binary sticky bit..." chmod -v u+s "${BINDIR}"/ethersrv-linux echo "Cleaning up..." rm -rf "${SRCDIR}" echo 'All done!' ================================================ FILE: ansible/templates/install_etherdfs/retronas_dos.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. comment = dos path = {{ retronas_path }}/dos guest ok = no browseable = yes write list = {{ retronas_user }} writeable = yes valid users = {{ retronas_user }} create mask = 0775 directory mask = 0775 follow symlinks = yes wide links = yes strict sync = no sync always = yes ================================================ FILE: ansible/templates/install_ethflopd/ethflopd.service.j2 ================================================ [Unit] Description=ethflopd L2 floppy emulator server for MS-DOS After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] Umask=0000 User={{ retronas_user }} ExecStart={{ retronas_root }}/bin/ethflopd -f {{ retronas_etherdfs_interface }} {{ retronas_path}}/dos Restart=on-failure RestartSec=1 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_ethflopd/install_ethflopd.sh.j2 ================================================ #!/bin/bash SRCDIR="{{ retronas_root }}/src" BINDIR="{{ retronas_root }}/bin" APPNAME=ethflopd VERSION=20240916 echo "Configuring build directories..." rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}/${APPNAME}" cd "${SRCDIR}" echo "Downloading ethflopd source..." curl -L -o ${APPNAME}.tar.gz https://master.dl.sourceforge.net/project/ethflop/ethflopd%20%28server%29/${VERSION}/ethflopd-${VERSION}-src.tar.gz tar -xvf ${APPNAME}.tar.gz -C ${APPNAME} cd ${APPNAME} [ ! -f Makefile.linux ] && echo "Makefile not found, cannot build" && exit 1 make -f Makefile.linux echo "Moving binary to bindir..." mv -vf ${APPNAME} "${BINDIR}"/ echo "Setting binary sticky bit..." chmod -v u+s "${BINDIR}"/${APPNAME} echo "Cleaning up..." rm -rf "${SRCDIR}" echo 'All done!' ================================================ FILE: ansible/templates/install_extract-xiso/install_extract-xiso.sh.j2 ================================================ #!/bin/bash set -u RN_BIN=/usr/local/bin/ APP=extract-xiso OUTPATH=/tmp/$APP REPO=https://github.com/XboxDev/extract-xiso.git XC=$APP function _log { echo "$1" } ### REQUIREMENTS REQFAIL=0 [ $REQFAIL -ne 0 ] && _log "Requirements failed, see previous errors" && exit $REQFAIL ### CLONE RESULT="FAILURE" _log "Attempting to clone ${REPO}" [ ! -d ] && mkdir -p $OUTPATH cd $OUTPATH git clone $REPO ### COMPILE cd $APP mkdir build cd build cmake .. # MAKE make [ -x ${XC} ] && mv ${XC} "${RN_BIN}/" chmod 755 ${RN_BIN}/${XC} # CLEAN UP rm -Rf ${OUTPATH}/ ================================================ FILE: ansible/templates/install_far2l/install_far2l.sh.j2 ================================================ #!/bin/bash set -u SRCDIR="{{ retronas_root }}/src" BINDIR="/usr/local/bin" REPO=https://github.com/elfmz/far2l echo "Configuring build directories..." [ -d ${SRCDIR} ] && rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Downloading git source ..." git clone $REPO cd "${SRCDIR}/$(basename $REPO .git)" git checkout $(git tag | tail -n1) echo "Building" mkdir _build cd _build cmake -DUSEWX=no -DCMAKE_BUILD_TYPE=Release .. cmake --build . -j$(nproc --all) sudo cmake --install . echo "Cleaning up..." [ -d ${SRCDIR} ] && rm -rf "${SRCDIR}" echo "All done!" ================================================ FILE: ansible/templates/install_fenrir-ode-webserver/fenrir-ode-webserver.service.j2 ================================================ [Unit] Description={{ my_name }} After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] User={{ retronas_user }} ExecStart={{ fenrir_ode_bin }} --dir "{{ fenrir_ode_path }}" --port {{ fenrir_ode_port }} Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_fenrir-ode-webserver/install_fenrir-ode-webserver.sh.j2 ================================================ #!/bin/bash set -u RN_BIN=/usr/local/bin/ APP=webserver REPO=https://github.com/Fenrir-ode/${APP}.git OUTPATH=/tmp function _log { echo "$1" } ### REQUIREMENTS REQFAIL=0 #[ ! -x /usr/bin/gmake ] && _log "GMAKE not found" && REQFAIL=1 [ $REQFAIL -ne 0 ] && _log "Requirements failed, see previous errors" && exit $REQFAIL cd $OUTPATH if [ ! -f ${OUTPATH}/${APP}/.git/config ] then git clone $REPO else cd ${OUTPATH}/${APP} git pull fi cd ${OUTPATH}/${APP} git submodule init git submodule update --recursive mkdir build cd build cmake .. make mv ${OUTPATH}/${APP}/build/FenrirServer $RN_BIN/ # CLEAN UP #rm -Rf ${OUTPATH}/${APP} ================================================ FILE: ansible/templates/install_firewalld/workarounds/clear-python-bytecode.j2 ================================================ #!/bin/bash set -u # # firewalld will not start if corrupted bytecode exists for a dependent library # normally this is a none issue with standard python apps but for a firewall it is # a fairly bad scenario # # may be caused by a loss of power to a device # # clear out all bytecode from the python lib dir # PYTHON_LIBDIRS=( /usr/lib/python*/ /usr/local/lib/python*/ ) for PYTHON_LIBDIR in ${PYTHON_LIBDIRS[@]} do find $PYTHON_LIBDIR -type f -regex ".*\.pyc$" -exec rm "{}" \; done ================================================ FILE: ansible/templates/install_firewalld/workarounds/override.conf.j2 ================================================ # /etc/systemd/system/firewalld.service.d/override.conf [Service] ExecStartPre=-/usr/local/sbin/clear-python-bytecode ExecStart= ExecStart=/usr/sbin/firewalld --nofork --nopid ================================================ FILE: ansible/templates/install_firewalld-zones/policies/retro_to_modern.xml.j2 ================================================ ================================================ FILE: ansible/templates/install_firewalld-zones/services/ps3netsrv.xml.j2 ================================================ ================================================ FILE: ansible/templates/install_firewalld-zones/services/samba-modern.xml.j2 ================================================ Samba Modern Only allows 445/tcp ================================================ FILE: ansible/templates/install_firewalld-zones/zones/modern.xml.j2 ================================================ Modern Connection out to your main Modern network ================================================ FILE: ansible/templates/install_firewalld-zones/zones/retro.xml.j2 ================================================ retro retro device zone ================================================ FILE: ansible/templates/install_flippydrive/flippydrive.service.j2 ================================================ [Unit] Description=Flippydrive Network Service Documentation=https://docs.flippydrive.com/network.html Requires=network-online.target After=network-online.target [Service] User={{ retronas_user }} Type=simple ExecStart=/opt/flippydrive/flippydrive.sh TimeoutStopSec=10 Restart=on-failure [Install] WantedBy=default.target ================================================ FILE: ansible/templates/install_flippydrive/flippydrive.sh.j2 ================================================ #!/bin/bash cd /opt/flippydrive ARCH=$(uname -m) case $ARCH in x86_64) ARCH=amd64 ;; *) echo "Unsupported architecture: $ARCH" exit 1 esac LASTREL=$(ls -rt flippy_cli_*_linux_${ARCH} | tail -n1) if [ ! -z $LASTREL ] then [ ! -x $LASTREL ] && chmod +x $LASTREL ./$LASTREL {{ retronas_path }}/roms/nintendo/gamecube/iso fi ================================================ FILE: ansible/templates/install_flippydrive/install_flippydrive.sh.j2 ================================================ #!/bin/bash # Set world readable/executable umask umask 0022 SRCDIR="/opt/flippydrive" cd "${SRCDIR}" RELEASE=$( curl -kLs https://api.github.com/repos/OffBroadway/flippydrive-assets/releases | jq -r ".[0].assets | map(select(.name | match (\"flippy_cli_.*linux\")))[-1] | .browser_download_url" ) [ -z "$RELEASE" ] && echo "Couldn't get release name name" && exit 1 echo "Downloading $RELEASE" cd /tmp curl -OJL "${RELEASE}" unzip flippy_cli_*.zip -d $SRCDIR rm -f /tmp/flippy_cli_*.zip ================================================ FILE: ansible/templates/install_freestation/retronas_freestation_cifs.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. comment = freestation path = {{ retronas_path }}/freestation guest ok = no browseable = yes write list = {{ retronas_user }} writeable = yes valid users = {{ retronas_user }} create mask = 0775 directory mask = 0775 follow symlinks = yes wide links = yes strict sync = no ================================================ FILE: ansible/templates/install_freestation/retronas_freestation_nfs.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. /data/retronas/freestation *(rw,async,fsid=75c75da3367aebdeb62b3c9ad16cae53,all_squash,anonuid=1001,anongid=1001,no_subtree_check) ================================================ FILE: ansible/templates/install_fsp/fspd.conf.j2 ================================================ ## Config autogenerated by RetroNAS # FSP is UDP only. Will not conflict with FTP on TCP/21 # However running on 2121 for unprivileged RetroNAS user port 2121 # Listen on all IPs listenaddress 0.0.0.0 # MTU 1500 - 40 byte IP/UDP overhead packetsize 1460 # Top level dir for anon connections homedir {{ retronas_path }}/gamecube/swiss homedir_restricted no tmpdir tmp pidlogname /tmp/fspd.pid grabcommand on vercommand on #dircache 100 #statcache 30 #statcache_timeout 20 #filecache 30 #setuid {{ retronas_user }} #setgid {{ retronas_group }} umask 0002 # Don't background. systemd needs this daemonize off restricted off reverse_name off # Allow writes for save file push read_only off debug off ================================================ FILE: ansible/templates/install_fsp/fspd.service.j2 ================================================ [Unit] Description=FSP File Service Protocol Documentation=http://fsp.sourceforge.net Requires=network-online.target After=network-online.target [Service] User={{ retronas_user }} Type=simple Environment="PATH={{ retronas_root }}/bin/fsp:$PATH" ExecStart={{ retronas_root }}/bin/fsp/bin/fspd TimeoutStopSec=10 Restart=on-failure [Install] WantedBy=default.target ================================================ FILE: ansible/templates/install_fsp/install_fsp.sh.j2 ================================================ #!/bin/bash # Set world readable/executable umask umask 0022 # Set the install dir IDIR="{{ retronas_root }}/bin/fsp" mkdir -p "${IDIR}/etc" # make/clean the source build location mkdir -p "{{ retronas_root }}/src" cd "{{ retronas_root }}/src" rm -rf fsp # Clone the source code from SourceForge git clone https://git.code.sf.net/p/fsp/code fsp cd fsp # Build and install as per fsp documentation scons prefix="${IDIR}" install ================================================ FILE: ansible/templates/install_gogrepo/gogrepo-wrapper.sh.j2 ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh ## If this is run as root, switch to our RetroNAS user ## Manifests and cookies stored in ~/.gogrepo CLEAR ## Script Globals RNUDIR=$( getent passwd | grep ^${OLDRNUSER}\: | awk -F ':' '{print $6}' ) RNUGOGREPO=$RNUDIR/.gogrepo GOGREPO="/opt/retronas/bin/gogrepo/gogrepo.py" GOGDEPO="{{ retronas_path }}/gog" GOGMAN=${RNUDIR}/.gogrepo/gog-manifest.dat GOGGAME="" GOGOS="" OSLIST=() GAMELIST=() ## New install # GOG Operating System [ -z "$OLDGOGOS" ] && OLDGOGOS="none" [ -z "$OLDGOGLANG" ] && OLDGOGLANG="none" NEWGOGOS="windows" NEWGOGLANG="en" ## Make the main directory [ ! -d $RNUGOGREPO ] && mkdir -p $RNUGOGREPO cd $RNUGOGREPO function header { echo "" echo "$1..." echo "" } function update { header "Refreshing GOG manifest..." DROP_ROOT $GOGREPO update ${@} } function login { header "Initiating GOG login" header "Have your GOG username and password ready" DROP_ROOT $GOGREPO login } function download { header "Downloading/updating games..." DROP_ROOT $GOGREPO download ${@} "${GOGDEPO}" } function get_os_list { OS_LIST=( "windows" "mac" "linux" "windows mac" "windows linux" "mac linux" "windows mac linux" "quit" ) } function get_lang_list { LANG_LIST=( "ar" "bl" "br" "cn" "cz" "da" "de" "en" "es" "fi" "fr" "gk" "hu" "it" "jp" "ko" "nl" "no" "pl" "pt" "ro" "ru" "sb" "sk" "sv" "tr" "quit" ) } function get_games_list { GAME_LIST=$(grep "'title':" $GOGMAN | awk -F "'" '{print $4}' | sort) } function select_os { header "Select the OS you would like to use..." get_os_list PS3="Enter a number (current: ${OLDGOGOS}): " select ITEM in "${OS_LIST[@]}" do if [ ! -z "$ITEM" ] then if [ "$ITEM" != "quit" ] then NEWGOGOS="$ITEM" fi break else echo "Invalid option" fi done if [ ! -z "$NEWGOGOS" ] then echo "Updating GOG settings to $NEWGOGOS" # update gog setting sed -i '/retronas_gog_os:/d' "${ANCFG}" echo "retronas_gog_os: \"${NEWGOGOS}\"" >> "${ANCFG}" fi } function select_lang { header "Select the language you would like to use..." get_lang_list PS3="Enter a number (current: ${OLDGOGLANG}): " select KEY in "${LANG_LIST[@]}" do if [ ! -z "${KEY}" ] then if [ "${KEY}" != "quit" ] then NEWGOGLANG="${KEY}" fi break else echo "Invalid option" fi done if [ ! -z "$NEWGOGLANG" ] then echo "Updating GOG settings to $NEWGOGLANG" # update gog setting sed -i '/retronas_gog_lang:/d' "${ANCFG}" echo "retronas_gog_lang: \"${NEWGOGLANG}\"" >> "${ANCFG}" fi } function gameslist { PS3="Enter a number: " get_games_list select ITEM in $GAME_LIST do if [ ! -z $ITEM ] then GOGGAME=$ITEM break else echo "Invalid option" fi done } function _usage { cat << USAGE [ GOGREPO RetroNAS Wrapper ] $0 login|import-cookies|select-os|select-lang|update-skip-known|update-download-single|download-all|update-download login log in to gog import-cookies import a cookies file in LWP/Mozilla formats select-os select the operating systems you want to target select-lang select the language you want to target update-skip-known update all metadata update-download-single update and download a single title download-all download all know titles update-download update and download all USAGE exit } case $1 in login) # login login ;; import-cookies) # import cookies import_cookies ;; update-skip-known) # sync games list update -os ${OLDGOGOS} ;; select-auth) select_auth ;; select-os) select_os ;; select-lang) select_lang ;; update-download-single) # download 1 game gameslist update -os ${OLDGOGOS} -id ${GOGGAME} download -id ${GOGGAME} ;; download-all) # download all games download ;; update-download) # sync and download update -os ${GOGOS} download ;; *) _usage ;; esac PAUSE exit 0 ================================================ FILE: ansible/templates/install_gogrepo/gogrepo_download.sh.j2 ================================================ #!/bin/bash echo "" echo "Downloading/updating games..." echo "" mkdir -p ~/.gogrepo 2>/dev/null cd ~/.gogrepo /opt/retronas/bin/gogrepo/gogrepo.py download ${@} "{{ retronas_path }}/gog" ================================================ FILE: ansible/templates/install_gogrepo/gogrepo_import-cookies.sh.j2 ================================================ #!/bin/bash echo "" echo "Importing GOG Cookies" echo "" set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh ## If this is run as root, switch to our RetroNAS user ## Manifests and cookies stored in ~/.gogrepo CLEAR GOGREPODIR=/home/{{ retronas_user }}/.gogrepo FILES=( gog-cookies.dat cookies-gog-com.txt ) [ ! -f $GOGREPODIR ] && mkdir -p $GOGREPODIR 2>/dev/null cd $GOGREPODIR for FILE in ${FILES[@]} do COOKIES="${OLDRNPATH}/config/${FILE}" echo -n "Looking for $COOKIES" if [ -f "${COOKIES}" ] then DROP_ROOT \ echo "... Found, importing into ${GOGREPODIR}"; \ mv -f "${COOKIES}" "${GOGREPODIR}/gog-cookies.dat"; \ chmod 640 "${GOGREPODIR}/gog-cookies.dat"; \ break else echo "... Not Found" fi done chown -R {{ retronas_user }}:{{ retronas_group }} ${GOGREPODIR} ================================================ FILE: ansible/templates/install_gogrepo/gogrepo_login.sh.j2 ================================================ #!/bin/bash echo "" echo "Initiating GOG login" echo "Have your GOG username and password ready" echo "" mkdir -p ~/.gogrepo 2>/dev/null cd ~/.gogrepo /opt/retronas/bin/gogrepo/gogrepo.py login ================================================ FILE: ansible/templates/install_gogrepo/gogrepo_update.sh.j2 ================================================ #!/bin/bash echo "" echo "Refreshing GOG manifest..." echo "" mkdir -p ~/.gogrepo 2>/dev/null cd ~/.gogrepo /opt/retronas/bin/gogrepo/gogrepo.py update ${@} ================================================ FILE: ansible/templates/install_hb-store-cdn/config.ini.j2 ================================================ host={{ ansible_default_ipv4.address }} port=6449 basePath={{ retronas_path }}/ps4/{{ my_name }} binVersion=0.00 ================================================ FILE: ansible/templates/install_hb-store-cdn/hb-store-cdn-check.sh.j2 ================================================ #!/bin/bash STATUS=$(sudo -u {{ retronas_user }} {{ retronas_root }}/bin/{{ my_name }}/hb-store-cdn-cli-server check-bin | grep "Update is required") if [ ! -z "${STATUS}" ] then sudo -u {{ retronas_user }} {{ retronas_root }}/bin/{{ my_name }}/hb-store-cdn-cli-server download-bin systemctl restart {{ my_name }}.service fi ================================================ FILE: ansible/templates/install_hb-store-cdn/hb-store-cdn.cron.j2 ================================================ 0 */12 * * * {{ retronas_root }}/bin/{{ my_name }}/hb-store-cdn-check.sh ================================================ FILE: ansible/templates/install_hb-store-cdn/hb-store-cdn.service.j2 ================================================ [Unit] Description=Homebrew Store for PlayStation4 After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] User={{ retronas_user }} WorkingDirectory={{ retronas_root }}/bin/{{ my_name }} ExecStart={{ retronas_root }}/bin/{{ my_name }}/hb-store-cdn-cli-server start Restart=on-failure RestartSec=1 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_hb-store-cdn/install_hb-store-cdn.sh.j2 ================================================ #!/bin/bash APPNAME="{{ my_name }}" SRCDIR="{{ retronas_root }}/src" BINDIR="{{ retronas_root }}/bin/$APPNAME" REPO=https://github.com/Gkiokan/hb-store-cdn-cli-server.git # Use the binary release #RELEASE=$( curl -kLs https://api.github.com/repos/Gkiokan/hb-store-cdn-cli-server/releases | jq -r ".[0].assets | map(select(.name | match (\"hb-store-cdn-cli-server-linux\")))[] | .browser_download_url" ) # #if [ ! -z "${RELEASE}" ] #then # DEST="${BINDIR}/hb-store-cdn-cli-server" # curl -JLo"${DEST}" "${RELEASE}" # chmod +x "${DEST}" #fi [ ! -x /usr/bin/npm ] && echo "npm could not be found" && exit 1 # max version we can build with is node18 npm install -g node@18.20.8 npm install -g npm@10.8.2 echo "Configuring build directories..." rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Cloning ..." git clone $REPO $APPNAME cd $APPNAME echo "Install Dependencies" /usr/local/bin/npm install /usr/local/bin/npm install pkg -g echo "Set arch (default x86_64)" MACH=$(uname -m) case $MACH in aarch64|arm*) ARCH=linux-arm ;; *) ARCH=linux ;; esac echo "Building" /usr/local/bin/npm run build:$ARCH BUILT=release/hb-store-cdn-cli-server [ ! -f $BUILT ] && echo "Build failed" && exit 1 echo "Moving binary to RetroNAS bin dir..." mkdir -p "${BINDIR}" 2>/dev/null chmod +x $BUILT mv -vf $BUILT "${BINDIR}"/ echo "Cleaning up..." rm -rf "${SRCDIR}" chown -R {{ retronas_user }}:{{ retronas_group }} "${BINDIR}"/ echo "All done!" ================================================ FILE: ansible/templates/install_hdldump/install_hdldump.sh.j2 ================================================ #!/bin/bash set -u RN_BIN=/usr/local/bin/ APP=hdl-dump REPO=https://github.com/ps2homebrew/${APP}.git OUTPATH=/tmp function _log { echo "$1" } ### REQUIREMENTS REQFAIL=0 #[ ! -x /usr/bin/gmake ] && _log "GMAKE not found" && REQFAIL=1 [ $REQFAIL -ne 0 ] && _log "Requirements failed, see previous errors" && exit $REQFAIL cd $OUTPATH if [ ! -f ${OUTPATH}/${APP}/.git/config ] then git clone $REPO else cd ${OUTPATH}/${APP} git pull fi cd ${OUTPATH}/${APP} make RELEASE=yes mv ${OUTPATH}/${APP}/hdl_dump $RN_BIN/ # CLEAN UP rm -Rf ${OUTPATH}/${APP} ================================================ FILE: ansible/templates/install_hdparm/hdparm-manager.sh.j2 ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh #CHECK_ROOT HDPARM=/usr/sbin/hdparm SERVICE="hdparm" SELECTION={{ retronas_path }}/config/hdparm-manager-drive # check for previous selection or default to /dev/sda if [ -f $SELECTION ] then DRIVE=$(cat $SELECTION) else DRIVE=/dev/sda fi function drive_selector { PS3="Select a drive ($DRIVE): " select DRIVE in $(lsblk --all --list --noheadings | awk '/disk/{print "/dev/"$1}') quit do [ $DRIVE == "quit" ] && exit echo $DRIVE > $SELECTION exit done } case $(basename $0 .sh) in hdparm-manager-drive-selector) drive_selector ;; hdparm-manager-disable-apm) sudo ${HDPARM} -B 255 $DRIVE ;; hdparm-manager-disable-standby) sudo ${HDPARM} -S 0 $DRIVE ;; hdparm-manager-start-service) # Start Service sudo systemctl reset-failed ${SERVICE}.service sudo systemctl restart ${SERVICE}.timer sudo systemctl enable ${SERVICE}.timer sudo systemctl restart ${SERVICE}.service ;; hdparm-manager-query-service) # Start Service sudo systemctl status ${SERVICE}.timer sudo systemctl status ${SERVICE}.service ;; hdparm-manager-stop-service) # Start Service sudo systemctl stop ${SERVICE}.timer sudo systemctl stop ${SERVICE}.service sudo systemctl disable ${SERVICE}.timer sudo systemctl disable ${SERVICE}.service ;; *) exit 1 ;; esac ================================================ FILE: ansible/templates/install_hdparm/hdparm.service.j2 ================================================ [Unit] Description=HDPARM HDD No Sleep [Service] Type=simple ExecStart={{ retronas_root }}/scripts/hdparm.sh TimeoutStopSec=10 Restart=no [Install] WantedBy=default.target ================================================ FILE: ansible/templates/install_hdparm/hdparm.sh.j2 ================================================ #!/bin/bash # # Prevent a disk going to sleep by reading a sector # TRIES=0 RANDSECTOR=1 error() { >&2 echo "$1" } log() { echo "$1" } # check for config file [ ! -f {{ retronas_path }}/config/hdparm-manager-drive ] && error "Failed to find config file" && exit 1 function set_sector() { local MAXSECTOR=$1 RANDSECTOR=$(shuf -i 1-${MAXSECTOR} -n 1 2>&1) # test to see if the above was successful, can fail on systems without lfs compiled # see https://www.gnu.org/software/coreutils/faq/coreutils-faq.html if [ $? -ne 0 ] then error "Failed to determine randsec at $MAXSECTOR ($TRIES/$RETRY)" [ $TRIES -eq 3 ] && RANDSECTOR=1 && exit MAXSECTOR=$((${MAXSECTOR}/2)) TRIES=$((${TRIES}+1)) set_sector $MAXSECTOR fi } # list the drives that need to be punished NOSLEEP=( $(cat {{ retronas_path }}/config/hdparm-manager-drive) ) # REQUIREMENTS REQFAIL=0 [ $REQFAIL -ne 0 ] && error "Failed requiements, check previous messages" && exit $REQFAIL for DISK in ${NOSLEEP[@]} do [ ! -r $DISK ] && error "$DISK is not readable, exiting" && exit 1 BLOCKDEV=$(echo $DISK | sed 's/\/dev\///') MAXSECTOR=$(cat /sys/class/block/${BLOCKDEV}/size) [ -z $MAXSECTOR ] && error "Cannot obtain MAXSECTORS from $DISK, exiting" && exit 1 set_sector $MAXSECTOR if [ ! -z "${RANDSECTOR}" ] then log "Reading ${RANDSECTOR} (max:${MAXSECTOR}) from ${DISK}" hdparm --read-sector $RANDSECTOR $DISK &>/dev/null else error "Failed to obtain a random sector is the drive available?" fi done ================================================ FILE: ansible/templates/install_hdparm/hdparm.timer.j2 ================================================ [Unit] Description=Run HDPARM HDD No Sleep [Timer] OnBootSec=3m OnUnitActiveSec=3m RandomizedDelaySec=2m [Install] WantedBy=timers.target ================================================ FILE: ansible/templates/install_hfsutils/install_hfsutils.sh.j2 ================================================ #!/bin/bash set -u ## we are using a fork because trixie doesn't have a package # see: https://tracker.debian.org/pkg/hfsutils REPO=hfsutils OWNER=jepler BRANCH=misc-fixes SRCDIR="{{ retronas_root }}/src" echo "Configuring build directories..." rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Downloading hfsutils source code..." git clone https://github.com/$OWNER/$REPO cd $REPO [ ! -z $BRANCH ] && git checkout $BRANCH echo "Building libhfs" ## libhfs cd libhfs autoconf ./configure make cd .. echo "Building hfsutils" ## hfsutils autoconf ./configure make echo "Installing hfsutils" make install echo "Cleaning up" rm -rf $SRCDIR ================================================ FILE: ansible/templates/install_hostapd/hostapd-dnsmasq.conf.j2 ================================================ dhcp-range={{ retronas_net_wifi_interface }},{{ retronas_net_wifi_dhcprange }} dhcp-option={{ retronas_net_wifi_interface }},option:router,{{ retronas_net_wifi_router }} dhcp-option={{ retronas_net_wifi_interface }},option:ntp-server,{{ retronas_net_wifi_ntp }} #dhcp-option={{ retronas_net_wifi_interface }},19,0 # ip-forwarding off ================================================ FILE: ansible/templates/install_hostapd/hostapd-retronas.conf.j2 ================================================ interface={{ retronas_net_wifi_interface }} ssid={{ retronas_net_wifi_ssid }} channel={{ retronas_net_wifi_channel }} hw_mode={{ retronas_net_wifi_hwmode }} country_code={{ retronas_net_wifi_countrycode }} auth_algs=1 ignore_broadcast_ssid=0 wpa=2 wpa_key_mgmt=WPA-PSK wpa_pairwise=TKIP CCMP rsn_pairwise=CCMP wpa_passphrase={{ retronas_wifi_password.stdout }} ieee80211d=1 ieee80211n=1 ctrl_interface=/var/run/hostapd ctrl_interface_group=0 # attempts to fix disassociation of c64 wifi disassoc_low_ack=0 beacon_int=100 dtim_period=2 wpa_ptk_rekey=600 ================================================ FILE: ansible/templates/install_hostapd/hostapd-retronas.service.j2 ================================================ [Unit] Description=Access point and authentication server for retronas Documentation=man:hostapd(8) Requires=network.target After=network.target StartLimitIntervalSec=2 StartLimitBurst=5 BindsTo=sys-subsystem-net-devices-{{ retronas_net_wifi_interface }}.device After=sys-subsystem-net-devices-{{ retronas_net_wifi_interface }}.device [Service] Type=forking ExecStart=/usr/sbin/hostapd -B -P /run/hostapd-retronas.pid /etc/hostapd/hostapd-retronas.conf RestartSec=10s TimeoutStartSec=8s Restart=on-failure [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_kermit/iksd.socket.j2 ================================================ [Socket] ListenStream = 1649 Accept=yes [Install] WantedBy = sockets.target ================================================ FILE: ansible/templates/install_kermit/iksd@.service.j2 ================================================ [Unit] Description=Internet Kermit Server [Service] # Note the - to make systemd ignore the exit code ExecStart=-/usr/sbin/iksd -A --dbfile:/var/run/iksd/iksd.db --syslog:5 --root:{{ retronas_path }} --anonymous:on # This is the part that makes it work like inetd StandardInput=socket StandardOutput=socket DynamicUser=no User=root Group=root # /usr, /boot, /etc read-only ProtectSystem=strict ProtectHome=true NoNewPrivileges=true RuntimeDirectory=iksd ReadWritePaths=/var/run/iksd /run/iksd /var/log ReadOnlyPaths={{ retronas_path }} # We can't establish new network connections RestrictAddressFamilies=AF_INET AF_INET6 AF_PACKET [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_lighttpd/99-retronas.conf.j2 ================================================ server.document-root = "{{ retronas_path }}" server.username = "{{ retronas_user }}" server.groupname = "{{ retronas_group }}" dir-listing.activate = "enable" ================================================ FILE: ansible/templates/install_linux-dexdrive/dexdrive_dumper.sh.j2 ================================================ #!/bin/bash set -u DEXDEV=/dev/dexdrive0 DESYS=${1:-ps1} # PS1 DEXEXT="mcd" DEXPATH={{ retronas_path }}/saves/sony/playstation1 case $DESYS in n64) DEXEXT="n64" DEXPATH={{ retronas_path }}/saves/nintendo/nintendo64 echo "N64 is untested, let me know what raw save format is for N64" PAUSE exit 0 ;; *) ;; esac FILENAME="" while [ -z "${FILENAME}" ] do read -p "Please type a name for the memcard to be saved as (no extension, (q)uit): " FILENAME case "${FILENAME}" in Q|q) echo "Quitting" exit 1 ;; *) echo "${FILENAME}" esac done if [ -b ${DEXDEV} ] then DUMPFILE="${DEXPATH}/${FILENAME}.${DEXEXT}" echo "Dumping ${DEXDEV} to ${DUMPFILE}, please wait ..." dd if="${DEXDEV}" of="${DUMPFILE}" chown {{ retronas_user }}:{{ retronas_group }} "${DUMPFILE}" else echo "$DEXDEV not found, didn't you connect it?" sleep 3 fi ================================================ FILE: ansible/templates/install_linux-dexdrive/install_linux-dexdrive.sh.j2 ================================================ #!/bin/bash set -u APP=linux-dexdrive REPO=https://github.com/fbriere/${APP}.git OUTPATH=$(mktemp -d) function _log { echo "$1" } HEADERS=linux-headers-$(uname -r) grep "Raspberry Pi" /proc/device-tree/model [ $? -eq 0 ] && HEADERS=raspberrypi-kernel-headers # install the required source files apt-get -y install git build-essential $HEADERS cd $OUTPATH if [ ! -f ${OUTPATH}/${APP}/.git/config ] then git clone $REPO else cd ${OUTPATH}/${APP} git pull fi cd ${OUTPATH}/${APP} git apply /tmp/makefile.patch make make install echo "dexdrive" >> /etc/modprobe.d/dexdrive.conf # remove the required source files apt-get -y remove $HEADERS ================================================ FILE: ansible/templates/install_linux-dexdrive/linux-dexdrive.service.j2 ================================================ [Unit] Description=Dex Drive service ConditionPathExists=/dev/ttyUSB0 [Service] Type=forking ExecStart=/usr/local/bin/dexattach -D /dev/ttyUSB0 TimeoutStopSec=10 Restart=no [Install] WantedBy=default.target ================================================ FILE: ansible/templates/install_linux-dexdrive/makefile.patch.j2 ================================================ diff --git a/Makefile b/Makefile index 7e5a5f0..622f248 100644 --- a/Makefile +++ b/Makefile @@ -27,6 +27,7 @@ modules: install: all cp dexattach $(DESTDIR)/$(PREFIX)/bin $(MAKE) -C $(KERNELDIR) M=$(PWD) INSTALL_MOD_PATH=$(abspath $(DESTDIR)) modules_install + depmod -A clean: rm -rf dexattach ================================================ FILE: ansible/templates/install_linux-gadgets/gadget-mass-storage-manage.sh.j2 ================================================ #!/bin/bash MODULE=g_mass_storage DEVICE="" DEVICEPATH="" SYSTEMD="retronas-gadget" select_device() { IFS=$'\n' DEVICE=() DEVICES+=($(lsblk -sl 2>/dev/null | awk '/(disk|part|rom)/{print $1" ("$4")"}' | sort -u)) DEVICES+=($(ls -la {{ retronas_path }}/images/* 2>/dev/null | awk '{print $9}')) DEVICES+=("quit") [ {{ ''.join (('$','{', '#DEVICES[@]}')) }} -le 1 ] && echo "No targets found, exiting ... " && exit 1 select SDEVICE in "${DEVICES[@]}" do DEVICE="$(echo ${SDEVICE} | awk -F ' ' '{print $1}')" [ $SDEVICE == "quit" ] && echo "User requested exit ..." && exit 0 [ ! -z "${DEVICE}" ] && break done } create_systemd_path() { DEVICEPATH=$(ls -la /dev/disk/by-path/ | grep $DEVICE | head -n1 | awk '{print $9}') if [ ! -z "${DEVICEPATH}" ] then echo "Configuring systemd path file for ${DEVICE} (${DEVICEPATH})" cat << PEOF > /etc/systemd/system/${SYSTEMD}.path [Path] PathExists=/dev/disk/by-path/$DEVICEPATH [Install] WantedBy=remote-fs.target PEOF fi } create_systemd_service() { DEVICEPATH=$(ls -la /dev/disk/by-path/ | grep $DEVICE | head -n1 | awk '{print $9}') if [ ! -z "${DEVICEPATH}" ] then echo "Configuring systemd service file for ${DEVICE} (${DEVICEPATH})" cat << SEOF > /etc/systemd/system/${SYSTEMD}.service [Unit] Description=Gadget Device Requires=open-iscsi.service [Service] Type=oneshot ExecStartPre=-echo on > /sys/bus/usb/devices/usb1/power/control ExecStartPre=-/usr/sbin/rmmod g_mass_storage ExecStartPre=/usr/bin/sleep 2 ExecStart=/usr/sbin/modprobe g_mass_storage file=/dev/disk/by-path/${DEVICEPATH} stall=0 ro=0 removable=1 Restart=no RemainAfterExit=yes SEOF fi } enable_systemd() { systemctl daemon-reload systemctl enable ${SYSTEMD}.path systemctl start ${SYSTEMD}.path } select_device create_systemd_path create_systemd_service #enable_systemd ================================================ FILE: ansible/templates/install_litch/litch_claim.sh.j2 ================================================ #!/bin/bash echo "" echo "litch claim bundles..." echo "" mkdir -p ~/.litch 2>/dev/null cd ~/.litch /opt/retronas/bin/litch/litch.py --claim-bundles ================================================ FILE: ansible/templates/install_litch/litch_download.sh.j2 ================================================ #!/bin/bash echo "" echo "litch download purchases ..." echo "" mkdir -p ~/.litch 2>/dev/null cd ~/.litch /opt/retronas/bin/litch/litch.py --download-purchases --content-path {{ retronas_path }}/itchio ================================================ FILE: ansible/templates/install_litch/litch_download_clean.sh.j2 ================================================ #!/bin/bash echo "" echo "litch download purchases ..." echo "" mkdir -p ~/.litch 2>/dev/null cd ~/.litch /opt/retronas/bin/litch/litch.py --download-purchases --cleanup-incorrect-files --content-path {{ retronas_path }}/itchio ================================================ FILE: ansible/templates/install_litch/litch_login.sh.j2 ================================================ #!/bin/bash echo "" echo "litch login ..." echo "" mkdir -p ~/.litch 2>/dev/null cd ~/.litch /opt/retronas/bin/litch/litch.py --login ================================================ FILE: ansible/templates/install_macproxy_classic/macproxy.service.j2 ================================================ [Unit] Description=Macproxy Classic service After=network.target [Service] Type=simple Restart=always ExecStart=/opt/macproxy_classic/start_macproxy.sh SyslogIdentifier=MACPROXY [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_megatools/install_megatools.sh.j2 ================================================ #!/bin/bash set -u RN_BIN=/usr/local/bin/ APP=megatools REPO=https://xff.cz/git/${APP} OUTPATH=/tmp function _log { echo "$1" } ### REQUIREMENTS REQFAIL=0 #[ ! -x /usr/bin/make ] && _log "MAKE not found" && REQFAIL=1 [ $REQFAIL -ne 0 ] && _log "Requirements failed, see previous errors" && exit $REQFAIL cd $OUTPATH if [ ! -f ${OUTPATH}/${APP}/.git/config ] then git clone $REPO else cd ${OUTPATH}/${APP} git pull fi cd ${OUTPATH}/${APP} # patch for old debian glib #sed -i 's/g_memdup2/g_memdup/g' lib/mega.c # meson setup build ninja -C build ninja -C build install #mv ${OUTPATH}/${APP}/build/megatools $RN_BIN/ # CLEAN UP rm -Rf ${OUTPATH}/${APP} ================================================ FILE: ansible/templates/install_minicom/minicom.sh.j2 ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh case $(basename $0 .sh) in minicom-config) DROP_ROOT /usr/bin/minicom -s [ $? -ne 0 ] && PAUSE ;; *) DROP_ROOT /usr/bin/minicom [ $? -ne 0 ] && PAUSE ;; esac ================================================ FILE: ansible/templates/install_minicom/minirc.dfl.j2 ================================================ # Machine-generated file - use "minicom -s" to change parameters. pu updir {{ retronas_path }}/{{ my_name }} pu downdir {{ retronas_path }}/{{ my_name }} ================================================ FILE: ansible/templates/install_mister-organize/install_mister-organize.sh.j2 ================================================ #!/bin/bash set -ue ROMVAULT=3.7.4 MISTORG="{{ retronas_path }}/{{ module_name }}" cd "${MISTORG}" case $(uname -m) in x86_64) ARCH=x64 ;; *) echo "Unsupported Architecture" ;; esac DIRS=( DatRoot RomRoot ) # Create RomVault Directories for DIR in ${DIRS[@]} do [ ! -d $DIR ] && mkdir $DIR done ln -sfT ../romimport ToSort # Setup RomVault Config RVNAME="RomVault Basic Setup" if [ -f "${RVNAME}.zip" ] then unzip -jo "${RVNAME}.zip" "${RVNAME}/RomVault3cfg.xml" fi # Move Dat files rm -f "${MISTORG}/DatRoot/MiSTer_*.dat" find $MISTORG -maxdepth 1 -name "*.dat" -exec mv "{}" DatRoot/ \; # Unpack the console dat file that is zipped find $MISTORG -maxdepth 1 -name "MiSTer_Console*.zip" -exec unzip -jo -d DatRoot/ {} \; # Clean up cd $MISTORG rm -f *.zip # Obtain RomVault for Linux RVZIP=RVCmd_V${ROMVAULT}-Linux-${ARCH}.zip cd /tmp curl -skLO https://www.romvault.com/download/${RVZIP} if [ -f ${RVZIP} ] then unzip -o ${RVZIP} -d $MISTORG chmod +x ${MISTORG}/RomVaultCmd rm -f $RVZIP else echo "Failed to download" exit 1 fi chown -R {{ retronas_user }}:{{ retronas_group }} {{ retronas_path }}/{{ module_name }} ================================================ FILE: ansible/templates/install_mister-organize/mister-organize.sh.j2 ================================================ #!/bin/bash cd {{ retronas_path }}/{{ module_name }}/ su -p retronas -c "./RomVaultCmd -all" ================================================ FILE: ansible/templates/install_mister_cifs/retronas-mister-dirs.service.j2 ================================================ [Unit] Description=retronas-mister-dirs After=multi-user.target [Service] Type=simple Restart=no WorkingDirectory=/opt/retronas/ansible ExecStartPre=/usr/bin/git reset --hard HEAD ExecStartPre=/usr/bin/git pull ExecStart=/usr/bin/ansible-playbook --extra-vars "dirs_only=true" {{ my_file }}.yml TimeoutStartSec=0 RemainAfterExit=no [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_mister_cifs/retronas-mister-dirs.timer.j2 ================================================ [Unit] Description=Run retronas-mister-dirs [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target ================================================ FILE: ansible/templates/install_mtcp-netdrive/install_mtcp-netdrive.sh.j2 ================================================ #!/bin/bash VERSION=${1:-2025-01-10} ARCBIN=https://www.brutman.com/mTCP/download/mTCP_NetDrive_server-bin_${VERSION}.zip DEST=/opt/mtcp-netdrive LZIP=mtcp.zip # download if [ ! -f ${TMPDIR}/${LZIP} ] then curl -JLo${TMPDIR}/${LZIP} "${ARCBIN}" fi # extract if [ -f ${TMPDIR}/${LZIP} ] then unzip -j -d $DEST ${TMPDIR}/${LZIP} fi case $(uname -m) in aarch64) BIN=netdrive_linux_arm64 ;; x86_64) BIN=netdrive_linux_amd64 ;; *) echo "Unknown architecture $(uname -m)" esac if [ -f "${DEST}/${BIN}" ] then chmod +x "${DEST}/${BIN}" ln -sf "${DEST}/${BIN}" "${DEST}/netdrive" fi chown -R {{ retronas_user }}:{{ retronas_group }} $DEST ================================================ FILE: ansible/templates/install_mtcp-netdrive/mtcp-netdrive.service.j2 ================================================ [Unit] Description=mTCP Netdrive Requires=network.target After=network.target [Service] Type=forking WorkingDirectory=/opt/mtcp-netdrive ExecStart={{ retronas_root }}/scripts/mtcp-netdrive.sh start ExecStop={{ retronas_root }}/scripts/mtcp-netdrive.sh stop # only because somewhere in the chain screen decides to report failure SuccessExitStatus=1 Restart=no [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_mtcp-netdrive/mtcp-netdrive.sh.j2 ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MODE=${1:-config} SESSION=mtcp-netdrive [ ! -f /opt/mtcp-netdrive/netdrive ] && echo "mTCP Netdrive is not installed" && exit 1 cd /opt/mtcp-netdrive/ case $MODE in console) DROP_ROOT /usr/bin/screen -x $SESSION ;; start) DROP_ROOT /usr/bin/screen -dmS $SESSION ./netdrive -log_file /opt/mtcp-netdrive/log.txt serve -image_dir /data/retronas/roms/microsoft/dos/ ;; stop) DROP_ROOT /usr/bin/screen -S $SESSION -X stuff "quit^M" ;; *) exit ;; esac ================================================ FILE: ansible/templates/install_mtcp-netdrive/mtcp-netdrive.xml.j2 ================================================ ================================================ FILE: ansible/templates/install_mysticbbs/create_filebone_na.py.j2 ================================================ #!/usr/bin/env python3 # # sairuk, built with limited scope for RetroNAS deduping filearea creation # ## references # https://git.shipoclu.com/moon/enigma-bbs/src/commit/60369ea378be82cd76ba954577b9bd34dec919a3/core/oputil/oputil_file_base.js # https://web.archive.org/web/20060507083451/http://www.filegate.net/info/filegate.zxx # https://talk.dallasmakerspace.org/t/bbs-utils-reading-mystic-database-files/56722 # ## based on # - lastcallers.py : (CC No-By)2019-2034 Dallas Makerspace, Some Rights Reserved : Authors: Dwight Spencer (denzuko) # - mystic_library.php : netsurge : mysphp14.zip import os, yaml from struct import Struct RN_SYSTEMS="{{ retronas_root }}/ansible/retronas_systems.yml" RN_BASE="{{ retronas_path }}/roms/" # NOTE: this is not a comprehensive intepretation of the data, just enough for what we need fbase_t = Struct("I 60s ? 60s ? 61s ? 175s ? 61s ? 80s ? 8s ? ? 123s") BYTES=640 ignored = [ 'system_map', 'system_links', "system_template", ] def yaml_data(): data = [] ind = open(RN_SYSTEMS,'r').read() odata = yaml.safe_load(ind) for key in odata.keys(): if key not in ignored: for item in odata[key]: if item["pretty_name"] != "": data.append({"src": item["src"], "pretty_name": item["pretty_name"]}) return data def filebone(data={}, fa={}): # output the filebone.na format print("% File Echo Description") print("%") for item in data: d = item["src"] n = item["pretty_name"] ad = os.path.join(RN_BASE,d) if ad not in fa.values(): print(f"Area {d} 0 ! RTNS: {n}") print("%") print("% End of RetroNAS Fileecho List") def fileareas(dat="fbases.dat"): dat = os.path.join("data",dat) if not os.path.exists(dat): return [] fileareas = {} filesize = os.stat(dat).st_size records = int(filesize / BYTES) with open(dat, 'rb') as data: by = data.read() ba = [by[i:i+BYTES] for i in range(-1, len(by), BYTES)] for record in range(1, records): filearea = fbase_t.unpack_from(ba[record]) fname = filearea[3].decode().strip('\x00')[1:] fname = fname.split(":")[-1].replace("_", " ").lstrip() fpath = filearea[11].decode().strip('\x00')[:-1] fileareas[fname] = fpath return fileareas def main(dat="fbases.dat"): fa = fileareas() data = yaml_data() filebone(data, fa) if __name__ == "__main__": main() ================================================ FILE: ansible/templates/install_mysticbbs/install_mysticbbs.sh.j2 ================================================ #!/bin/bash DEST=/opt/mysticbbs TMPDEST=/tmp/mysticbbs DESTFILE=mysticbbs DL="" EXT="" # version locked because auto upgrade cannot be tested atm # `install auto overwrite` overwrites key configuration, like filebases, general config etc if [ -f /opt/mysticbbs/mystic.dat ] then echo "Upgrading Mystic is a manual process once installed, exiting otherwise your bbs could be wiped" exit fi case $(uname -m) in aarch64) DL=https://www.mysticbbs.com/downloads/mys112a48_p64.zip ;; x86_64) DL=https://www.mysticbbs.com/downloads/mys112a48_l64.rar ;; *) echo "Unknown architecture $(uname -m)" esac if [ ! -z "${DL}" ] then EXT="${DL##*.}" DESTFILE="${DESTFILE}.${EXT}" if [ ! -f $TMPDIR/$DESTFILE ] then curl -JLo $TMPDIR/$DESTFILE "${DL}" fi fi [ ! -d $DEST ] && mkdir -p $DEST if [ -f $TMPDIR/$DESTFILE ] then 7z x -o${TMPDEST} -y "${TMPDIR}/${DESTFILE}" fi chown -R retronas:retronas $DEST chmod +x $TMPDEST/install $TMPDEST/upgrade cd $TMPDEST ./install auto $DEST overwrite rm -f $TMPDIR/$DESTFILE if [ -f /opt/mysticbbs/mutil ] then {{ retronas_root }}/scripts/mysticbbs.sh filearea {{ retronas_root }}/scripts/mysticbbs.sh upload fi ================================================ FILE: ansible/templates/install_mysticbbs/mysticbbs-mis.service.j2 ================================================ [Unit] Description=MysticBBS Internet Server Requires=network.target After=network.target [Service] Type=forking WorkingDirectory=/opt/mysticbbs ExecStart=/opt/mysticbbs/mis daemon ExecStop=/opt/mysticbbs/mis shutdown RestartSec=10s TimeoutStartSec=8s Restart=on-failure [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_mysticbbs/mysticbbs.sh.j2 ================================================ #!/bin/sh MODE=${1:-config} FA_CREATED=retronas.filesareas_done [ ! -f /opt/mysticbbs/mystic ] && echo "Mystic is not installed" && exit 1 cd /opt/mysticbbs case $MODE in local) ./mystic -l ;; filearea) #if [ -f $FA_CREATED ] #then # echo "File areas for RetroNAS have already been imported, running this again will result in duplicate fileareas" # echo "If you are sure, remove the file $FA_CREATED and run this option again" # exit #fi if [ -f retronas_create_fileareas.ini ] then [ -f retronas.na ] && mv retronas.na retronas.na.$(date +'%s') python3 create_filebone_na.py > retronas.na ./mutil retronas_create_fileareas.ini rm retronas.na touch $FA_CREATED fi ;; upload) ./mutil retronas_massupload.ini ;; *) ./mystic -cfg ;; esac ================================================ FILE: ansible/templates/install_mysticbbs/mysticbbs.xml.j2 ================================================ ================================================ FILE: ansible/templates/install_mysticbbs/retronas_create_fileareas.ini.j2 ================================================ [General] Import_FILEBONE.NA = true [Import_FILEBONE.NA] ; filename of filebone.na filename = retronas.na ; root directory to create file paths under. when a new filebone echo ; is found, mUtil will create a file using "root_dir" + areatag. So ; for example if root is "c:\mystic\filebase\" and the areatag is ; MYSTICBBS it will create "c:\mystic\filebase\MYSTICBBS". This root ; directory MUST exist. root_dir = /data/retronas/roms ; Use echotag for base description and FTP name use_echotag = false ; Convert tags to lower case for filebase base filename/dir ; True or 1 for yes, false or 0 for no lowercase_filename = false ; Default values when creating a new file base dispfile = template = ansiflst acs_list = acs_ftp = acs_download = acs_upload = acs_hatch = acs_sysop = s255 ; true/false type values 0=false 1=true (newscan 2=forced) ; true/false type values 0=false 1=true (newscan 2=forced) new_scan = 1 free_files = 0 show_uploader = 1 anon_ftp = 0 ================================================ FILE: ansible/templates/install_mysticbbs/retronas_massupload.ini.j2 ================================================ [General] MassUpload = true [MassUpload] ; this function searches all configured file directories for new ; files and will upload them into the BBS. It will attempt to ; import FILE_ID.DIZ using the configured archivers if the option ; is enabled. ; Name to save has the uploader uploader_name = RetroNAS ; Import FILE_ID.DIZ? 1=yes import_fileid = 1 ; Rename filenames that are longer than the maximum allowed length length_rename = false ; No description string used when no FILE_ID.DIZ is imported. no_description = No Description ; Ignore list one file mask per line (allows * and ? wildcards) ignore = files.bbs ;ignore = *.readme ================================================ FILE: ansible/templates/install_nabu/install_nabu.sh.j2 ================================================ #!/bin/bash TMPFILES=$(mktemp -d) declare -A VERSIONS=( ['x86_64']='x64' ['aarch64']='arm64' ['arm']='arm' ) BINDIR=/opt/nabu ARCH=$(uname -m) ARCHIVE=linux-${VERSIONS[$ARCH]}.zip [ ! -d $BINDIR ] && mkdir -p $BINDIR cd $TMPFILES curl -O http://cloud.nabu.ca/${ARCHIVE} if [ -f ${ARCHIVE} ] then unzip -j $ARCHIVE -d $BINDIR rm -f $ARCHIVE chmod +x $BINDIR/NABU-Internet-Adapter* chown -R {{ retronas_user }}:{{ retronas_group }} $BINDIR fi ================================================ FILE: ansible/templates/install_nabu/nabu.sh.j2 ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh BINDIR=/opt/nabu BIN=NABU-Internet-Adapter-84 cd $BINDIR LIB=libdl.so [ ! -f ${LIB} ] && ln -s /lib/x86_64-linux-gnu/${LIB}.2 ${LIB} DROP_ROOT "./$BIN" ================================================ FILE: ansible/templates/install_nbd-client/nbd.conf.j2 ================================================ nbd ================================================ FILE: ansible/templates/install_netatalk2/AppleVolumes.default.j2 ================================================ # Netatalk 2.x afp volume cofiguration # # volume format: # :DEFAULT: [all of the default options except volume name] # path [name] [casefold:x] [options:z,l,j] \ # [allow:a,@b,c,d] [deny:a,@b,c,d] [dbpath:path] [password:p] \ # [rwlist:a,@b,c,d] [rolist:a,@b,c,d] [limitsize:value in bytes] \ # [preexec:cmd] [root_preexec:cmd] [postexec:cmd] [root_postexec:cmd] \ # [allowed_hosts:IPv4 address[/IPv4 netmask bits]] \ # [denied_hosts:IPv4 address[/IPv4 netmask bits]] \ # ... more, see below ... # # name: volume name. it can't include the ':' character # # # variable substitutions: # you can use variables for both and now. here are the # rules: # 1) if you specify an unknown variable, it will not get converted. # 2) if you specify a known variable, but that variable doesn't have # a value, it will get ignored. # # the variables: # $b -> basename of path # $c -> client's ip or appletalk address # $d -> volume pathname on server # $f -> full name (whatever's in the gecos field) # $g -> group # $h -> hostname # $i -> client ip without tcp port or appletalk network # $s -> server name (can be the hostname) # $u -> username (if guest, it's whatever user guest is running as) # $v -> volume name (either ADEID_NAME or basename of path) # $z -> zone (may not exist) # $$ -> $ # # # casefold options [syntax: casefold:option]: # tolower -> lowercases names in both directions # toupper -> uppercases names in both directions # xlatelower -> client sees lowercase, server sees uppercase # xlateupper -> client sees uppercase, server sees lowercase # # allow/deny/rwlist/rolist format [syntax: allow:user1,@group]: # user1,@group,user2 -> allows/denies access from listed users/groups # rwlist/rolist control whether or not the # volume is ro for those users. # allowed_hosts -> Only listed hosts and networks are allowed, # all others are rejected. Example: # allowed_hosts:10.1.0.0/16,10.2.1.100 # denied_hosts -> Listed hosts and nets are rejected, # all others are allowed. Example: # denied_hosts: 192.168.100/24,10.1.1.1 # preexec -> command to be run when the volume is mounted, # ignore for user defined volumes # root_preexec -> command to be run as root when the volume is mounted, # ignore for user defined volumes # postexec -> command to be run when the volume is closed, # ignore for user defined volumes # root_postexec -> command to be run as root when the volume is closed, # ignore for user defined volumes # veto -> hide files and directories,where the path matches # one of the "/" delimited vetoed names. Matches are # partial, e.g. path is /abc/def/file and veto:/abc/ # will hide the file. # adouble -> specify the format of the metadata files. # default is "v2". netatalk 1.x used "v1". # "osx" cannot be treated normally any longer. # volsizelimit -> size in MiB. Useful for TimeMachine: limits the # reported volume size, thus preventing TM from using # the whole real disk space for backup. # Example: "volsizelimit:1000" would limit the # reported disk space to 1 GB. # # codepage options [syntax: options:charsetname] # volcharset -> specifies the charset to be used # as the volume codepage # e.g. "UTF8", "UTF8-MAC", "ISO-8859-15" # maccharset -> specifies the charset to be used # as the legacy client (<=Mac OS 9) codepage # e.g. "MAC_ROMAN", "MAC_CYRILLIC" # # perm -> default permission value # OR with the client requested perm # Use with options:upriv # dperm -> default permission value for directories # OR with the client requested perm # Use with options:upriv # fperm -> default permission value for files # OR with the client requested perm # Use with options:upriv # umask -> set perm mask # Use with options:upriv # dbpath:path -> store the database stuff in the following path. # cnidserver:server[:port] # -> Query this servername or IP address # (default:localhost) and port (default: 4700) # for CNIDs. Only used with CNID backend "dbd". # This option here overrides any setting from # afpd.conf:cnidserver. # password:password -> set a volume password (8 characters max) # cnidscheme:scheme -> set the cnid scheme for the volume, # default is [dbd] # available schemes: [dbd last tdb] # ea -> none|auto|sys|ad # Specify how Extended Attributes are stores. default # is auto. # auto: try "sys" (by setting an EA on the shared # directory itself), fallback to "ad". Requires # writable volume for performing the test. # Note: options:ro overwrites "auto" with "none." # sys: Use filesystem EAs # ad: Use files in AppleDouble directories # none: No EA support # # # miscellaneous options [syntax: options:option1,option2]: # tm -> enable TimeMachine support # prodos -> make compatible with appleII clients. # crlf -> enable crlf translation for TEXT files. # noadouble -> don't create .AppleDouble unless a resource # fork needs to be created. # ro -> mount the volume as read-only. # mswindows -> enforce filename restrictions imposed by MS # Windows. this will also invoke a default # codepage (iso8859-1) if one isn't already # specified. # nohex -> don't do :hex translations for anything # except dot files. specify usedots as well if # you want that turned off. note: this option # makes the / character illegal. # usedots -> don't do :hex translation for dot files. note: when # this option gets set, certain file names # become illegal. these are .Parent and # anything that starts with .Apple. # invisibledots -> don't do :hex translation for dot files. note: when # this option gets set, certain file names # become illegal. these are .Parent and # anything that starts with .Apple. also, dot # files created on the unix side are marked invisible. # limitsize -> limit disk size reporting to 2GB. this is # here for older macintoshes using newer # appleshare clients. yucko. # nofileid -> don't advertise createfileid, resolveid, deleteid # calls # root_preexec_close -> a non-zero return code from root_preexec close the # volume being mounted. # preexec_close -> a non-zero return code from preexec close the # volume being mounted. # nostat -> don't stat volume path when enumerating volumes list # upriv -> use unix privilege. # illegalseq -> encode illegal sequence in filename asis, # ex "\217-", which is not a valid SHIFT-JIS char, # is encoded as U\217 - # nocnidcache -> Don't store and read CNID to/from AppleDouble file. # This should not be used as it also prevents a CNID # database rebuild with `dbd`! # caseinsensitive -> The underlying FS is case insensitive (only # test with JFS in OS2 mode) # dropbox -> Allows a volume to be declared as being a "dropbox." # Note that netatalk must be compiled with dropkludge # support for this to function. Warning: This option # is deprecated and might not work as expected. # dropkludge -> same as "dropbox" # nodev -> always use 0 for device number, helps when the # device number is not constant across a reboot, # cluster, ... # # The line below sets some DEFAULT, starting with Netatalk 2.1. :DEFAULT: options:upriv,usedots # By default all users have access to their home directories. {{ retronas_path }} "retronas" # End of File ================================================ FILE: ansible/templates/install_netatalk2/afpd.conf.j2 ================================================ # # CONFIGURATION FOR AFPD (Netatalk 2.x) # # Each single line defines a virtual server that should be available. # Though, using "\" character, newline escaping is supported. # Empty lines and lines beginning with `#' are ignored. # Options in this file will override both compiled-in defaults # and command line options. # # # Format: # - [options] to specify options for the default server # "Server name" [options] to specify an additional server # # # The following options are available: # Transport Protocols: # -[no]tcp Make "AFP over TCP" [not] available # -[no]ddp Make "AFP over AppleTalk" [not] available. # If you have -proxy specified, specify -uamlist "" to # prevent ddp connections from working. # # -transall Make both available # # Transport Options: # -ipaddr Specifies the IP address that the server should # advertise and listens to. The default is advertise # the first IP address of the system, but to listen # for any incoming request. The network address may # be specified either in dotted-decimal format for # IPv4 or in hexadecimal format for IPv6. # This option also allows to use one machine to # advertise the AFP-over-TCP/IP settings of another # machine via NBP when used together with the -proxy # option. # -server_quantum # Specifies the DSI server quantum. The minimum # value is 1MB. The max value is 0xFFFFFFFF. If you # specify a value that is out of range, you'll get # the default value (currently the minimum). # -admingroup # Specifies the group of administrators who should # all be seen as the superuser when they log in. # Default is disabled. # -ddpaddr x.y Specifies the DDP address of the server. # the default is to auto-assign an address (0.0). # this is only useful if you're running on # a multihomed host. # -port Specifies the TCP port the server should respond # to (default is 548) # -fqdn specify a fully-qualified domain name (+optional # port). this gets discarded if the server can't # resolve it. this is not honored by appleshare # clients <= 3.8.3 (default: none) # -hostname Use this instead of the result from calling # hostname for dertermening which IP address to # advertise, therfore the hostname is resolved to # an IP which is the advertised. This is NOT used for # listening and it is also overwritten by -ipaddr. # -proxy Run an AppleTalk proxy server for specified # AFP/TCP server (if address/port aren't given, # then first IP address of the system/548 will # be used). # if you don't want the proxy server to act as # a ddp server as well, set -uamlist to an empty # string. # -dsireadbuf [number] # Scale factor that determines the size of the # DSI/TCP readahead buffer, default is 12. This is # multiplies with the DSI server quantum (default # ~300k) to give the size of the buffer. Increasing # this value might increase throughput in fast local # networks for volume to volume copies. Note: This # buffer is allocated per afpd child process, so # specifying large values will eat up large amount of # memory (buffer size * number of clients). # -tcprcvbuf [number] # Try to set TCP receive buffer using setsockpt(). # Often OSes impose restrictions on the applications # ability to set this value. # -tcpsndbuf [number] # Try to set TCP send buffer using setsockpt(). # Often OSes impose restrictions on the applications # ability to set this value. # -slp Register this server with the Service Location # Protocol (if SLP support was compiled in). # -nozeroconf Don't register this server with the Multicats # DNS Protocol. # -advertise_ssh Allows Mac OS X clients (10.3.3-10.4) to # automagically establish a tunneled AFP connection # through SSH. This option is not so significant # for the recent Mac OS X. See the Netatalk Manual # in detail. # # # Authentication Methods: # -uampath Use this path to look for User Authentication Modules. # (default: /usr/lib/netatalk) # -uamlist Comma-separated list of UAMs. # (default: uams_dhx.so,uams_dhx2.so) # # some commonly available UAMs: # uams_guest.so: Allow guest logins # # uams_clrtxt.so: (uams_pam.so or uams_passwd.so) # Allow logins with passwords # transmitted in the clear. # # uams_randnum.so: Allow Random Number and Two-Way # Random Number exchange for # authentication. # # uams_dhx.so: (uams_dhx_pam.so or uams_dhx_passwd.so) # Allow Diffie-Hellman eXchange # (DHX) for authentication. # # uams_dhx2.so: (uams_dhx2_pam.so or uams_dhx2_passwd.so) # Allow Diffie-Hellman eXchange 2 # (DHX2) for authentication. # # Password Options: # -[no]savepassword [Don't] Allow clients to save password locally # -passwdfile Use this path to store Randnum passwords. # (Default: /etc/netatalk/afppasswd. The only other # useful value is ~/.passwd. See 'man afppasswd' # for details.) # -passwdminlen <#> minimum password length. may be ignored. # -[no]setpassword [Don't] Allow clients to change their passwords. # -loginmaxfail <#> maximum number of failed logins. this may be # ignored if the uam can't handle it. # # AppleVolumes files: # -defaultvol Specifies path to AppleVolumes.default file # (default /etc/netatalk/AppleVolumes.default, # same as -f on command line) # -systemvol Specifies path to AppleVolumes.system file # (default /etc/netatalk/AppleVolumes.system, # same as -s on command line) # -[no]uservolfirst [Don't] read the user's ~/AppleVolumes or # ~/.AppleVolumes before reading # /etc/netatalk/AppleVolumes.default # (same as -u on command line) # -[no]uservol [Don't] Read the user's volume file # -closevol Immediately unmount volumes removed from # AppleVolumes files on SIGHUP sent to the afp # master process. # # Miscellaneous: # -authprintdir Specifies the path to be used (per server) to # store the files required to do CAP-style # print authentication which papd will examine # to determine if a print job should be allowed. # These files are created at login and if they # are to be properly removed, this directory # probably needs to be umode 1777 # -guestname "user" Specifies the user name for the guest login # (default "nobody", same as -g on command line) # -loginmesg "Message" Client will display "Message" upon logging in # (no default, same as -l "Message" on commandline) # -nodebug Switch off debugging # -client_polling With this switch enabled, afpd won't advertise # that it is capable of server notifications, so that # connected clients poll the server every 10 seconds # to detect changes in opened server windows. # Note: Depending on the number of simultaneously # connected clients and the network's speed, this can # lead to a significant higher load on your network! # -sleep AFP 3.x wait number hours before disconnecting # clients in sleep mode. Default 10 hours # -tickleval Specify the tickle timeout interval (in seconds). # Note, this defaults to 30 seconds, and really # shouldn't be changed. If you want to control # the server idle timeout, use the -timeout option. # -timeout Specify the number of tickles to send before # timing out a connection. # The default is 4, therefore a connection will # timeout in 2 minutes. # -[no]icon [Don't] Use the platform-specific icon. Recent # Mac OS don't display it any longer. # -volnamelen # Max length of UTF8-MAC volume name for Mac OS X. # Note that Hangul is especially sensitive to this. # 255: limit of spec # 80: limit of generic Mac OS X (default) # 73: limit of Mac OS X 10.1, if >= 74 # Finder crashed and restart repeatedly. # Mac OS 9 and earlier is not influenced by this, # Maccharset volume names are always limitted to 27. # -[un]setuplog " []" # Specify that any message of a loglevel up to the # given loglevel should be logged to the given file. # If the filename is ommited the loglevel applies to # messages passed to syslog. # # By default (no explicit -setuplog and no buildtime # configure flag --with-logfile) afpd logs to syslog # with a default logging setup equivalent to # "-setuplog default log_info". # # If build with --with-logfile[=somefile] # (default logfile /var/log/netatalk.log) afpd # defaults to a setup that is equivalent to # "-setuplog default log_info [netatalk.log|somefile]" # # logtypes: Default, AFPDaemon, Logger, UAMSDaemon # loglevels: LOG_SEVERE, LOG_ERROR, LOG_WARN, # LOG_NOTE, LOG_INFO, LOG_DEBUG, # LOG_DEBUG6, LOG_DEBUG7, LOG_DEBUG8, # LOG_DEBUG9, LOG_MAXDEBUG # # Example: Useful default config # -setuplog "default log_info /var/log/afpd.log" # # Debugging config # -setuplog "default log_maxdebug /var/log/afpd.log" # # -signature { user: | auto } # Specify a server signature. This option is useful # while running multiple independent instances of # afpd on one machine (e.g. in clustered environments, # to provide fault isolation etc.). # Default is "auto". # "auto" signature type allows afpd generating # signature and saving it to afp_signature.conf # automatically (based on random number). # "host" signature type switches back to "auto" # because it is obsoleted. # "user" signature type allows administrator to # set up a signature string manually. # Examples: three servers running on one machine: # first -signature user:USERS # second -signature user:USERS # third -signature user:ADMINS # First two servers will act as one logical AFP # service. If user logs in to first one and then # connects to second one, session will be # automatically redirected to the first one. But if # client connects to first and then to third, # will be asked for password twice and will see # resources of both servers. # Traditional method of signature generation causes # two independent afpd instances to have the same # signature and thus cause clients to be redirected # automatically to server (s)he logged in first. # -k5keytab # -k5service # -k5realm # These are required if the server supports # Kerberos 5 authentication # -ntdomain # -ntseparator # Use for e.g. winbind authentication, prepends # both strings before the username from login and # then tries to authenticate with the result # through the available and active UAM authentication # modules. # -dircachesize entries # Maximum possible entries in the directory cache. # The cache stores directories and files. It is used # to cache the full path to directories and CNIDs # which considerably speeds up directory enumeration. # Default size is 8192, maximum size is 131072. Given # value is rounded up to nearest power of 2. Each # entry takes about 100 bytes, which is not much, but # remember that every afpd child process for every # connected user has its cache. # -fcelistener host[:port] # Enables sending FCE events to the specified host, # default port is 12250 if not specified. Specifying # mutliple listeners is done by having this option # once for each of them. # -fceevents fmod,fdel,ddel,fcre,dcre,tmsz # Speficies which FCE events are active, default is # fmod,fdel,ddel,fcre,dcre. # -fcecoalesce all|delete|create # Coalesce FCE events. # -fceholdfmod seconds # This determines the time delay in seconds which is # always waited if another file modification for the # same file is done by a client before sending an FCE # file modification event (fmod). For example saving # a file in Photoshop would generate multiple events # by itself because the application is opening, # modifying and closing a file mutliple times for # every "save". Defautl: 60 seconds. # -keepsessions Enable "Continuous AFP Service". This means the # ability to stop the master afpd process with a # SIGQUIT signal, possibly install an afpd update and # start the afpd process. Existing AFP sessions afpd # processes will remain unaffected. Technically they # will be notified of the master afpd shutdown, sleep # 15-20 seconds and then try to reconnect their IPC # channel to the master afpd process. If this # reconnect fails, the sessions are in an undefined # state. Therefor it's absolutely critical to restart # the master process in time! # -noacl2maccess Don't map filesystem ACLs to effective permissions. # # Codepage Options: # -unixcodepage Specifies the servers unix codepage, # e.g. "ISO-8859-15" or "UTF8". # This is used to convert strings to/from # the systems locale, e.g. for authenthication. # Defaults to LOCALE if your system supports it, # otherwise ASCII will be used. # # -maccodepage Specifies the legacy clients (<= Mac OS 9) # codepage, e.g. "MAC_ROMAN". # This is used to convert strings to the # systems locale, e.g. for authenthication # and SIGUSR2 messaging. This will also be # the default for volumes maccharset. # # CNID related options: # -cnidserver # Specifies the IP address and port of a # cnid_metad server, required for CNID dbd # backend. Defaults to localhost:4700. # The network address may be specified either # in dotted-decimal format for IPv4 or in # hexadecimal format for IPv6. # # Avahi (Bonjour) related options: # -mimicmodel # Specifies the icon model that appears on # clients. Defaults to off. Examples: RackMac # (same as Xserve), PowerBook, PowerMac, Macmini, # iMac, MacBook, MacBookPro, MacBookAir, MacPro, # AppleTV1,1, AirPort # # # Some examples: # # The simplest case is to not have an afpd.conf. # # 4 servers w/ names server1-3 and one w/ the hostname. servers # 1-3 get routed to different ports with server 3 being bound # specifically to address 192.168.1.3 # # - # server1 -port 12000 # server2 -port 12001 # server3 -port 12002 -ipaddr 192.168.1.3 # # a dedicated guest server, a user server, and a special # AppleTalk-only server: # # "Guest Server" -uamlist uams_guest.so \ # -loginmesg "Welcome guest! I'm a public server." # "User Server" -uamlist uams_dhx2.so -port 12000 # "special" -ddp -notcp -defaultvol -systemvol # # default: # - -tcp -noddp -uamlist uams_dhx.so,uams_dhx2.so - -transall -icon -mimicmodel PowerMac ================================================ FILE: ansible/templates/install_netatalk2/default.j2 ================================================ # Netatalk 2.x configuration ######################################################################### # Global configuration ######################################################################### #### machine's AFPserver/AppleTalk name. ATALK_NAME=retroafp #### server (unix) and legacy client (<= Mac OS 9) charsets ATALK_UNIX_CHARSET='LOCALE' ATALK_MAC_CHARSET='MAC_ROMAN' #### Don't Edit. export the charsets, read form ENV by apps export ATALK_UNIX_CHARSET export ATALK_MAC_CHARSET ######################################################################### # AFP specific configuration ######################################################################### #### Set which daemons to run. #### If you use AFP file server, run both cnid_metad and afpd. CNID_METAD_RUN=yes AFPD_RUN=yes #### maximum number of clients that can connect: #AFPD_MAX_CLIENTS=20 #### UAMs (User Authentication Modules) #### available options: uams_dhx.so, uams_dhx2.so, uams_guest.so, #### uams_clrtxt.so(legacy), uams_randnum.so(legacy) AFPD_UAMLIST="-U uams_dhx2.so,uams_clrtxt.so,uams_dhx.so,uams_guest.so,uams_randnum.so" #### Set the id of the guest user when using uams_guest.so #AFPD_GUEST=nobody #### config for cnid_metad. Default log config: #CNID_CONFIG="-l log_note" ######################################################################### # AppleTalk specific configuration (legacy) ######################################################################### #### Set which legacy daemons to run. #### If you need AppleTalk, run atalkd. #### papd, timelord and a2boot are dependent upon atalkd. ATALKD_RUN=yes PAPD_RUN=yes TIMELORD_RUN=yes A2BOOT_RUN=yes #### Control whether the daemons are started in the background. #### If it is dissatisfied that legacy atalkd starts slowly, set "yes". #### In case using systemd/systemctl, this is not so significant. ATALK_BGROUND=yes #### Set the AppleTalk Zone name. #### NOTE: if your zone has spaces in it, you're better off specifying #### it in atalkd.conf #ATALK_ZONE=@zone ================================================ FILE: ansible/templates/install_netatalk2x/AppleVolumes.default.j2 ================================================ # Netatalk 2.x afp volume cofiguration # This file looks empty when viewed with "vi". In fact, there is one # '~', so users with no AppleVolumes file in their home directory get # their home directory by default. # # volume format: # :DEFAULT: [all of the default options except volume name] # path [name] [casefold:x] [options:z,l,j] \ # [allow:a,@b,c,d] [deny:a,@b,c,d] [dbpath:path] [password:p] \ # [rwlist:a,@b,c,d] [rolist:a,@b,c,d] [limitsize:value in bytes] \ # [preexec:cmd] [root_preexec:cmd] [postexec:cmd] [root_postexec:cmd] \ # [allowed_hosts:IPv4 address[/IPv4 netmask bits]] \ # [denied_hosts:IPv4 address[/IPv4 netmask bits]] \ # ... more, see below ... # # name: volume name. it can't include the ':' character # # # variable substitutions: # you can use variables for both and now. here are the # rules: # 1) if you specify an unknown variable, it will not get converted. # 2) if you specify a known variable, but that variable doesn't have # a value, it will get ignored. # # the variables: # $b -> basename of path # $c -> client's ip or appletalk address # $d -> volume pathname on server # $f -> full name (whatever's in the gecos field) # $g -> group # $h -> hostname # $i -> client ip without tcp port or appletalk network # $s -> server name (can be the hostname) # $u -> username (if guest, it's whatever user guest is running as) # $v -> volume name (either ADEID_NAME or basename of path) # $z -> zone (may not exist) # $$ -> $ # # # casefold options [syntax: casefold:option]: # tolower -> lowercases names in both directions # toupper -> uppercases names in both directions # xlatelower -> client sees lowercase, server sees uppercase # xlateupper -> client sees uppercase, server sees lowercase # # allow/deny/rwlist/rolist format [syntax: allow:user1,@group]: # user1,@group,user2 -> allows/denies access from listed users/groups # rwlist/rolist control whether or not the # volume is ro for those users. # allowed_hosts -> Only listed hosts and networks are allowed, # all others are rejected. Example: # allowed_hosts:10.1.0.0/16,10.2.1.100 # denied_hosts -> Listed hosts and nets are rejected, # all others are allowed. Example: # denied_hosts: 192.168.100/24,10.1.1.1 # preexec -> command to be run when the volume is mounted, # ignore for user defined volumes # root_preexec -> command to be run as root when the volume is mounted, # ignore for user defined volumes # postexec -> command to be run when the volume is closed, # ignore for user defined volumes # root_postexec -> command to be run as root when the volume is closed, # ignore for user defined volumes # veto -> hide files and directories,where the path matches # one of the "/" delimited vetoed names. Matches are # partial, e.g. path is /abc/def/file and veto:/abc/ # will hide the file. # adouble -> specify the format of the metadata files. # default is "v2". netatalk 1.x used "v1". # "osx" cannot be treated normally any longer. # volsizelimit -> size in MiB. Useful for TimeMachine: limits the # reported volume size, thus preventing TM from using # the whole real disk space for backup. # Example: "volsizelimit:1000" would limit the # reported disk space to 1 GB. # # codepage options [syntax: options:charsetname] # volcharset -> specifies the charset to be used # as the volume codepage # e.g. "UTF8", "UTF8-MAC", "ISO-8859-15" # maccharset -> specifies the charset to be used # as the legacy client (<=Mac OS 9) codepage # e.g. "MAC_ROMAN", "MAC_CYRILLIC" # # perm -> default permission value # OR with the client requested perm # Use with options:upriv # dperm -> default permission value for directories # OR with the client requested perm # Use with options:upriv # fperm -> default permission value for files # OR with the client requested perm # Use with options:upriv # umask -> set perm mask # Use with options:upriv # dbpath:path -> store the database stuff in the following path. # cnidserver:server[:port] # -> Query this servername or IP address # (default:localhost) and port (default: 4700) # for CNIDs. Only used with CNID backend "dbd". # This option here overrides any setting from # afpd.conf:cnidserver. # password:password -> set a volume password (8 characters max) # cnidscheme:scheme -> set the cnid scheme for the volume, # default is [dbd] # available schemes: [dbd last tdb] # ea -> none|auto|sys|ad # Specify how Extended Attributes are stores. default # is auto. # auto: try "sys" (by setting an EA on the shared # directory itself), fallback to "ad". Requires # writable volume for performing the test. # Note: options:ro overwrites "auto" with "none." # sys: Use filesystem EAs # ad: Use files in AppleDouble directories # none: No EA support # # # miscellaneous options [syntax: options:option1,option2]: # tm -> enable TimeMachine support # prodos -> make compatible with appleII clients. # crlf -> enable crlf translation for TEXT files. # noadouble -> don't create .AppleDouble unless a resource # fork needs to be created. # ro -> mount the volume as read-only. # mswindows -> enforce filename restrictions imposed by MS # Windows. this will also invoke a default # codepage (iso8859-1) if one isn't already # specified. # nohex -> don't do :hex translations for anything # except dot files. specify usedots as well if # you want that turned off. note: this option # makes the / character illegal. # usedots -> don't do :hex translation for dot files. note: when # this option gets set, certain file names # become illegal. these are .Parent and # anything that starts with .Apple. # invisibledots -> don't do :hex translation for dot files. note: when # this option gets set, certain file names # become illegal. these are .Parent and # anything that starts with .Apple. also, dot # files created on the unix side are marked invisible. # limitsize -> limit disk size reporting to 2GB. this is # here for older macintoshes using newer # appleshare clients. yucko. # nofileid -> don't advertise createfileid, resolveid, deleteid # calls # root_preexec_close -> a non-zero return code from root_preexec close the # volume being mounted. # preexec_close -> a non-zero return code from preexec close the # volume being mounted. # nostat -> don't stat volume path when enumerating volumes list # upriv -> use unix privilege. # illegalseq -> encode illegal sequence in filename asis, # ex "\217-", which is not a valid SHIFT-JIS char, # is encoded as U\217 - # nocnidcache -> Don't store and read CNID to/from AppleDouble file. # This should not be used as it also prevents a CNID # database rebuild with `dbd`! # caseinsensitive -> The underlying FS is case insensitive (only # test with JFS in OS2 mode) # dropbox -> Allows a volume to be declared as being a "dropbox." # Note that netatalk must be compiled with dropkludge # support for this to function. Warning: This option # is deprecated and might not work as expected. # dropkludge -> same as "dropbox" # nodev -> always use 0 for device number, helps when the # device number is not constant across a reboot, # cluster, ... # # The line below sets some DEFAULT, starting with Netatalk 2.1. :DEFAULT: options:upriv,usedots # The "~" below indicates that Home directories are visible by default. # If you do not wish to have people accessing their Home directories, # please put a pound sign in front of the tilde or delete it. #~ {{ retronas_path }} retroafp options:prodos,upriv,usedots # End of File ================================================ FILE: ansible/templates/install_netatalk2x/afpd.conf.j2 ================================================ # # CONFIGURATION FOR AFPD (Netatalk 2.x) # # Each single line defines a virtual server that should be available. # Though, using "\" character, newline escaping is supported. # Empty lines and lines beginning with `#' are ignored. # Options in this file will override both compiled-in defaults # and command line options. # # # Format: # - [options] to specify options for the default server # "Server name" [options] to specify an additional server # # # The following options are available: # Transport Protocols: # -[no]tcp Make "AFP over TCP" [not] available # -[no]ddp Make "AFP over AppleTalk" [not] available. # If you have -proxy specified, specify -uamlist "" to # prevent ddp connections from working. # # -transall Make both available # # Transport Options: # -ipaddr Specifies the IP address that the server should # advertise and listens to. The default is advertise # the first IP address of the system, but to listen # for any incoming request. The network address may # be specified either in dotted-decimal format for # IPv4 or in hexadecimal format for IPv6. # This option also allows to use one machine to # advertise the AFP-over-TCP/IP settings of another # machine via NBP when used together with the -proxy # option. # -server_quantum # Specifies the DSI server quantum. The minimum # value is 1MB. The max value is 0xFFFFFFFF. If you # specify a value that is out of range, you'll get # the default value (currently the minimum). # -admingroup # Specifies the group of administrators who should # all be seen as the superuser when they log in. # Default is disabled. # -ddpaddr x.y Specifies the DDP address of the server. # the default is to auto-assign an address (0.0). # this is only useful if you're running on # a multihomed host. # -port Specifies the TCP port the server should respond # to (default is 548) # -fqdn specify a fully-qualified domain name (+optional # port). this gets discarded if the server can't # resolve it. this is not honored by appleshare # clients <= 3.8.3 (default: none) # -hostname Use this instead of the result from calling # hostname for dertermening which IP address to # advertise, therfore the hostname is resolved to # an IP which is the advertised. This is NOT used for # listening and it is also overwritten by -ipaddr. # -proxy Run an AppleTalk proxy server for specified # AFP/TCP server (if address/port aren't given, # then first IP address of the system/548 will # be used). # if you don't want the proxy server to act as # a ddp server as well, set -uamlist to an empty # string. # -dsireadbuf [number] # Scale factor that determines the size of the # DSI/TCP readahead buffer, default is 12. This is # multiplies with the DSI server quantum (default # ~300k) to give the size of the buffer. Increasing # this value might increase throughput in fast local # networks for volume to volume copies. Note: This # buffer is allocated per afpd child process, so # specifying large values will eat up large amount of # memory (buffer size * number of clients). # -tcprcvbuf [number] # Try to set TCP receive buffer using setsockpt(). # Often OSes impose restrictions on the applications # ability to set this value. # -tcpsndbuf [number] # Try to set TCP send buffer using setsockpt(). # Often OSes impose restrictions on the applications # ability to set this value. # -slp Register this server with the Service Location # Protocol (if SLP support was compiled in). # -nozeroconf Don't register this server with the Multicats # DNS Protocol. # -advertise_ssh Allows Mac OS X clients (10.3.3-10.4) to # automagically establish a tunneled AFP connection # through SSH. This option is not so significant # for the recent Mac OS X. See the Netatalk Manual # in detail. # # # Authentication Methods: # -uampath Use this path to look for User Authentication Modules. # (default: /opt/retronas/bin/netatalk2x/etc/netatalk/uams) # -uamlist Comma-separated list of UAMs. # (default: uams_dhx.so,uams_dhx2.so) # # some commonly available UAMs: # uams_guest.so: Allow guest logins # # uams_clrtxt.so: (uams_pam.so or uams_passwd.so) # Allow logins with passwords # transmitted in the clear. # # uams_randnum.so: Allow Random Number and Two-Way # Random Number exchange for # authentication. # # uams_dhx.so: (uams_dhx_pam.so or uams_dhx_passwd.so) # Allow Diffie-Hellman eXchange # (DHX) for authentication. # # uams_dhx2.so: (uams_dhx2_pam.so or uams_dhx2_passwd.so) # Allow Diffie-Hellman eXchange 2 # (DHX2) for authentication. # # Password Options: # -[no]savepassword [Don't] Allow clients to save password locally # -passwdfile Use this path to store Randnum passwords. # (Default: /opt/retronas/bin/netatalk2x/etc/netatalk/afppasswd. The only other # useful value is ~/.passwd. See 'man afppasswd' # for details.) # -passwdminlen <#> minimum password length. may be ignored. # -[no]setpassword [Don't] Allow clients to change their passwords. # -loginmaxfail <#> maximum number of failed logins. this may be # ignored if the uam can't handle it. # # AppleVolumes files: # -defaultvol Specifies path to AppleVolumes.default file # (default /opt/retronas/bin/netatalk2x/etc/netatalk/AppleVolumes.default, # same as -f on command line) # -systemvol Specifies path to AppleVolumes.system file # (default /opt/retronas/bin/netatalk2x/etc/netatalk/AppleVolumes.system, # same as -s on command line) # -[no]uservolfirst [Don't] read the user's ~/AppleVolumes or # ~/.AppleVolumes before reading # /opt/retronas/bin/netatalk2x/etc/netatalk/AppleVolumes.default # (same as -u on command line) # -[no]uservol [Don't] Read the user's volume file # -closevol Immediately unmount volumes removed from # AppleVolumes files on SIGHUP sent to the afp # master process. # # Miscellaneous: # -authprintdir Specifies the path to be used (per server) to # store the files required to do CAP-style # print authentication which papd will examine # to determine if a print job should be allowed. # These files are created at login and if they # are to be properly removed, this directory # probably needs to be umode 1777 # -guestname "user" Specifies the user name for the guest login # (default "nobody", same as -g on command line) # -loginmesg "Message" Client will display "Message" upon logging in # (no default, same as -l "Message" on commandline) # -nodebug Switch off debugging # -client_polling With this switch enabled, afpd won't advertise # that it is capable of server notifications, so that # connected clients poll the server every 10 seconds # to detect changes in opened server windows. # Note: Depending on the number of simultaneously # connected clients and the network's speed, this can # lead to a significant higher load on your network! # -sleep AFP 3.x wait number hours before disconnecting # clients in sleep mode. Default 10 hours # -tickleval Specify the tickle timeout interval (in seconds). # Note, this defaults to 30 seconds, and really # shouldn't be changed. If you want to control # the server idle timeout, use the -timeout option. # A value of 0 disables session timer tickles. # -timeout Specify the number of tickles to send before # timing out a connection. # The default is 4, therefore a connection will # timeout in 2 minutes. # -[no]icon [Don't] Use the platform-specific icon. Recent # Mac OS don't display it any longer. # -volnamelen # Max length of UTF8-MAC volume name for Mac OS X. # Note that Hangul is especially sensitive to this. # 255: limit of spec # 80: limit of generic Mac OS X (default) # 73: limit of Mac OS X 10.1, if >= 74 # Finder crashed and restart repeatedly. # Mac OS 9 and earlier is not influenced by this, # Maccharset volume names are always limitted to 27. # -[un]setuplog " []" # Specify that any message of a loglevel up to the # given loglevel should be logged to the given file. # If the filename is ommited the loglevel applies to # messages passed to syslog. # # By default (no explicit -setuplog and no buildtime # configure flag --with-logfile) afpd logs to syslog # with a default logging setup equivalent to # "-setuplog default log_info". # # If build with --with-logfile[=somefile] # (default logfile /var/log/netatalk.log) afpd # defaults to a setup that is equivalent to # "-setuplog default log_info [netatalk.log|somefile]" # # logtypes: Default, AFPDaemon, Logger, UAMSDaemon # loglevels: LOG_SEVERE, LOG_ERROR, LOG_WARN, # LOG_NOTE, LOG_INFO, LOG_DEBUG, # LOG_DEBUG6, LOG_DEBUG7, LOG_DEBUG8, # LOG_DEBUG9, LOG_MAXDEBUG # # Example: Useful default config # -setuplog "default log_info /var/log/afpd.log" # # Debugging config # -setuplog "default log_maxdebug /var/log/afpd.log" # # -signature { user: | auto } # Specify a server signature. This option is useful # while running multiple independent instances of # afpd on one machine (eg. in clustered environments, # to provide fault isolation etc.). # Default is "auto". # "auto" signature type allows afpd generating # signature and saving it to afp_signature.conf # automatically (based on random number). # "host" signature type switches back to "auto" # because it is obsoleted. # "user" signature type allows administrator to # set up a signature string manually. # Examples: three servers running on one machine: # first -signature user:USERS # second -signature user:USERS # third -signature user:ADMINS # First two servers will act as one logical AFP # service. If user logs in to first one and then # connects to second one, session will be # automatically redirected to the first one. But if # client connects to first and then to third, # will be asked for password twice and will see # resources of both servers. # Traditional method of signature generation causes # two independent afpd instances to have the same # signature and thus cause clients to be redirected # automatically to server (s)he logged in first. # -k5keytab # -k5service # -k5realm # These are required if the server supports # Kerberos 5 authentication # -ntdomain # -ntseparator # Use for eg. winbind authentication, prepends # both strings before the username from login and # then tries to authenticate with the result # through the availabel and active UAM authentication # modules. # -dircachesize entries # Maximum possible entries in the directory cache. # The cache stores directories and files. It is used # to cache the full path to directories and CNIDs # which considerably speeds up directory enumeration. # Default size is 8192, maximum size is 131072. Given # value is rounded up to nearest power of 2. Each # entry takes about 100 bytes, which is not much, but # remember that every afpd child process for every # connected user has its cache. # -fcelistener host[:port] # Enables sending FCE events to the specified host, # default port is 12250 if not specified. Specifying # mutliple listeners is done by having this option # once for each of them. # -fceevents fmod,fdel,ddel,fcre,dcre,tmsz # Speficies which FCE events are active, default is # fmod,fdel,ddel,fcre,dcre. # -fcecoalesce all|delete|create # Coalesce FCE events. # -fceholdfmod seconds # This determines the time delay in seconds which is # always waited if another file modification for the # same file is done by a client before sending an FCE # file modification event (fmod). For example saving # a file in Photoshop would generate multiple events # by itself because the application is opening, # modifying and closing a file mutliple times for # every "save". Defautl: 60 seconds. # -keepsessions Enable "Continuous AFP Service". This means the # ability to stop the master afpd process with a # SIGQUIT signal, possibly install an afpd update and # start the afpd process. Existing AFP sessions afpd # processes will remain unaffected. Technically they # will be notified of the master afpd shutdown, sleep # 15-20 seconds and then try to reconnect their IPC # channel to the master afpd process. If this # reconnect fails, the sessions are in an undefined # state. Therefor it's absolutely critical to restart # the master process in time! # -noacl2maccess Don't map filesystem ACLs to effective permissions. # # Codepage Options: # -unixcodepage Specifies the servers unix codepage, # e.g. "ISO-8859-15" or "UTF8". # This is used to convert strings to/from # the systems locale, e.g. for authenthication. # Defaults to LOCALE if your system supports it, # otherwise ASCII will be used. # # -maccodepage Specifies the legacy clients (<= Mac OS 9) # codepage, e.g. "MAC_ROMAN". # This is used to convert strings to the # systems locale, e.g. for authenthication # and SIGUSR2 messaging. This will also be # the default for volumes maccharset. # # CNID related options: # -cnidserver # Specifies the IP address and port of a # cnid_metad server, required for CNID dbd # backend. Defaults to localhost:4700. # The network address may be specified either # in dotted-decimal format for IPv4 or in # hexadecimal format for IPv6. # # Avahi (Bonjour) related options: # -mimicmodel # Specifies the icon model that appears on # clients. Defaults to off. Examples: RackMac # (same as Xserve), PowerBook, PowerMac, Macmini, # iMac, MacBook, MacBookPro, MacBookAir, MacPro, # AppleTV1,1, AirPort # # # Some examples: # # The simplest case is to not have an afpd.conf. # # 4 servers w/ names server1-3 and one w/ the hostname. servers # 1-3 get routed to different ports with server 3 being bound # specifically to address 192.168.1.3 # # - # server1 -port 12000 # server2 -port 12001 # server3 -port 12002 -ipaddr 192.168.1.3 # # a dedicated guest server, a user server, and a special # AppleTalk-only server: # # "Guest Server" -uamlist uams_guest.so \ # -loginmesg "Welcome guest! I'm a public server." # "User Server" -uamlist uams_dhx2.so -port 12000 # "special" -ddp -notcp -defaultvol -systemvol # # default: # - -tcp -noddp -uamlist uams_dhx.so,uams_dhx2.so - -transall -hostname "retroafp" -uamlist uams_guest.so,uams_clrtxt.so,uams_randnum.so,uams_dhx.so,uams_dhx2.so ================================================ FILE: ansible/templates/install_netatalk2x/afpexpect.sh.j2 ================================================ #!/usr/bin/expect -f set timeout -1 set USERNAME [lindex $argv 0] set PASSWORD [lindex $argv 1] spawn /opt/retronas/bin/netatalk2x/bin/afppasswd -a $USERNAME expect "Enter NEW AFP password:" send "$PASSWORD\r" expect "Enter NEW AFP password again:" send "$PASSWORD\r" expect eof ================================================ FILE: ansible/templates/install_netatalk2x/atalkd.conf.j2 ================================================ # # Format of lines in this file: # # interface [ -seed ] [ -router | -dontroute ] # [ -phase { 1 | 2 } ] [ -addr net.node ] # [ -net first[-last] ] [ -zone ZoneName ] ... # # -seed only works if you have multi-interfaces. Any missing arguments are # automatically configured from the network. Note: lines can't actually be # split, tho it's a good idea. # # -router is like -seed but it allows single-interface routing. -dontroute # disables routing for the specified interface. # # Some examples: # # The simplest case is no atalkd.conf. This works on most platforms # (notably not Solaris), since atalkd can discover the local interfaces # on the machine. # # Very slightly more complicated: # # le0 # or # eth0 # # for Solaris/SunOS or Linux. # # A much more complicated example: # # le0 -phase 1 # le1 -seed -phase 2 -addr 66.6 -net 66-67 -zone "No Parking" # # This turns on transition routing between the le0 and le1 # interfaces on a Sun. It also causes atalkd to fail if other # routers disagree about it's configuration of le1. # {{ ansible_default_ipv4.interface }} -router -phase 2 -net 1 -zone "retroafp" ================================================ FILE: ansible/templates/install_netatalk2x/default.j2 ================================================ # Netatalk 2.x configuration ######################################################################### # Global configuration ######################################################################### #### machine's AFPserver/AppleTalk name. ATALK_NAME=retroafp #### server (unix) and legacy client (<= Mac OS 9) charsets ATALK_UNIX_CHARSET='LOCALE' ATALK_MAC_CHARSET='MAC_ROMAN' #### Don't Edit. export the charsets, read form ENV by apps export ATALK_UNIX_CHARSET export ATALK_MAC_CHARSET ######################################################################### # AFP specific configuration ######################################################################### #### Set which daemons to run. #### If you use AFP file server, run both cnid_metad and afpd. CNID_METAD_RUN=yes AFPD_RUN=yes #### maximum number of clients that can connect: #AFPD_MAX_CLIENTS=20 #### UAMs (User Authentication Modules) #### available options: uams_dhx.so, uams_dhx2.so, uams_guest.so, #### uams_clrtxt.so(legacy), uams_randnum.so(legacy) AFPD_UAMLIST="-U uams_dhx2.so,uams_clrtxt.so,uams_dhx.so,uams_guest.so,uams_randnum.so" #### Set the id of the guest user when using uams_guest.so #AFPD_GUEST=nobody #### config for cnid_metad. Default log config: #CNID_CONFIG="-l log_note" ######################################################################### # AppleTalk specific configuration (legacy) ######################################################################### #### Set which legacy daemons to run. #### If you need AppleTalk, run atalkd. #### papd, timelord and a2boot are dependent upon atalkd. ATALKD_RUN=yes PAPD_RUN=yes TIMELORD_RUN=yes A2BOOT_RUN=yes #### Control whether the daemons are started in the background. #### If it is dissatisfied that legacy atalkd starts slowly, set "yes". #### In case using systemd/systemctl, this is not so significant. ATALK_BGROUND=yes #### Set the AppleTalk Zone name. #### NOTE: if your zone has spaces in it, you're better off specifying #### it in atalkd.conf #ATALK_ZONE=@zone ================================================ FILE: ansible/templates/install_netatalk2x/install_netatalk2x.sh.j2 ================================================ #!/bin/bash ## RetroNAS Netatalk-2.x install script # Set world readable/executable umask umask 0022 # Set the install dir IDIR="{{ retronas_root }}/bin/netatalk2x" mkdir -p "${IDIR}" # make/clean the source build location mkdir -p "{{ retronas_root }}/src" cd "{{ retronas_root }}/src" rm -rf Netatalk-2.x # Clone the source code from SourceForge git clone https://github.com/rdmark/Netatalk-2.x.git cd Netatalk-2.x git checkout $(git tag | grep netatalk-2 | tail -n1) ./bootstrap ./configure --prefix=${IDIR} --enable-systemd --enable-ddp --enable-a2boot --enable-cups --enable-timelord --enable-zeroconf make -j$(nproc) make install ================================================ FILE: ansible/templates/install_netatalk3/install_netatalk3.sh.j2 ================================================ #!/bin/bash ## RetroNAS Netatalk-3 install script TRKRVER=$(dpkg -l | awk -F'-' '/libtracker-miner/{print $3}') # Set world readable/executable umask umask 0022 # Set the install dir IDIR="{{ retronas_root }}/bin/netatalk3" mkdir -p "${IDIR}" # make/clean the source build location mkdir -p "{{ retronas_root }}/src" cd "{{ retronas_root }}/src" rm -rf netatalk # Clone the source code from SourceForge git clone https://github.com/netatalk/netatalk.git cd netatalk git checkout $(git tag | grep netatalk-3 | tail -n1) OPTIONS=() OPTIONS+=" --prefix=${IDIR}" OPTIONS+=" --with-init-style=debian-systemd" OPTIONS+=" --without-libevent" OPTIONS+=" --without-tdb" OPTIONS+=" --with-cracklib" OPTIONS+=" --enable-krbV-uam" OPTIONS+=" --with-pam-confdir=/etc/pam.d" OPTIONS+=" --with-dbus-daemon=/usr/bin/dbus-daemon" OPTIONS+=" --with-dbus-sysconf-dir=/etc/dbus-1/system.d" # spotlight support requires libtracker-miner if [ ! -z $TRKRVER ] then [ ! -f /usr/bin/tracker ] && ln -sf /usr/bin/tracker3 /usr/bin/tracker OPTIONS+=" --with-tracker-pkgconfig-version=$TRKRVER" fi ./bootstrap ./configure $OPTIONS make -j$(nproc) make install ================================================ FILE: ansible/templates/install_netatalk3/netatalk.service.j2 ================================================ [Unit] Description=Netatalk AFP fileserver for Macintosh clients Documentation=man:afp.conf(5) man:netatalk(8) man:afpd(8) man:cnid_metad(8) man:cnid_dbd(8) Documentation=http://netatalk.sourceforge.net/ After=network.target avahi-daemon.service [Service] Type=forking GuessMainPID=no ExecStart={{ retronas_root }}/bin/netatalk3/sbin/netatalk PIDFile=/var/lock/netatalk ExecReload=/bin/kill -HUP $MAINPID Restart=always RestartSec=1 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_netatalk3/retronas.conf.j2 ================================================ ## RetroNAS config ## This is autogenerated. Changes will be lost. [retronas] path = {{ retronas_path }} rwlist = {{ retronas_user }} ================================================ FILE: ansible/templates/install_netatalk4/atalkd.service.j2 ================================================ [Unit] Description=Netatalk Appletalk service Documentation=man:atalkd.conf(5) Documentation=https://netatalk.io/ After=network.target avahi-daemon.service Before=netatalk.service [Service] Type=forking GuessMainPID=no ExecStart={{ retronas_root }}/bin/netatalk4/sbin/atalkd PIDFile=/var/lock/atalkd ExecReload=/bin/kill -HUP $MAINPID Restart=always RestartSec=1 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_netatalk4/install_netatalk4.sh.j2 ================================================ #!/bin/bash ## RetroNAS Netatalk-4 install script TRKRVER=$(dpkg -l | awk -F'-' '/libtracker-miner/{print $3}') # Set world readable/executable umask umask 0022 # Set the install dir IDIR="{{ retronas_root }}/bin/netatalk4" mkdir -p "${IDIR}" # make/clean the source build location mkdir -p "{{ retronas_root }}/src" cd "{{ retronas_root }}/src" rm -rf netatalk # Clone the source code from SourceForge git clone https://github.com/netatalk/netatalk.git cd netatalk git checkout $(git describe --tags --abbrev=0 | grep netatalk-4 | tail -n1) OPTIONS="" OPTIONS+=" -Dprefix=${IDIR}" OPTIONS+=" -Dwith-appletalk=true" OPTIONS+=" -Dwith-zeroconf=true" OPTIONS+=" -Dwith-spotlight=true" OPTIONS+=" -Dwith-init-style=systemd" OPTIONS+=" -Dwith-cracklib=true" OPTIONS+=" -Dwith-krbV-uam=true" OPTIONS+=" -Dwith-pam-config-path=/etc/pam.d" # as per https://dbus.freedesktop.org/doc/dbus-daemon.1.html OPTIONS+=" -Dwith-dbus-daemon-path=/usr/bin/dbus-daemon" OPTIONS+=" -Dwith-dbus-sysconf-path=/usr/share/dbus-1/system.d" # spotlight support requires libtracker-miner if [ ! -z $TRKRVER ] then [ ! -f /usr/bin/tracker ] && ln -sf /usr/bin/tracker3 /usr/bin/tracker OPTIONS+=" --with-tracker-pkgconfig-version=$TRKRVER" fi meson setup build $OPTIONS meson compile -C build if [ $? -eq 0 ] then sudo meson install -C build exit 0 fi echo "Build failed! exiting" exit 1 ================================================ FILE: ansible/templates/install_netatalk4/netatalk.service.j2 ================================================ [Unit] Description=Netatalk AFP fileserver Documentation=man:afp.conf(5) man:netatalk(8) man:afpd(8) man:cnid_metad(8) man:cnid_dbd(8) Documentation=https://netatalk.io/ After=network.target avahi-daemon.service atalkd.service [Service] Type=forking GuessMainPID=no ExecStart={{ retronas_root }}/bin/netatalk4/sbin/netatalk PIDFile=/var/lock/netatalk ExecReload=/bin/kill -HUP $MAINPID Restart=always RestartSec=1 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_netatalk4/retronas.conf.j2 ================================================ ## RetroNAS config ## This is autogenerated. Changes will be lost. [retronas] path = {{ retronas_path }} rwlist = {{ retronas_user }} ================================================ FILE: ansible/templates/install_netlink/install_netlink.sh.j2 ================================================ #!/bin/bash # still based on https://github.com/Kazade/dreampi/issues/17 DPITMP=$(mktemp -d) OUTDIR=/opt/netlink # clone the repo and switch to the python3 branch cd $DPITMP SOURCECODE=$( curl -kLs https://api.github.com/repos/eaudunord/Netlink/releases | jq -r ".[0].assets | map(select(.name | match (\"Netlink_Tunnel\")))[-1] | .browser_download_url" ) [ -z "$SOURCECODE" ] && echo "Couldn't get source code name" && exit 1 echo $SOURCECODE RELEASE=$(basename "${SOURCECODE}") [ ! -f $RELEASE ] && curl -OJL "${SOURCECODE}" # unpack and clean [ ! -d $OUTDIR ] && mkdir -p $OUTDIR unzip $RELEASE -x "*/winPython/*" "*.bat" cp -R Netlink_Tunnel*/* $OUTDIR/ # xband.py is missind the from the 4.4 release if [ ! -f $OUTDIR/xband.py ] then curl -o$OUTDIR/xband.py https://raw.githubusercontent.com/eaudunord/Netlink/refs/heads/main/tunnel/xband.py fi # pull python3 requirements from dreampi curl -O https://raw.githubusercontent.com/sairuk/dreampi/master/requirements.txt python3 -m pip install -r requirements.txt ================================================ FILE: ansible/templates/install_netlink/netlink.conf.j2 ================================================ domain-needed bogus-priv server=46.101.91.123 no-resolv no-hosts cache-size=500 log-queries ================================================ FILE: ansible/templates/install_netlink/netlink.patch.j2 ================================================ --- tunnel.py 2022-12-03 21:45:41.763778651 +0000 +++ tunnel.py 2022-09-26 14:29:52.000000000 +0100 @@ -67,7 +67,7 @@ def com_scanner(): global com_port speed = 115200 - for i in range(1,25): # this should be a big enough range. USB com ports usually end up in the teens. + for i in range(0,25): # this should be a big enough range. USB com ports usually end up in the teens. osName = os.name if osName == 'posix': # should work on linux and Mac for USB modem, but untested. com_port = "/dev/ttyACM%s" % i ================================================ FILE: ansible/templates/install_netlink/netlink.service.j2 ================================================ [Unit] Description=netlink for Sega Saturn After=network.target [Service] WorkingDirectory=/opt/netlink ExecStart=/usr/bin/python3 /opt/netlink/tunnel.py noUpdate Restart=on-failure RestartSec=30s [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_netmount/install_netmount.sh.j2 ================================================ #!/bin/bash set -u DEST=/opt/netmount TDIR=$(mktemp -d) OWNER=jrohel REPO=NetMount echo "Downloading release ..." ARCH=$(uname -m) RELEASE=$( curl -kLs https://api.github.com/repos/${OWNER}/${REPO}/releases | jq -r ".[0].assets | map(select(.name | match (\"netmount.*linux-${ARCH}\")))[-1] | .browser_download_url" ) [ -z "$RELEASE" ] && echo "Couldn't get release for arch: ${ARCH}" && exit 1 cd ${TDIR} REL_NAME="$(basename ${RELEASE})" if `curl -OJL "${RELEASE}"` then [ ! -d ${DEST} ] && mkdir -p ${DEST} bzip2 -d ${REL_NAME} rm netmount*.bz2 mv netmount* ${DEST}/ chmod +x ${DEST}/netmount* find ${DEST} -executable -type f -iname "netmount*" -exec ln -s {} ${DEST}/netmount \; rm -rf ${TDIR} exit 0 fi echo "Install failed!" exit 1 ================================================ FILE: ansible/templates/install_netmount/netmount-confman.py.j2 ================================================ #!/usr/bin/env python3 import os import yaml import argparse # # this is written specifically for RetroNAS use it is fairly basic and hacky # however some basic flexibilty is provided # - sai failed = False output_types = ["systemd"] binpath = "/opt/netmount/netmount" def log(s): print(s) def error(s): log(f"ERROR: {s}") failed = True def check_state(): if failed: exit(1) def gen_systemd(cli, service_name="netmount"): systemd_path = "/etc/systemd/system" if not os.access(systemd_path, os.W_OK): error(f"Path not writable: {systemd_path}") check_state() service_file = os.path.join(systemd_path,f"{service_name.lower()}.service") log(f"Writing {service_file}") ncli = " ".join([binpath, cli]) with open(service_file, "w") as f: f.write(f"""[Unit] Description={service_name} After=multi-user.target [Service] User=retronas Type=simple Restart=always ExecStart={ncli} TimeoutStartSec=0 RemainAfterExit=yes [Install] WantedBy=multi-user.target """) def format_cli(d): cli = [] # program options prog_options = [] if "options" in d: for opt in d["options"]: prog_options.append(f"--{opt}={d['options'][opt]}") cli.append(" ".join(prog_options)) drives = [] for drive in d["drives"]: if "letter" not in drive: error("letter: must be defined in config") if "path" not in drive: error("path: must be defined in config") check_state() # drive options letter = drive["letter"] drive.pop("letter") path = drive["path"] drive.pop("path") drive_options = [] for do in drive: drive_options.append(f"{do}={drive[do]}") drive_options = ",".join(drive_options) drives.append(",".join([f"{letter}={path}",drive_options])) cli = cli + drives return(" ".join(cli)) def main(args): conf = args.conf_dir output = args.output_type for root, dirs, files in os.walk(conf): for filename in files: abs = os.path.join(root, filename) y = {} try: with open(abs,'r') as f: y = yaml.safe_load(f) except: error(f"Failed to read yaml in {conf}") check_state() if not "drives" in y: error("Invalid drive configuration file, drives: not found") check_state() cli = format_cli(y) check_state() if output == "systemd": gen_systemd(cli, y["name"]) else: error(f"Unsupported mode {output}") check_state() if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('--conf-dir', type=str, help='directory holding yaml configs for drives', default="{{ retronas_path }}/config/netmount") parser.add_argument('--output-type', type=str, help='output type', choices=output_types, default="systemd") args = parser.parse_args() main(args) ================================================ FILE: ansible/templates/install_netmount/netmount-confman.sh.j2 ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh CLEAR python3 /opt/retronas/scripts/netmount-confman.py systemctl daemon-reload PAUSE ================================================ FILE: ansible/templates/install_netmount/retronas.yaml.j2 ================================================ name: netmount-drives-retronas drives: - letter: R path: {{ retronas_path }}/dos label: RETRONAS options: translit-map-path: /opt/netmount/netmount-u2a.map ================================================ FILE: ansible/templates/install_network-presets-standalone/dhcpcd.conf.j2 ================================================ # A sample configuration for dhcpcd. # See dhcpcd.conf(5) for details. # Allow users of this group to interact with dhcpcd via the control socket. #controlgroup wheel # Inform the DHCP server of our hostname for DDNS. hostname # Use the hardware address of the interface for the Client ID. clientid # or # Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361. # Some non-RFC compliant DHCP servers do not reply with this set. # In this case, comment out duid and enable clientid above. #duid # Persist interface configuration when dhcpcd exits. persistent # Rapid commit support. # Safe to enable by default because it requires the equivalent option set # on the server to actually work. option rapid_commit # A list of options to request from the DHCP server. option domain_name_servers, domain_name, domain_search, host_name option classless_static_routes # Respect the network MTU. This is applied to DHCP routes. option interface_mtu # Most distributions have NTP support. #option ntp_servers # A ServerID is required by RFC2131. require dhcp_server_identifier # Generate SLAAC address using the Hardware Address of the interface #slaac hwaddr # OR generate Stable Private IPv6 Addresses based from the DUID slaac private # Example static IP configuration: #interface eth0 #static ip_address=192.168.0.10/24 #static ip6_address=fd51:42f8:caae:d92e::ff/64 #static routers=192.168.0.1 #static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e::1 # It is possible to fall back to a static IP if DHCP fails: # define static profile #profile static_eth0 #static ip_address=192.168.1.23/24 #static routers=192.168.1.1 #static domain_name_servers=192.168.1.1 # fallback to static profile on eth0 #interface eth0 #fallback static_eth0 # # retro lan interface {{ retronas_net_retro_interface }} static ip_address={{ retronas_net_retro_ip }}/{{ retronas_net_retro_subnet }} #static routers={{ retronas_net_retro_router }} static domain_name_servers={{ retronas_net_retro_dns }} # retro wifi interface {{ retronas_net_wifi_interface }} static ip_address={{ retronas_net_wifi_ip }}/{{ retronas_net_wifi_subnet }} static routers={{ retronas_net_wifi_router }} static domain_name_servers={{ retronas_net_wifi_dns }} ================================================ FILE: ansible/templates/install_network-presets-zoned/dhcpcd.conf.j2 ================================================ # A sample configuration for dhcpcd. # See dhcpcd.conf(5) for details. # Allow users of this group to interact with dhcpcd via the control socket. #controlgroup wheel # Inform the DHCP server of our hostname for DDNS. hostname # Use the hardware address of the interface for the Client ID. clientid # or # Use the same DUID + IAID as set in DHCPv6 for DHCPv4 ClientID as per RFC4361. # Some non-RFC compliant DHCP servers do not reply with this set. # In this case, comment out duid and enable clientid above. #duid # Persist interface configuration when dhcpcd exits. persistent # Rapid commit support. # Safe to enable by default because it requires the equivalent option set # on the server to actually work. option rapid_commit # A list of options to request from the DHCP server. option domain_name_servers, domain_name, domain_search, host_name option classless_static_routes # Respect the network MTU. This is applied to DHCP routes. option interface_mtu # Most distributions have NTP support. #option ntp_servers # A ServerID is required by RFC2131. require dhcp_server_identifier # Generate SLAAC address using the Hardware Address of the interface #slaac hwaddr # OR generate Stable Private IPv6 Addresses based from the DUID slaac private # Example static IP configuration: #interface eth0 #static ip_address=192.168.0.10/24 #static ip6_address=fd51:42f8:caae:d92e::ff/64 #static routers=192.168.0.1 #static domain_name_servers=192.168.0.1 8.8.8.8 fd51:42f8:caae:d92e::1 # It is possible to fall back to a static IP if DHCP fails: # define static profile #profile static_eth0 #static ip_address=192.168.1.23/24 #static routers=192.168.1.1 #static domain_name_servers=192.168.1.1 # fallback to static profile on eth0 #interface eth0 #fallback static_eth0 # # retro lan interface {{ retronas_net_retro_interface }} static ip_address={{ retronas_net_retro_ip }}/{{ retronas_net_retro_subnet }} #static routers={{ retronas_net_retro_router }} static domain_name_servers={{ retronas_net_retro_dns }} ================================================ FILE: ansible/templates/install_nfs/exports.j2 ================================================ ## Automatically created by RetroNAS ## Changes will be lost {{ retronas_path }} *(rw,async,fsid=99,all_squash,anonuid={{ retronas_user_id }},anongid={{ retronas_group_id }}) ================================================ FILE: ansible/templates/install_nfs/nfs-kernel-server.j2 ================================================ ## Automatically created by RetroNAS ## Changes will be lost # Number of servers to start up RPCNFSDCOUNT="8 -V 2" # Runtime priority of server (see nice(1)) RPCNFSDPRIORITY=0 # Options for rpc.mountd. # If you have a port-based firewall, you might want to set up # a fixed port here using the --port option. For more information, # see rpc.mountd(8) or http://wiki.debian.org/SecuringNFS # To disable NFSv4 on the server, specify '--no-nfs-version 4' here RPCMOUNTDOPTS="--manage-gids" # Do you want to start the svcgssd daemon? It is only required for Kerberos # exports. Valid alternatives are "yes" and "no"; the default is "no". NEED_SVCGSSD="" # Options for rpc.svcgssd. RPCSVCGSSDOPTS="" ================================================ FILE: ansible/templates/install_open-iscsi/iscsi-manager-target-login.sh.j2 ================================================ #!/bin/bash SERVERIP=${1:-} USERNAME="" PASSWORD="" IQN="" TARGET="" ISCSICFG=/etc/iscsi/nodes list_targets() { IFS=$'\n' TARGETS=($(iscsiadm -m discovery -t st -p $1 2>/dev/null | awk -F ' ' /$SERVERIP/'{print $2" ("$1")"}') quit) [ {{ ''.join (('$','{', '#TARGETS[@]}')) }} -le 1 ] && echo "No targets found, exiting ... " && exit 1 select TARGET in "${TARGETS[@]}" do IQN="$(echo ${TARGET} | awk -F ' ' '{print $1}')" [ $IQN == "quit" ] && echo "User requested exit ..." && exit 0 [ ! -z "${IQN}" ] && break done } check_target() { iscsiadm -m session | grep -E "${SERVERIP}.*${IQN}" &>/dev/null if [ $? -eq 0 ] then echo "Target is already connected, nothing to do, exiting ..." exit 0 fi } login_target() { check_target iscsiadm -m node -T $IQN -p $SERVERIP --login &>/dev/null DEFAULTPATH="${ISCSICFG}/${IQN}/${SERVERIP}*/default" if [ $? -eq 0 ] then if [ -f ${DEFAULTPATH} ] then sed -i -r 's/node.conn\[0\].startup.*/node.conn[0].startup = automatic/' ${DEFAULTPATH} else echo "default node profile for ${TARGET} not found, cannot update node startup settings" fi else echo "login to target failed, not enabling on startup" fi } get_ip() { read -r -p "Enter ISCSI target host ip address [ip:port (default:3620)]: " SERVERIP } get_up() { read -r -p "does your ISCSI target required credentials?" ANSWER case ANSWER in Yy) read -r -p "Enter ISCSI target username: " USERNAME read -r --password -p "Enter ISCSI target password: " PASSWORD ;; *) ;; esac } [ -z "$SERVERIP" ] && get_ip #[ -z "$USERNAME"] || [ -z "$PASSWORD" ] && get_up list_targets $SERVERIP login_target $IQN ================================================ FILE: ansible/templates/install_pfsshell/install_pfsshell.sh.j2 ================================================ #!/bin/bash set -u APP=pfsshell REPO=https://github.com/ps2homebrew/${APP}.git OUTPATH=/tmp function _log { echo "$1" } ### REQUIREMENTS REQFAIL=0 #[ ! -x /usr/bin/gmake ] && _log "GMAKE not found" && REQFAIL=1 [ $REQFAIL -ne 0 ] && _log "Requirements failed, see previous errors" && exit $REQFAIL cd $OUTPATH if [ ! -f ${OUTPATH}/${APP}/.git/config ] then git clone $REPO else cd ${OUTPATH}/${APP} git pull fi cd ${OUTPATH}/${APP} git submodule update --remote meson setup -Denable_pfsfuse=true build ninja -C build ninja -C build install # CLEAN UP rm -Rf ${OUTPATH}/${APP} ================================================ FILE: ansible/templates/install_pi1541/pi1541.sh.j2 ================================================ #!/bin/bash # # PI1541 installer # set -u clear TMPFILES={{ retronas_path }}/pi1541 TARGET=/mnt/pi1541 MOUNT_DRIVE() { echo "Mounting drive /dev/$1 at $TARGET" MNTPOINT=$(mount | grep $1 | awk '{print $3}') if [ ! -z "${MNTPOINT}" ] then echo "Drive already mounted at $MNTPOINT, wont mount" else echo "Drive not mounted, will mount to $TARGET" mkdir -p $TARGET mount -t vfat /dev/$1 $TARGET [ $? -eq 0 ] && echo " Done" fi } INSTALL_PI1541() { local ARCHIVE=Pi1541.zip cd $TMPFILES echo "Pi1541 software" if [ ! -f $TMPFILES/$ARCHIVE ] then echo " $ARCHIVE not found downloading to $TMPFILES" curl -sO https://cbm-pi1541.firebaseapp.com/$ARCHIVE fi echo " Installing $ARCHIVE to $TARGET" unzip -qq -o $ARCHIVE cp -R Pi1541/* $TARGET/ [ $? -eq 0 ] && echo " Done" rm -rf Pi1541/ } INSTALL_FIRMWARE() { local ARCHIVE=1.20180919.zip cd $TMPFILES echo "RPI firmware" if [ ! -f $TMPFILES/$ARCHIVE ] then echo " $ARCHIVE not found downloading to $TMPFILES" curl -sLO https://github.com/raspberrypi/firmware/archive/$ARCHIVE [ $? -eq 0 ] && echo " Done" fi echo " Installing required RPI firmware to $TARGET" unzip -qq -o -j $ARCHIVE firmware-*/boot/{bootcode.bin,fixup.dat,start.elf} -d $TARGET/ [ $? -eq 0 ] && echo " Done" } INSTALL_ROM() { local ARCHIVE=vice-tmp.zip cd $TMPFILES echo "Drive firmware and font files" if [ ! -f $TMPFILES/$ARCHIVE ] then echo " $ARCHIVE not found downloading to $TMPFILES" curl -sL -o $ARCHIVE https://sourceforge.net/projects/vice-emu/files/latest/download [ $? -eq 0 ] && echo " Done" fi echo " Installing drive rom" unzip -qq -o -j $ARCHIVE "*/DRIVES/dos1541" -d $TARGET/ [ $? -eq 0 ] && echo " Done" echo " Installing CBM font" unzip -qq -o -j $ARCHIVE "*/C64/chargen" -d $TARGET/ [ $? -eq 0 ] && echo " Done" } CONFIG_OPTIONB() { read -p "Configure cable Option B support? [y/N]: " ANSWER case $ANSWER in y|Y) sed -i -r 's/\/\/(splitIECLines)/\1/' $TARGET/options.txt [ $? -eq 0 ] && echo " Done" ;; *) INSTALL_ROMS ;; esac } INSTALL_ROMS() { SYSTEMS=( commodore64 commodore128 commodore16 commodoreplus4 vic20 exit ) echo "Select a system to copy roms for to the $TARGET" select SYSTEM in "${SYSTEMS[@]}" do [ $SYSTEM == "exit" ] && echo "Exiting..." && CLEANUP ROMPATH="{{ retronas_path }}/roms/commodore/$SYSTEM" echo "$(df -h | grep "$TARGET" | awk '{print $1, "has", $4, "free"}') $(du -hs $ROMPATH | awk '{print $1, "is required"}')" read -p "Continue? [y/N]: " ANSWER case $ANSWER in y|Y) if [ ! -z "$SYSTEM" ] then ROMSYS="$TARGET/1541/$SYSTEM" echo "Copying roms from $ROMPATH" [ ! -d "$ROMSYS" ] && mkdir -p "$ROMSYS" cp -R "$ROMPATH/"* "$ROMSYS" [ $? -eq 0 ] && echo " Done" INSTALL_ROMS fi ;; *) INSTALL_ROMS ;; esac done } CLEANUP() { echo "Unmounting $TARGET" umount $TARGET rmdir $TARGET exit 0 } SELECT_DRIVE() { FAT32DEVS=($(lsblk -f -r | grep -v boot | awk '/FAT32/{print $1}' ) exit) {# this workaround is for broken bash array count support in jinja #} if [ {{ ['${','#FAT32DEVS[@]}']|join('') }} -le 1 ] then echo "No available FAT32 drives found, insert one and run this script again" sleep 3 exit 1 fi echo "Available FAT32 devices:" select DRIVE in "${FAT32DEVS[@]}" do [ $DRIVE == "exit" ] && echo "Exiting..." && exit 0 read -p "($DRIVE) Are you sure? [y/N]: " ANSWER case $ANSWER in y|Y) if [ ! -z "$DRIVE" ] then MOUNT_DRIVE $DRIVE INSTALL_FIRMWARE INSTALL_PI1541 INSTALL_ROM CONFIG_OPTIONB INSTALL_ROMS CLEANUP fi exit ;; *) SELECT_DRIVE $1 ;; esac done } cat << TITLE ********************************************* * * Pi1541 installer * * You will be prompted for a drive to setup * for use with Pi1541 * ********************************************* TITLE SELECT_DRIVE ================================================ FILE: ansible/templates/install_piscsi/install_piscsi.sh.j2 ================================================ #!/bin/bash set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh APP=piscsi REPO=https://github.com/PiSCSI/${APP}.git SRCDIR={{ retronas_root }}/src/ RPI=0 CONNECT_TYPE=${1:-fullspec} OUTDIR={{ retronas_root }}/bin/${APP} function _log { echo "$1" } ### REQUIREMENTS REQFAIL=0 [ $REQFAIL -ne 0 ] && _log "Requirements failed, see previous errors" && exit $REQFAIL if `grep -Eqq "^Raspberry.*" /proc/device-tree/model` then # X64 remote access build flags # EXTRA_FLAGS="-DSPDLOG_FMT_EXTERNAL -DFMT_HEADER_ONLY" _log "Unsupported OS, only for RPI" sleep 3 exit 1 fi [ ! -d $SRCDIR ] && mkdir -p $SRCDIR cd $SRCDIR if [ ! -f ${SRCDIR}/${APP}/.git/config ] then git clone $REPO else cd ${SRCDIR}/${APP} git clean -d -f git reset --hard git checkout main git pull fi LATEST=$(git tag | tail -n1) git checkout $LATEST # BUILD TYPE case $CONNECT_TYPE in fullspec) # FULL SPEC BOARD CONNECT_TYPE_BUILD=FULLSPEC ;; standard) # STANDARD BOARD CONNECT_TYPE_BUILD=STANDARD ;; *) _log "Please pass a board type fullspec or standard" exit 1 esac # PATCH MAKEFILE #git apply -3 {{ retronas_root }}/src/piscsi_retronas_patch.diff # BUILD #BUILD_DIR=${SRCDIR}/${APP}/src/raspberrypi BUILD_DIR=${SRCDIR}/${APP}/cpp/ cd ${BUILD_DIR} make clean make all CONNECT_TYPE=${CONNECT_TYPE_BUILD} -j$(nproc) # Copy BINs if [ -f ${BUILD_DIR}/bin/piscsi ] then [ ! -d "${OUTDIR}" ] && mkdir -p "${OUTDIR}" SERVICE=piscsi.service STARTED=$(systemctl show $SERVICE --full --property SubState --value) [ $STARTED == "running" ] && systemctl stop $SERVICE cp -f ${BUILD_DIR}/bin/* "${OUTDIR}/" systemctl restart $SERVICE fi ================================================ FILE: ansible/templates/install_piscsi/install_piscsi_standard.sh.j2 ================================================ #!/bin/bash ./install_piscsi.sh standard ================================================ FILE: ansible/templates/install_piscsi/piscsi.service.j2 ================================================ [Unit] Description=piscsi After=multi-user.target [Service] Type=simple Restart=always WorkingDirectory={{ retronas_root }}/bin/piscsi Environment=PATH=$PATH:{{ retronas_root }}/bin/piscsi ExecStart={{ retronas_root }}/bin/piscsi/piscsi -F /home/{{ retronas_user }}/piscsi -P /etc/piscsi_passwd TimeoutStartSec=0 RemainAfterExit=yes [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_piscsi/piscsi_retronas_patch.diff.j2 ================================================ diff --git a/src/raspberrypi/Makefile b/src/raspberrypi/Makefile index 5a09b4a..33c16cb 100644 --- a/src/raspberrypi/Makefile +++ b/src/raspberrypi/Makefile @@ -9,8 +9,8 @@ GCCVERSION10 := $(shell expr `gcc -dumpversion` \>= 10) ## arm-linux-gnueabihf- CROSS_COMPILE = -CC = $(CROSS_COMPILE)gcc -CXX = $(CROSS_COMPILE)g++ +CC = $(CROSS_COMPILE)gcc-9 +CXX = $(CROSS_COMPILE)g++-9 ## DEBUG=1 : A Debug build includes the debugger symbols ## and disables compiler optimization. Typically, @@ -22,7 +22,7 @@ ifeq ($(DEBUG), 1) BUILD_TYPE = Debug else # Release compiler flags - CXXFLAGS += -O3 -Wall -Werror -Wextra -DNDEBUG + CXXFLAGS += -O3 -Wall -Wextra -DNDEBUG BUILD_TYPE = Release endif ifeq ("$(shell uname -s)","Linux") ================================================ FILE: ansible/templates/install_proftpd/ftp.service.j2 ================================================ retroftp _ftp._tcp 21 ================================================ FILE: ansible/templates/install_proftpd/retronas.conf.j2 ================================================ ## RetroNAS Configuration ## This is autogenerated. Changes will be lost. # Listen on all IPs DefaultAddress 0.0.0.0 # Set the server name ServerName "RetroNAS" # Set the path for authorised users DefaultRoot "{{ retronas_path }}" # Set the Linux on-disk permissions to match the RetroNAS user User "{{ retronas_user }}" Group "{{ retronas_group }}" # Allow writes from the RetroNAS user AllowUser "{{ retronas_user }}" # Set the path and read-only for anonymous user # Don't require password for anonymous AnonRequirePassword off # Map read-only permissions to RetroNAS user UserAlias anonymous "{{ retronas_user }}" # Deny writes for anonymous user DenyAll ================================================ FILE: ansible/templates/install_ps2_openps2loader/retronas_ps2.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. comment = ps2 path = {{ retronas_path }}/ps2/OpenPS2Loader guest ok = no browseable = yes write list = {{ retronas_user }} writeable = yes valid users = {{ retronas_user }} create mask = 0775 directory mask = 0775 follow symlinks = yes wide links = yes strict sync = no sync always = yes ================================================ FILE: ansible/templates/install_ps2_udpbd/install_ps2_udpbd.sh.j2 ================================================ #!/bin/bash SRCDIR="{{ retronas_root }}/src" BINDIR="{{ retronas_root }}/bin" REPO="https://gitlab.com/ps2max/udpbd-server.git" BASE=$( basename $REPO .git ) ARCH=$(uname -m) echo "Configuring build directories..." rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Downloading {{ my_name }} source code... from $REPO" git clone $REPO cd $BASE make build if [ -f build/udpbd-server.${ARCH} ] then echo "Moving binary to RetroNAS bin dir..." mkdir -p "${BINDIR}" 2>/dev/null mv -vf build/udpbd-server.${ARCH} "${BINDIR}"/udpbd-server echo "Cleaning up..." rm -rf "${SRCDIR}" echo "All done!" else echo "Build failed" fi ================================================ FILE: ansible/templates/install_ps2_udpbd/ps2_udpbd.service.j2 ================================================ [Unit] Description=UDPBD for PlayStation2 After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] User={{ retronas_user }} Environment="UDPBD_DEVICE={{ retronas_path }}/{{ my_name }}/retronas_udpbd.img" ExecStart={{ retronas_root }}/bin/udpbd-server ${UDPBD_DEVICE} Restart=on-failure RestartSec=1 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_ps2_udpbd/udpbd_manager.sh.j2 ================================================ #!/bin/bash select_device() { IFS=$'\n' DEVICE=() DEVICES+=($(lsblk -sl 2>/dev/null | awk '/(disk|part|rom)/{print $1" ("$4")"}' | sort -u)) DEVICES+=($(ls -la {{ retronas_path }}/images/* 2>/dev/null | awk '{print $9}')) DEVICES+=("quit") [ {{ ''.join (('$','{', '#DEVICES[@]}')) }} -le 1 ] && echo "No targets found, exiting ... " && exit 1 select SDEVICE in "${DEVICES[@]}" do DEVICE="$(echo ${SDEVICE} | awk -F ' ' '{print $1}')" [ $SDEVICE == "quit" ] && echo "User requested exit ..." && exit 0 [ ! -z "${DEVICE}" ] && break done } select_device if [ ! -z $DEVICE ] then sed -i -r "s#(UDPBD_DEVICE=).*#\1/dev/${DEVICE}\"#" /etc/systemd/system/ps2_udpbd.service systemctl daemon-reload fi ================================================ FILE: ansible/templates/install_ps3netsrv/install_ps3netsrv.sh.j2 ================================================ #!/bin/bash SRCDIR="{{ retronas_root }}/src" BINDIR="{{ retronas_root }}/bin" #echo "Installing prerequisite packages..." #apt install -y curl wget make gcc g++ automake autoconf build-essential unzip libmbedtls-dev libmbedtls12 meson ninja-build echo "Configuring build directories..." rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Downloading ps3netsrv source code..." #SOURCECODE=$( curl -kLs 'https://github.com/aldostools/webMAN-MOD/releases/latest' | awk -F '"' '/href.*ps3netsrv.*zip/{print $2}' #SOURCECODE=$( curl -kLs 'https://github.com/aldostools/webMAN-MOD/tags' | awk -F '"' /href.*${PATTERN}/'{print $4}' | head -n1 ) SOURCECODE=$( curl -kLs https://api.github.com/repos/aldostools/webMAN-MOD/releases | jq -r ".[0].assets | map(select(.name | match (\"ps3netsrv\")))[-1] | .browser_download_url" ) [ -z "$SOURCECODE" ] && echo "Couldn't get source code name" && exit 1 echo $SOURCECODE #curl -OJL "https://github.com/${SOURCECODE}" curl -OJL "${SOURCECODE}" unzip ps3netsrv*.zip cd ps3netsrv*/src meson buildrelease --buildtype=release ninja -C buildrelease if [ $? -eq 0 ] then echo "Moving binary to RetroNAS bin dir..." mkdir -p "${BINDIR}" 2>/dev/null mv -vf buildrelease/ps3netsrv "${BINDIR}"/ echo "Cleaning up..." rm -rf "${SRCDIR}" echo "All done!" exit 0 fi echo "Build failed! exiting" exit 1 ================================================ FILE: ansible/templates/install_ps3netsrv/ps3netsrv-perms.service.j2 ================================================ [Unit] Description=ps3netsrv for PlayStation3 permissions fix [Service] Type=oneshot ExecStart=/usr/bin/chown -RLc {{ retronas_user }}:{{ retronas_group }} "{{ retronas_path }}/ps3/ps3netsrv" ExecStart=/usr/bin/chmod -Rc a-st,u+rwX,g+rwX,o+rX "{{ retronas_path }}/roms/videos/" ExecStart=/usr/bin/chmod -Rc a-st,u+rwX,g+rwX,o+rX "{{ retronas_path }}/roms/sony/" ================================================ FILE: ansible/templates/install_ps3netsrv/ps3netsrv-perms.timer.j2 ================================================ [Unit] Description=ps3netsrv for PlayStation3 permissions fix [Timer] OnUnitActiveSec=20s RandomizedDelaySec=15s Persistent=true [Install] WantedBy=timers.target ================================================ FILE: ansible/templates/install_ps3netsrv/ps3netsrv.service.j2 ================================================ [Unit] Description=ps3netsrv for PlayStation3 with CFW/HEN and webMAN-MOD After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] User={{ retronas_user }} ExecStart={{ retronas_root }}/bin/ps3netsrv {{ retronas_path }}/ps3/ps3netsrv Restart=on-failure RestartSec=1 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_pygopherd/install_pygopherd.sh.j2 ================================================ #!/bin/bash set -u APP=pygopherd REPO=https://github.com/michael-lazar/${APP}.git OUTPATH=/opt function _log { echo "$1" } ### REQUIREMENTS REQFAIL=0 [ $REQFAIL -ne 0 ] && _log "Requirements failed, see previous errors" && exit $REQFAIL cd $OUTPATH if [ ! -f ${OUTPATH}/${APP}/.git/config ] then git clone $REPO else cd ${OUTPATH}/${APP} git pull fi ================================================ FILE: ansible/templates/install_pygopherd/pygopherd.conf.j2 ================================================ ###################################################################### # LOCAL DEVELOPMENT QUICKSTART SETTINGS ###################################################################### [pygopherd] ################################################## # Operating System / Overall Behavior ################################################## # Set this to true if you want the server to "detach" itself; that is, # to go into the background after it starts. detach = no # If you want gopherd to write a PID file, set this to the location # where you want it. Otherwise, comment out this line. pidfile = /var/run/pygopherd.pid ################################################## # Network ################################################## # The server name to present to the world. If you do not specify it # here, Pygopherd will attempt to figure it out automatically. # This is used only to present to clients. It does not control # where the server listens. # servername = retronas # The interface on which to listen. It should be an IP address or # a domain name. If specified, pygopherd will attempt to listen to # the specified port on only this interface -- useful if you are doing # virtual hosting. If not specified, pygopherd will listen on all # interfaces the OS provides. If in doubt, do not specify this. # # interface = gopher.example.com # What port to listen on. If not running as root, this must be # greater than 1024. port = 70 # Type of server to run. Valid options are ForkingTCPServer # and ThreadingTCPServer. ForkingTCPServer is highly recommended # for now. servertype = ThreadingTCPServer # What port to *say* we're listening on. Most people should NOT # specify this. You might want to if you are using firewalling or # port forwarding and the port number is different to the world than # it is locally. # advertisedport = 70 # Do we timeout on client conections? HIGHLY RECOMMENDED! # Value is given in seconds. If given, any read or write that makes # no progress in this number of seconds will time out. timeout = 60 ################################################## # Data Handling ################################################## # You can add a header to every directory by creating a # .abstract file in that directory and filling it with the # information you like. This will then be rendered as a header # for the directory. This option controls this feature. Note: # for this to work, you must define a mapping to ABSTRACT in eaexts # below. abstract_headers = on # Individual files and folders can also have abstracts. You can # choose to have pygopherd render these abstracts in the directory # listing itself -- they'll appear beneath the menu name for the file. # You can set this option to any of three values: # # always -- always render these abstracts. # unsupported -- render them only for protocols that do not natively # support abstracts. Gopher+ is the only protocol that natively # supports them currently. # never -- never render these abstracts. abstract_entries = always ################################################## # Error handling ################################################## # If there is an error, you can decide whether or not to log a full # backtrace. A full backtrace will usually be needed to find the # problem. tracebacks = yes ################################################## # Security ################################################## ## Whether or not to use chroot. # This option is only valid if you are running pygopherd as root! usechroot = yes ## Username and groupname to setreuid/setregid to. Valid only if ## starting pygopherd as root. Comment out if you don't want this ## functionality. NOTE: DO NOT RUN AS ROOT UNLESS YOU USE THESE! BAD BAD BAD! setuid = {{ retronas_user }} setgid = {{ retronas_group }} ################################################## # TLS ################################################## # Enable TLS by sniffing the first byte of the client request for the start of # a TLS handshake. This allows both TLS and plaintext requests to be served # over the same port. enable_tls = no # File paths to the server certificate and keyfile in PEM format. These are # required if TLS is enabled. When using chroot, the certificates will be # loaded while root privileges are still active. tls_certfile = ./testdata/demo.crt tls_keyfile = ./testdata/demo.key ################################################## # Filesystem and MIME ################################################## # Where the documents are stored. root = {{ retronas_path }} # Location of a file to use to figure out MIME types. You can # specify multiple files here -- just separate them with a colon. # ALL of them that are found will be read. mimetypes = ./conf/mime.types:/etc/pygopherd/mime.types:/etc/mime.types # Encodings. You can use the default with the following syntax. The # mimetypex.encodings_map is {'.Z': 'compress', '.gz': 'gzip'}. # # For ease of use in the config file, we specify this as a list of # tuples. You can convert any hash to a list of tuples by using .items() # encoding = mimetypes.encodings_map.items() # You can override the default entirely (ie, to remove those) like this: # encoding = {'.bz2' : 'bzip2', '.gz' : 'gzip'}.items() # Or the same thing: # encoding = [('.bz2', 'bzip2'), ('.gz', 'gzip')] # Or, you can extend the default like so: encoding = list(mimetypes.encodings_map.items()) + \ list({'.bz2' : 'bzip2', '.tal': 'tal.TALFileHandler' }.items()) ###################################################################### # Logging ###################################################################### [logger] # Log method to use. One of: # syslog -- use Unix syslog facility # file -- log to standard output (future capability for logging to other # files) # none -- no logging logmethod = file # If you enable syslog, you will need to define these as well: # priority -- one of the following (listed in order of high to low): # LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, # LOG_INFO, LOG_DEBUG priority = LOG_INFO # Facility -- one of the following: # LOG_KERN, LOG_USER, LOG_MAIL, LOG_DAEMON, LOG_AUTH, LOG_LPR, LOG_NEWS, # LOG_UUCP, LOG_CRON, LOG_LOCAL0 - LOG_LOCAL7 facility = LOG_LOCAL3 ###################################################################### # GOPHER OBJECTS ###################################################################### # Settings for gopher objects [GopherEntry] # Use this MIME type if no other type is found. defaultmimetype = text/plain # Mapping from MIME types to gopher0 single-character types. # This is a list of lists. The first entry in each list is a # regexp to match and the second is the result. # # Please have a .* at the end to map all unknown types to a certain # character. For best results, that character should be nicely # corresponding to the defaultmimetype. mapping = [['text/html', 'h'], ['text/.+', '0'], ['application/mac-binhex40', '4'], ['audio/.+', 's'], ['image/gif', 'g'], ['image/.+', 'I'], ['application/gopher-menu', '1'], ['application/gopher\\+-menu', '1'], ['multipart/mixed', 'M'], ['application/.+', '9'], ['.*', '0'], ] # This is used by the system to generate Extended Attribute (EA), aka # Gopher+ blocks for a file. Basically, with the setup shown below, # you can create "filename.txt.abstract" to define the abstract # property for filename.txt. If you do that, you will probably want # to add these properties to ignorepatt below. The list is a mapping # from an extension to a block name. # # Sample for UMN compatibility: # eaexts = {'.abstract' : 'ABSTRACT', '.keywords' : 'KEYWORDS', '.ask' : 'ASK', '.3d' : '3D'} # # If you want to disable this capability, use this: # # eaexts = {} ###################################################################### # HANDLERS ###################################################################### ################################################## # Handler multiplexer ################################################## [handlers.HandlerMultiplexer] # A list of the handlers to consider. The handlers # are tried in the order listed. # # ### Suggested settings: # Note: the UMNDirHandler will handle all directories, even if they # do not have UMN-specific files, so you do not need to list the # dirhandler in this case. # # Warning: scriptexec and pyg can execute arbitrary code stored in # your path. Don't enable unless you know what you're doing! # # For UMN emulation: (full UMN featureset excluding scriptexec, no others) # # handlers = [url.HTMLURLHandler, UMN.UMNDirHandler, # html.HTMLFileTitleHandler, # mbox.MBoxMessageHandler, mbox.MBoxFolderHandler, # file.CompressedFileHandler, file.FileHandler] # # For Bucktooth emulation: (full Buck featureset excluding scriptexec) # #handlers = [gophermap.BuckGophermapHandler, url.HTMLURLHandler, # file.FileHandler, dir.DirHandler] # # For full Pygopherd featureset excluding scripts, compression, and PYG. # Supports both UMN and Bucktooth featuresets. This is the default # configuration for Pygopherd because it is secure yet versatile. # # handlers = [url.HTMLURLHandler, gophermap.BuckGophermapHandler, # mbox.MaildirFolderHandler, mbox.MaildirMessageHandler, # UMN.UMNDirHandler, html.HTMLFileTitleHandler, # mbox.MBoxMessageHandler, mbox.MBoxFolderHandler, # file.FileHandler] # For full Pygopherd featureset including scripts and PYG. Same as # above but adds scripts, decompression, and PYG execution. handlers = [url.HTMLURLHandler, gophermap.BuckGophermapHandler, mbox.MaildirFolderHandler, mbox.MaildirMessageHandler, UMN.UMNDirHandler, tal.TALFileHandler, html.HTMLFileTitleHandler, mbox.MBoxMessageHandler, mbox.MBoxFolderHandler, pyg.PYGHandler, scriptexec.ExecHandler, ZIP.ZIPHandler, file.CompressedFileHandler, file.FileHandler, url.URLTypeRewriter] ################################################## # Decompressing file handler ################################################## [handlers.file.CompressedFileHandler] # Decompressors is a map from an encoding (as specified in the # pygopherd section above) to a decompression program. # The decompression program must # accept the input in its stdin and write the decompressed output # to stdout. # # If you do not want to decompress things automatically for your # clients, you might wish to NOT use this handler. # # Note: this feature is probably NOT compatible with chroot unless # you take extra precautions. # We enable no decompressors by default... you'll need to do that. # decompressors = {} decompressors = {'bzip2': 'bzcat', 'gzip' : 'zcat', 'compress' : 'zcat'} # Regexp to match against filenames pending decompression. # The default will let ALL files be decompressed. decompresspatt = .* # You can be more restrictive: # decompresspatt = \.txt\.(bz2|gz|Z)$ ################################################## # Directory handler ################################################## [handlers.dir.DirHandler] # A regular expression of files to ignore. These files # will not be presented in lists of files to clients, # but if clients know the exact path to the files, they can # still be requested. # # This pattern is matched against the requested selector. # Selectors are guaranteed to begin with a slash by this point. # and never end with a slash unless they consist solely of a slash. # # By default, we ignore files starting with a period, gophermap # files, and files ending with a tilde. # # The default emulates UMN's default plus buck. Please note: # UMNDirHandler implicitly will keep all files starting with a dot out of # directory listings. If you exclude these files explicitly in ignorepatt, # then not only will they not show up, but the handler will also not scan # them for links and the like. # # A buck-only server might like: # # ignorepatt = ~$|/\.|/gophermap$ ignorepatt = /.cap$|/lost\+found$|/lib$|/bin$|/etc$|/dev$|~$|/\.cache|/\.forward$|/\.message$|/\.hushlogin$|/\.kermrc$|/\.notar$|/\.where$|/veronica.ctl$|/robots.txt$|/nohup.out$|/gophermap$|\.abstract$|\.keyboards$|\.ask|\.3d$|~$ # Expiration time, in seconds, for the cache. # Set to 0 to disable caching entirely. cachetime = 0 # Name of the cahe file. Must be set to something even if the cachetime # is zero. In that case, this filename will not be used but for the conf # file to parse, it must still be set. cachefile = .cache.pygopherd.dir ################################################## # UMN Directory Handler ################################################## [handlers.UMN.UMNDirHandler] # Extension stripping behavior. When a file from a directory # is presented in a menu, and no name is given, what to do? # For instance, given a file Welcome.txt and pygopherd.tar.gz: # # If extstrip is none, present Welcome.txt and pygopherd.tar.gz in the # menu. # # If extstrip is nonencoded, modify only those files that do not # have encodings. (If CompressedFileHandler is used, modify only # those files that to not have *HANDLED* encodings.) # If gzip is NOT a handled encoding, you'd get names Welcome and # pygopherd.tar.gz. If gzip IS a handled encoding, you'd get # Welcome and pygopherd. # # If extstrip is full, modify all modifyable names. Welcome.txt -> # Welcome and pygopherd.tar.gz -> pygopherd. # extstrip = none extstrip = nonencoded # extstrip = full [handlers.ZIP.ZIPHandler] ################################################## # ZIP file handler ################################################## # Even if it's listed in the available handlers, it's disabled here by # default. enabled = true pattern = \.zip$ ###################################################################### # PROTOCOLS ###################################################################### ################################################## # Protocol Multiplexer ################################################## [protocols.ProtocolMultiplexer] # A list of the protocols to consider for each request. # The protocols are tried in the order listed. protocols = [wap.WAPProtocol, gemini.GeminiProtocol, http.HTTPProtocol, http.HTTPSProtocol, spartan.SpartanProtocol, gopherp.GopherPlusProtocol, gopherp.SecureGopherPlusProtocol, rfc1436.GopherProtocol, rfc1436.SecureGopherProtocol] ################################################## # Gopher+ Protocol ################################################## [protocols.gopherp.GopherPlusProtocol] # The name and e-mail of the administrator admin = retronas ################################################## # HTTP Protocol ################################################## [protocols.http.HTTPProtocol] iconmapping = {'h' : 'text.gif', '0' : 'text.gif', '4' : 'binhex.gif', 's' : 'sound1.gif', 'g' : 'image3.gif', 'I' : 'image3.gif', 'M' : 'text.gif', '9' : 'binary.gif', '1' : 'folder.gif', '7' : 'folder.gif', 'i' : 'blank.gif'} # You can use this option to put something at the top of each HTML # page generated. # # The following tokens will be interpolated: # # GOPHERURL -- the Gopher URL for this page. # pagetopper = Welcome to RetroNAS! You are browsing Gopher through a Web interface right now. You can use most browsers or Gopher clients to browse Gopher natively. If your browser supports it, try clicking here to see this page in Gopher directly. To find Gopher browsers, click here.
################################################## # WAP Protocol ################################################## [protocols.wap.WAPProtocol] # waptop is the URL to access with WAP devices. The default, /wap, means # that accessing http://sitename.com/wap will bring up your site in WAP # mode. # # PyGopherd can autodetect WAP from some phones, so this is not always # necessary. waptop = /wap ################################################## # Gemini Protocol ################################################## [protocols.gemini.GeminiProtocol] # Note that the gemini protocol *requires* the TLS section to also be enabled. footer = => https://www.github.com/michael-lazar/pygopherd Generated by PyGopherd ################################################## # Spartan Protocol ################################################## [protocols.gemini.SpartanProtocol] footer = => https://www.github.com/michael-lazar/pygopherd Generated by PyGopherd ================================================ FILE: ansible/templates/install_pygopherd/pygopherd.service.j2 ================================================ [Unit] Description=Pygopherd After=multi-user.target [Service] Type=simple Restart=always WorkingDirectory=/opt/{{ my_name }} Environment=PYTHONPATH=/opt/{{ my_name }} ExecStart=/opt/pygopherd/bin/{{ my_name }} {{ retronas_root}}/etc/{{ my_name }}.conf TimeoutStartSec=0 RemainAfterExit=yes [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_rclone/rclone-webui.service.j2 ================================================ [Unit] Description=rclone webui Requires=network-online.target After=network-online.target [Service] Type=simple User={{ retronas_user }} ExecStart=/usr/bin/rclone rcd --rc-web-gui --rc-web-gui-no-open-browser --rc-addr 0.0.0.0:5572 --rc-htpasswd /etc/retronas.htpasswd TimeoutStopSec=10 Restart=on-failure [Install] WantedBy=default.target ================================================ FILE: ansible/templates/install_redumper/install_redumper.sh.j2 ================================================ #!/bin/bash ### # The x86_64 version is pulled from the official github # The aarch64 version is manually built and hosted seperately # set -e APP=redumper DESTDIR=/opt/${APP} [ ! -d "${DESTDIR}" ] && mkdir -p "${DESTDIR}" dl_install() { RELEASE=${1} [ -z "$RELEASE" ] && echo "Couldn't get release " && exit 1 RTMP=$(mktemp -d) cd $RTMP curl -sOJL "${RELEASE}" unzip $(basename ${RELEASE}) mv redumper*Linux*/bin/* $DESTDIR cd .. rm -rf $RTMP } get_x86_64() { ORG=superg REPO=redumper RELEASE=$(curl -skJL https://api.github.com/repos/${ORG}/${REPO}/releases | jq -r ".[0].assets | map(select(.name | match (\"Linux\")))[-1] | .browser_download_url" ) dl_install $RELEASE } get_aarch64() { URL=https://mameau.com/notes/retronas/redumper/aarch64/ PATTERN="redumper-build*linux-aarch64.zip" RELEASE=$(curl -skJL $URL | sed -rn "s/^.*($PATTERN)\">.*/\1/p" | sort -r | head -n1) dl_install $URL/$RELEASE } case $(uname -m) in x86_64) get_x86_64 ;; aarch64) get_aarch64 ;; esac ================================================ FILE: ansible/templates/install_retroaimserver/install_retroaimserver.sh.j2 ================================================ #!/bin/sh set -x PAT_ARM="linux.arm64_.*tar.gz" PAT_X86="linux.x86_64.tar.gz" DEST=/opt/retro-aim-server DESTFILE=retro-aim-server.tar.gz case $(uname -m) in aarch64) PAT=$PAT_ARM ;; x86_64) PAT=$PAT_X86 ;; *) echo "Unknown architecture $(uname -m)" esac RELEASE=$( curl -kLs https://api.github.com/repos/mk6i/retro-aim-server/releases | jq -r ".[0].assets | map(select(.name | match (\"${PAT}\")))[-1] | .browser_download_url" ) if [ ! -z $RELEASE ] then curl -JLo $TMPDIR/$DESTFILE "${RELEASE}" fi [ ! -d $DEST ] && mkdir -p $DEST if [ -f $TMPDIR/$DESTFILE ] then tar -xvf $TMPDIR/$DESTFILE -C $DEST --strip=1 fi chown -R {{ retronas_user }}:{{ retronas_group }} $DEST chmod +x $DEST/retro_aim_server ================================================ FILE: ansible/templates/install_retroaimserver/retro-aim-server.service.j2 ================================================ [Unit] Description=retro-aim-server After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] User={{ retronas_user }} WorkingDirectory=/opt/retro-aim-server ExecStart=/opt/retro-aim-server/retro_aim_server Restart=on-failure RestartSec=5 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_retroaimserver/retroaimserver.xml.j2 ================================================ ================================================ FILE: ansible/templates/install_retroaimserver/retroainserver.xml.j2 ================================================ ================================================ FILE: ansible/templates/install_romimport/romimport.sh.j2 ================================================ #!/bin/bash set -u TDIR="{{retronas_root}}/bin/Hardware-Target-Game-Database" MANIPULATE=0 FORCE=0 XTERMINATE=0 TARGET="" declare -A SYSTEMS SYSTEMS=( {% for item in system_map if item.smdb %} [{{ item.src }}]="{{ item.smdb }}" {% endfor %} ) ## REQUIREMENTS [ ! -d "${TDIR}" ] && echo "Cannot locate ROM import SMBD directory. Please add it from the Install Things menu." && exit 1 ## hacky af list_targets() { echo "Use id with -t to run a single system" echo "-------------------------------------" ### dump to screen for SYSTEM in ${!SYSTEMS[@]} do echo "id: ${SYSTEM}, ${SYSTEMS[$SYSTEM]}" done | column -s"," -t exit 0 } _usage() { echo "Usage $0" echo "-h this help" echo "-t target system" echo "-l list available targets" exit 0 } OPTSTRING="hlt:" while getopts $OPTSTRING ARG do case $ARG in h) _usage ;; l) # list targets list_targets ;; t) TARGET=${OPTARG} ;; esac done run_buildpack() { IFS=$'\n' local ODIR="${1}" local SMDB="${2}" local MSDB="$(basename $(echo $SMDB) .txt)" # UNARMED FOR TESTING cd "${TDIR}" python3 build_pack.py --input_folder "{{retronas_path}}/romimport" --output_folder "${ODIR}" --database "${SMDB}" --file_strategy smart --skip_existing --drop_initial_directory --missing "{{retronas_path}}/romimport/${MSDB}_missing.txt" } updateSMDB() { cd ${TDIR} echo "Refreshing SMBDs..." umask 0002 git config pull.rebase false git reset --hard HEAD git pull } auditsystem() { local SYSTEM="${1:-IAMNOTFOUND}" if [ ${SYSTEMS[${SYSTEM}]+_} ] then ODIR="{{retronas_path}}/roms/${SYSTEM}" SMDB="./EverDrive Pack SMDBs/${SYSTEMS[${SYSTEM}]}" if [ -d "${ODIR}" ] then echo '------------------------' echo "Analysing with ${SMDB}" echo "Outputting to ${ODIR}" run_buildpack "${ODIR}" "${SMDB}" echo -e '------------------------\n' else echo "Failed to file output directory ${ODIR}" fi else _usage fi } if [ -z "${TARGET}" ] then updateSMDB for SYSTEM in ${!SYSTEMS[@]} do auditsystem ${SYSTEM} done else updateSMDB auditsystem ${TARGET} fi ================================================ FILE: ansible/templates/install_romm_cifs/retronas-romm-dirs.service.j2 ================================================ [Unit] Description=retronas-romm-dirs [Service] Type=simple Restart=no ExecStart={{ retronas_root }}/scripts/retronas-romm-dirs.sh TimeoutStartSec=0 RemainAfterExit=no ================================================ FILE: ansible/templates/install_romm_cifs/retronas-romm-dirs.sh.j2 ================================================ #!/bin/sh cd /opt/retronas/ansible /usr/bin/git reset --hard HEAD /usr/bin/git pull /usr/bin/ansible-playbook {{ my_file }}.yml ================================================ FILE: ansible/templates/install_romm_cifs/retronas-romm-dirs.timer.j2 ================================================ [Unit] Description=Run retronas-romm-dirs [Timer] OnCalendar=daily Persistent=true [Install] WantedBy=timers.target ================================================ FILE: ansible/templates/install_sabretools/install_sabretools.sh.j2 ================================================ #!/bin/bash set -eu APP=SabreTools ORG=$APP REPO=$APP DESTDIR=/opt/${APP} case $(uname -m) in x86_64) ARCH=x64 ;; aarch64) ARCH=arm64 ;; *) echo "Unsupported arch" exit 1 esac dl_install() { RELEASE=${1} [ -z "$RELEASE" ] && echo "Couldn't get release " && exit 1 [ "$RELEASE" == "null" ] && echo "Couldn't get release " && exit 1 [ ! -d "${DESTDIR}" ] && mkdir -p "${DESTDIR}" RTMP=$(mktemp -d) cd $RTMP curl -sOJL "${RELEASE}" FILENAME=$(basename ${RELEASE}) if unzip -o $FILENAME -d $DESTDIR then [ -f /usr/local/bin/sabretools ] && rm -f /usr/local/bin/sabretools ln -s ${DESTDIR}/${APP} /usr/local/bin/sabretools rm -rf $RTMP fi } RELEASE=$(curl -skJL https://api.github.com/repos/${ORG}/${REPO}/releases | jq -r ".[0].assets | map(select(.name | match (\"linux-${ARCH}_release\")))[-1] | .browser_download_url" ) dl_install $RELEASE ================================================ FILE: ansible/templates/install_seaweedfs/install_seaweedfs.sh.j2 ================================================ #!/bin/bash BINDIR="{{ retronas_root }}/bin" echo "Downloading seaweedfs..." TARFILE=linux_$(dpkg --print-architecture).tar.gz RELEASE=$( curl -kLs https://api.github.com/repos/seaweedfs/seaweedfs/releases | jq -r ".[0].assets | map(select(.name | match (\"^${TARFILE}$\")))[-1] | .browser_download_url" ) [ -z "$RELEASE" ] && echo "Couldn't get release" && exit 1 echo $RELEASE cd /tmp curl -ksOJL "${RELEASE}" tar xvf ${TARFILE} echo "Moving binary to RetroNAS bin dir..." mkdir -p "${BINDIR}" 2>/dev/null mv -vf weed "${BINDIR}"/ echo "Cleaning up..." rm -f "/tmp/${RELEASE}" echo "All done!" ================================================ FILE: ansible/templates/install_seaweedfs/seaweedfs-credentials.sh.j2 ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh WEEDCONF=${1:-/opt/retronas/bin/weed-retronas-s3.json} MATCH=${2:-retronas} if [ -f ${WEEDCONF} ] then echo "Credentials for the identity: ${MATCH}" jq -r ".[][] | select(.name == \"${MATCH}\").credentials[]" ${WEEDCONF} else echo "Config file not found: ${WEEDCONF}" fi PAUSE ================================================ FILE: ansible/templates/install_seaweedfs/seaweedfs-retronas.service.j2 ================================================ [Unit] Description=seaweedfs s3/filer/volume storage After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] ExecStart={{ retronas_root }}/bin/weed server --dir={{ retronas_path }}/s3 -dataCenter=retronas -master -master.defaultReplication=000 -master.volumeSizeLimitMB=10000 -volume -volume.max=1 -s3 -s3.config={{ retronas_root }}/bin/weed-retronas-s3.json Restart=on-failure RestartSec=1 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_seaweedfs/seaweedfs.xml.j2 ================================================ # master # volume # filer # s3 ================================================ FILE: ansible/templates/install_seaweedfs/weed-retronas-s3.json.j2 ================================================ { "identities": [ { "name": "retronas", "credentials": [ { "accessKey": "{{ retronas_s3_access_key.stdout }}", "secretKey": "{{ retronas_s3_secret_key.stdout }}" } ], "actions": [ "Admin", "Read", "ReadAcp", "List", "Tagging", "Write", "WriteAcp" ] } ] } ================================================ FILE: ansible/templates/install_sit/install_sit.sh.j2 ================================================ #!/bin/bash set -u RN_BIN=/usr/local/bin/ SRCDIR={{ retronas_root }}/src REPO=sit OWNER=thecloudexpanse XC=( sit macbinfilt ) [ ! -d $SRCDIR ] && mkdir $SRCDIR cd $SRCDIR git clone https://github.com/${OWNER}/${REPO} cd ${REPO} make for X in ${XC[@]} do [ ! -f ${X} ] && echo "${X} not found" && exit 1 chmod +x ${X} mv ${X} ${RN_BIN}/ done # CLEAN UP rm -Rf ${SRCDIR}/ ================================================ FILE: ansible/templates/install_smbmounter/retronas_smbmounter.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. comment = Amiga SMBMounter path = {{ retronas_path }}/amiga guest ok = no browseable = yes write list = {{ retronas_user }} writeable = yes valid users = {{ retronas_user }} create mask = 0775 directory mask = 0775 follow symlinks = yes wide links = yes strict sync = no ================================================ FILE: ansible/templates/install_tcpser/install_tcpser.sh.j2 ================================================ #!/bin/bash set -u SRCDIR="{{ retronas_root }}/src" BINDIR="{{ retronas_root }}/bin" REPO=https://github.com/FozzTexx/tcpser.git if [ ! -x "${BINDIR}/tcpser" ] then echo "tcpser not found, so we'll build it!" echo "Configuring build directories..." [ -d ${SRCDIR} ] && rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Downloading git source ..." git clone $REPO cd "${SRCDIR}/$(basename $REPO .git)" echo "Patching Makefile to build for pthread" sed -i 's/^LDFLAGS\s=.*$/LDFLAGS = -pthread -lpthread/' Makefile echo "Building" make echo "Moving binary to RetroNAS bin dir..." mkdir -p "${BINDIR}" 2>/dev/null mv -vf tcpser "${BINDIR}/" echo "Cleaning up..." [ -d ${SRCDIR} ] && rm -rf "${SRCDIR}" echo "All done!" fi ================================================ FILE: ansible/templates/install_tcpser/tcpser@.service.j2 ================================================ [Unit] Description=tcpser %i After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] User={{ retronas_user }} EnvironmentFile={{ retronas_root }}/etc/tcpser/tcpser-%i ExecStart={{ retronas_root }}/bin/tcpser ${DEVICE} ${SPEED} ${LISTEN} ${ADDN} Restart=on-failure RestartSec=1 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_telnet/telnet.j2 ================================================ service telnet { flags = REUSE socket_type = stream wait = no user = root server = /usr/sbin/telnetd log_on_failure += USERID disable = no } ================================================ FILE: ansible/templates/install_tftpd-hpa/tftpd-hpa.j2 ================================================ # /etc/default/tftpd-hpa TFTP_USERNAME="{{ retronas_user }}" TFTP_DIRECTORY="{{ retronas_path }}" TFTP_ADDRESS=":69" TFTP_OPTIONS="--secure --create --permissive --umask 0000" ================================================ FILE: ansible/templates/install_tnfs/install_tnfs.sh.j2 ================================================ #!/bin/bash # Set world readable/executable umask umask 0022 # Set the install dir IDIR="{{ retronas_root }}/bin/tnfs" mkdir -p "${IDIR}" # make/clean the source build location mkdir -p "{{ retronas_root }}/src" cd "{{ retronas_root }}/src" rm -rf spectranet # Clone the source git clone https://github.com/FujiNetWIFI/spectranet.git cd spectranet/tnfs/tnfsd # Build and install rm -rvf bin/* make OS=LINUX cp -vf bin/tnfsd "${IDIR}/" ================================================ FILE: ansible/templates/install_tnfs/tnfsd.service.j2 ================================================ [Unit] Description=TNFS for Atari 8-bit and ZX Spectrum Documentation=https://github.com/FujiNetWIFI/spectranet Requires=network-online.target After=network-online.target [Service] Type=simple ExecStart={{ retronas_root }}/bin/tnfs/tnfsd {{ retronas_path }} -c {{ retronas_user }} TimeoutStopSec=10 Restart=on-failure [Install] WantedBy=default.target ================================================ FILE: ansible/templates/install_ucon64/install_ucon64.sh.j2 ================================================ #!/bin/bash set -u RN_BIN=/usr/local/bin/ VERSION=2.2.2 OUTPATH=/tmp/ucon64 OUTFILE=ucon64-${VERSION}-src.tar.gz URL=https://sourceforge.net/projects/ucon64/files/ucon64/ucon64-${VERSION} XC=ucon64 CONFIGURE_ARGS="" function _log { echo "$1" } ### REQUIREMENTS REQFAIL=0 [ ! -x /usr/bin/gmake ] && _log "GMAKE not found" && REQFAIL=1 [ $REQFAIL -ne 0 ] && _log "Requirements failed, see previous errors" && exit $REQFAIL ### MAKE directory _log "Checking for ${OUTPATH}" [ ! -d ${OUTPATH} ] && mkdir -p "${OUTPATH}" [ -f ${OUTPATH}/${OUTFILE} ] && rm -f ${OUTPATH}/${OUTFILE} ### DOWNLOAD ucon64 RESULT="FAILURE" _log "Attempting to download ucon64 ${VERSION} from ${URL}" curl -sqL -o${OUTPATH}/${OUTFILE} "${URL}/${OUTFILE}/" [ $? -eq 0 ] && RESULT="SUCCESS" _log "Download result: ${RESULT}" ### UNPACK if [ -f "${OUTPATH}/${OUTFILE}" ] then cd ${OUTPATH} tar xzvf ${OUTFILE} cd ucon64-${VERSION}-src/src/ fi ### CHECK parallel port support PARALLEL_H=/usr/include/x86_64-linux-gnu/sys/io.h # RPI is missing sys/io.h headers so parallel devices can't be supported (part of libc6-dev) [ ! -f ${PARALLEL_H} ] && CONFIGURE_ARGS+="--disable-parallel " # CONFIGURE ./configure ${CONFIGURE_ARGS} # MAKE gmake [ -x ${XC} ] && mv ${XC} "${RN_BIN}/" chmod 755 ${RN_BIN}/${XC} # CLEAN UP rm -Rf ${OUTPATH}/ ================================================ FILE: ansible/templates/install_waybackproxy/config.json.j2 ================================================ { "LISTEN_PORT": 8888, "DATE": "20011025", "DATE_TOLERANCE": 365, "GEOCITIES_FIX": true, "QUICK_IMAGES": true, "WAYBACK_API": true, "CONTENT_TYPE_ENCODING": true, "SILENT": false, "SETTINGS_PAGE": true } ================================================ FILE: ansible/templates/install_waybackproxy/install_waybackproxy.sh.j2 ================================================ #!/bin/bash # Set world readable/executable umask umask 0022 # Clone the source cd /opt git clone https://github.com/richardg867/WaybackProxy {{ my_name }} ================================================ FILE: ansible/templates/install_waybackproxy/waybackproxy.service.j2 ================================================ [Unit] Description=WaybackProxy Documentation=https://github.com/richardg867/WaybackProxy Requires=network-online.target After=network-online.target [Service] Type=simple WorkingDirectory=/opt/{{ my_name }}/ ExecStart=/usr/bin/python3 /opt/{{ my_name }}/{{ my_name }}.py TimeoutStopSec=10 Restart=on-failure [Install] WantedBy=default.target ================================================ FILE: ansible/templates/install_webone/install_webone.sh.j2 ================================================ #!/bin/bash DTVER=8 export PATH={{ retronas_root }}/bin/dotnetcore${DTVER}:{{ retronas_root }}/bin/dotnetcore${DTVER}/tools:${PATH} export DOTNET_ROOT={{ retronas_root }}/bin/dotnetcore${DTVER} export DOTNET_INSTALL_DIR={{ retronas_root }}/bin/dotnetcore${DTVER} SRCDIR="{{ retronas_root }}/src" BINDIR="{{ retronas_root }}/bin" rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" # Clone the WebOne repo git clone https://github.com/atauenis/webone.git cd webone # Fix a case-sensitive file issue sed -i 's/webone.csproj/WebOne.csproj/g' WebOne.sln # Install the dotnet-tarball tool dotnet tool install --global dotnet-tarball # Follow build guide from WebOne README.md dotnet restore dotnet publish -c Release dotnet build -c Release # Move the binaries into the bindir mkdir -p "${BINDIR}/webone" mv -vf ${SRCDIR}/webone/bin/Release/net${DTVER}.0/* "${BINDIR}/webone/" # Cleanup rm -rf "${SRCDIR}" ================================================ FILE: ansible/templates/install_webone/webone.service.j2 ================================================ [Unit] Description=WebOne HTTP Proxy Server Documentation=https://github.com/atauenis/webone/wiki/ Requires=network-online.target After=network-online.target [Service] Type=simple #DynamicUser=yes Environment="HOME=/tmp/" Environment="DOTNET_ROOT={{ retronas_root }}/bin/dotnetcore8" Environment="DOTNET_INSTALL_DIR={{ retronas_root }}/bin/dotnetcore8" Environment="PATH={{ retronas_root }}/bin/dotnetcore8:{{ retronas_root }}/bin/dotnetcore8/tools:$PATH" ExecStart={{ retronas_root }}/bin/webone/webone --daemon ReadWriteDirectories=-/var/log/ TimeoutStopSec=10 Restart=on-failure [Install] WantedBy=default.target ================================================ FILE: ansible/templates/install_wrp/install_wrp.sh.j2 ================================================ #!/bin/bash ARCH=$(dpkg --print-architecture | head -n1) # https://github.com/tenox7/wrp/releases/download/4.6.0/wrp-amd64-linux # https://github.com/tenox7/wrp/releases/download/4.6.0/wrp-arm64-linux RELEASE=$( curl -kLs https://api.github.com/repos/tenox7/wrp/releases | jq -r ".[0].assets | map(select(.name | match (\"wrp-${ARCH}-linux\")))[-1] | .browser_download_url" ) [ ! -d /opt/wrp ] && mkdir -p /opt/wrp cd /opt/wrp curl -kLsO "${RELEASE}" chmod +x $(basename ${RELEASE}) ================================================ FILE: ansible/templates/install_wrp/wrp.service.j2 ================================================ [Unit] Description={{ my_name|upper }} service After=network.target [Service] Type=simple Restart=always ExecStart=/opt/{{ my_name }}/{{ my_name }}-{{ architecture.stdout }}-linux -h -l :64888 SyslogIdentifier={{ my_name|upper }} [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_x11vnc/x11vnc_wrapper.sh.j2 ================================================ #!/bin/bash XDISPLAY=$1 XAUTH=$2 PORT=$3 RFBAUTH=/etc/vncpasswd_retronas # use a local auth file if it exists if [ -f /home/$USER/vncpasswd_retronas ] then RFBAUTH=/home/$USER/vncpasswd_retronas fi x11vnc -quiet -display $XDISPLAY -auth $XAUTH -listen 0.0.0.0 -rfbport $PORT -rfbauth $RFBAUTH -forever ================================================ FILE: ansible/templates/install_xbox/retronas_xbox.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. comment = xbox path = {{ retronas_path }}/xbox guest ok = no browseable = yes write list = {{ retronas_user }} writeable = yes valid users = {{ retronas_user }} create mask = 0775 directory mask = 0775 follow symlinks = yes wide links = yes ================================================ FILE: ansible/templates/install_xbox360/retronas_xbox360.conf.j2 ================================================ ## RetroNAS config. ## This is autogenerated. Changes will be lost. comment = xbox360 path = {{ retronas_path }}/xbox360/games guest ok = no browseable = yes valid users = {{ retronas_user }} create mask = 0775 directory mask = 0775 writeable = yes ================================================ FILE: ansible/templates/install_xbox360_netiso/dummy.iso.j2 ================================================ ================================================ FILE: ansible/templates/install_xbox360_netiso/install_xbox360_netiso.sh.j2 ================================================ #!/bin/bash set -ue ARCH=$(uname -m) GH_OWNER=tuxuser GH_REPO=netiso-srv DEST_PATH=/opt/xbox360_netiso RELEASE=$( curl -kLs https://api.github.com/repos/${GH_OWNER}/${GH_REPO}/releases | jq -r ".[0].assets | map(select(.name | match (\"netiso-srv-${ARCH}-unknown-linux-musl\")))[-1] | .browser_download_url" ) [ ! -d "${DEST_PATH}" ] && mkdir -p "${DEST_PATH}" cd "${DEST_PATH}" curl -kLsO "${RELEASE}" RELEASE_FILE=$( basename ${RELEASE} ) if [ ! -z $RELEASE ] then if [ -f "${RELEASE_FILE}" ] then unzip "$( basename ${RELEASE_FILE})" -d "_temp" TARGET=$(find -type f -name "netiso-srv") mv $TARGET ${DEST_PATH} chmod +x ${DEST_PATH}/$( basename ${TARGET}) else echo "Failed" exit 1 fi else echo "Download failed" exit 1 fi rm -f ${RELEASE_FILE} rm -rf ${DEST_PATH}/_temp ================================================ FILE: ansible/templates/install_xbox360_netiso/xbox360_netiso.service.j2 ================================================ [Unit] Description={{ my_name|upper }} service After=network.target [Service] User={{ retronas_user }} Type=simple Restart=always ExecStart=/opt/{{ module_name }}/netiso-srv -r -v {{ retronas_path }}/{{ system_key }} SyslogIdentifier={{ my_name|upper }} [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_xboxmanager/xboxmanager.cfg.j2 ================================================ { "xbox_username":"xbox", "xbox_password":"xbox", "xbox_ipaddress":"192.168.1.100", "xbox_type":"games", "xbox_games_drive":"E", "xbox_games_directory":"games", "local_games_directory":"{{ retronas_path }}/microsoft/xbox/iso", "local_mount_directory":"{{ retronas_path }}/device-mounts/xbox" } ================================================ FILE: ansible/templates/install_xlink-kai/xlink-kai.service.j2 ================================================ [Unit] Description=xlink-kai After=network.target StartLimitIntervalSec=60 StartLimitBurst=4 [Service] User={{ retronas_user }} ExecStart=/usr/bin/kaiengine KillSignal=3 RestartKillSignal=3 SuccessExitStatus=3 SIGQUIT QUIT Restart=always RestartSec=5 [Install] WantedBy=multi-user.target ================================================ FILE: ansible/templates/install_ytree/install_ytree.sh.j2 ================================================ #!/bin/bash set -u SRCDIR="{{ retronas_root }}/src" BINDIR="/usr/local/bin" REPO=https://github.com/lattenero/ytree echo "Configuring build directories..." [ -d ${SRCDIR} ] && rm -rf "${SRCDIR}" mkdir -p "${SRCDIR}" cd "${SRCDIR}" echo "Downloading git source ..." git clone $REPO cd "${SRCDIR}/$(basename $REPO .git)" echo "Building" make -j5 echo "Moving binary to RetroNAS bin dir..." mkdir -p "${BINDIR}" 2>/dev/null mv -vf ytree "${BINDIR}/" echo "Cleaning up..." [ -d ${SRCDIR} ] && rm -rf "${SRCDIR}" echo "All done!" ================================================ FILE: ansible/templates/install_zterm/install_zterm.sh.j2 ================================================ #!/bin/bash set -u OUTDIR=/opt/zterm ATMPDIR=/tmp/zterm REPO=https://github.com/sairuk/zterm # clean up old files [ -d "$ATMPDIR" ] && rm -rf "$ATMPDIR" # clone cd /tmp git clone $REPO # build cd "$ATMPDIR/build" cmake .. make # dir [ ! -d $OUTDIR ] && mkdir -p $OUTDIR # move if [ -f $ATMPDIR/build/zterm ] then mv $ATMPDIR/build/z* $OUTDIR #fix path sed -i -r 's#^DIR.+#DIR={{ retronas_path }}#' $OUTDIR/zconfig fi ================================================ FILE: ansible/templates/install_zterm/zterm.service.j2 ================================================ [Unit] Description=zterm zmodem file transfer server StartLimitIntervalSec=60 StartLimitBurst=4 ConditionPathExists=/dev/ttyUSB0 [Service] User={{ retronas_user }} WorkingDirectory=/opt/zterm/ ExecStart=/opt/zterm/zterm Restart=on-failure RestartSec=2 SuccessExitStatus=3 4 RestartForceExitStatus=3 4 [Install] WantedBy=multi-user.target ================================================ FILE: config/menu/3ds_qr.json ================================================ { "menu": { "title": "3DS QR Codes", "description": "Nintendo 3DS FBI homebrew", "id":"3DS QR Codes", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install Generator", "id":"3ds_qr_codes", "prompt": "", "type": "install", "group":"", "command": "3ds_qr_codes", "args": "" }, { "index":"03", "title": "Generate", "description": "Generate QR Codes", "id":"3ds_qr", "prompt": "", "type": "script", "group":"", "command": "3ds_qr", "args": "" }, { "index":"04", "title": "Regenerate", "description": "Regenerate all QR codes", "id":"3ds_qr_flush", "prompt": "", "type": "script", "group":"", "command": "3ds_qr", "args": "-f" }, { "index":"05", "title": "Interface", "description": "Select target interface to listen on", "id":"retronas_net_3dsqr_interface", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-3dsqr-interface", "args": "" }, { "index":"06", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "3DS-QR-codes.md", "args": "" } ] } } ================================================ FILE: config/menu/_template.json ================================================ { "menu": { "title": "", "description": "", "id":"", "prompt": "", "type": "", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" } ] } } ================================================ FILE: config/menu/adtpro.json ================================================ { "menu": { "title": "adtpro", "description": "ADTPro transfers data \\(physical disks and/or disk images\\) between Apple II-era computers and RetroNAS||We launch this service in headless localhost mode \\(serial over IP\\), you can use VNC to access the gui with the full feature set||Note: Requires a VNC client connected to retronas:60000", "id":"adtpro-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install adtpro application", "id":"adtpro", "prompt": "Install", "type": "install", "group":"", "command": "adtpro", "args": "" }, { "index": "03", "title": "Edit", "description": "Change the localhost (SIP) config", "id":"", "prompt": "", "type": "form", "group":"", "command": "adtpro_localhost_edit", "args": "" }, { "index":"04", "title": "Start", "description": "Start adtpro localhost mode", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "adtpro@localhost", "args": "" }, { "index":"05", "title": "Stop", "description": "Stop adtpro localhost mode", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "adtpro@localhost", "args": "" }, { "index":"06", "title": "Status", "description": "Query adtpro localhost mode", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "adtpro@localhost", "args": "" }, { "index":"07", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "ADTPro.md", "args": "" } ] }, "adtpro-serial": { "title": "adtpro", "description": "Please select an option", "id":"adtpro-serial-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index": "02", "title": "Edit", "description": "Serial device settings", "id":"adtpro-edit-serial", "prompt": "", "type": "form", "group":"", "command": "adtpro_serial_edit", "args": "" }, { "index":"03", "title": "Start", "description": "Start adtpro serial mode", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "adtpro@serial", "args": "" }, { "index":"04", "title": "Stop", "description": "Stop adtpro serial mode", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "adtpro@serial", "args": "" }, { "index":"05", "title": "Status", "description": "Query adtpro serial mode", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "adtpro@serial", "args": "" } ] }, "adtpro-ethernet": { "title": "adtpro", "description": "Please select an option", "id":"adtpro-ethernet-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index": "02", "title": "Edit", "description": "Change the Ethenet net listen port", "id":"", "prompt": "", "type": "form", "group":"", "command": "adtpro_ethernet_edit", "args": "" }, { "index":"03", "title": "Start", "description": "Start adtpro ethernet mode", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "adtpro@ethernet", "args": "" }, { "index":"04", "title": "Stop", "description": "Stop adtpro ethernet mode", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "adtpro@ethernet", "args": "" }, { "index":"05", "title": "Status", "description": "Query adtpro ethernet mode", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "adtpro@ethernet", "args": "" } ] }, "adtpro-audio": { "title": "adtpro", "description": "Please select an option", "id":"adtpro-audio-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Start", "description": "Start adtpro audio mode", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "adtpro@audio", "args": "" }, { "index":"03", "title": "Stop", "description": "Stop adtpro audio mode", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "adtpro@audio", "args": "" }, { "index":"04", "title": "Status", "description": "Query adtpro audio mode", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "adtpro@audio", "args": "" } ] }, "adtpro-localhost": { "title": "adtpro", "description": "Please select an option, note in this mode ADTPro is a client", "id":"adtpro-localhost-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index": "02", "title": "Edit", "description": "Change the localhost (SIP) config", "id":"", "prompt": "", "type": "form", "group":"", "command": "adtpro_localhost_edit", "args": "" }, { "index":"03", "title": "Start", "description": "Start adtpro localhost mode", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "adtpro@localhost", "args": "" }, { "index":"04", "title": "Stop", "description": "Stop adtpro localhost mode", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "adtpro@localhost", "args": "" }, { "index":"05", "title": "Status", "description": "Query adtpro localhost mode", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "adtpro@localhost", "args": "" } ] }, "adtpro-serial-edit": { "title": "ADTPro Serial Config", "description": "set ADTPro device", "id":"adtpro-serial-edit-menu", "prompt": "", "type": "menu", "items": [] }, "adtpro-ethernet-edit": { "title": "ADTPro Ethernet Config", "description": "set ADTPro device", "id":"adtpro-ethernet-edit-menu", "prompt": "", "type": "menu", "items": [] } } ================================================ FILE: config/menu/assembly64.json ================================================ { "menu": { "title": "assembly64", "description": "assembly64 project, A tool that helps you bulk download artifacts to your c64.||Note: Requires a VNC client connected to retronas:60001", "id":"assembly64-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install assembly64 application", "id":"assembly64", "prompt": "Install", "type": "install", "group":"", "command": "assembly64", "args": "" }, { "index":"03", "title": "Start", "description": "Start assembly64", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "assembly64", "args": "" }, { "index":"04", "title": "Stop", "description": "Stop assembly64", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "assembly64", "args": "" }, { "index":"05", "title": "Status", "description": "Query assembly64", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "assembly64", "args": "" }, { "index":"06", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "assembly64.md", "args": "" } ] } } ================================================ FILE: config/menu/atarist-sidecart.json ================================================ { "menu": { "title": "Atari ST Sidecart", "description": "Manage Sidecart support", "id":"sidecart", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install sidecart support", "id":"sidecart-install", "prompt": "", "type": "install", "group":"sidecart", "command": "atarist-sidecart", "args": "" }, { "index":"03", "title": "Update DB", "description": "Update the local floppy DB", "id":"sidecart-db", "prompt": "", "type": "script", "group":"sidecart", "command": "atarist-sidecart-updatedb", "args": "" }, { "index":"04", "title": "Update ROMS", "description": "Update ROM listing", "id":"sidecart-roms", "prompt": "", "type": "script", "group":"sidecart", "command": "atarist-sidecart-generate-roms", "args": "" }, { "index":"05", "title": "Mirror", "description": "Build a local mirror", "id":"sidecart-mirror", "prompt": "", "type": "script", "group":"sidecart", "command": "atarist-sidecart-mirrordb", "args": "" }, { "index":"06", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Sidecart.md", "args": "" } ] } } ================================================ FILE: config/menu/cockpit.json ================================================ { "menu": { "title": "cockpit", "description": "Install cockpit", "id":"cockpit", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install cockpit", "id":"cockpit", "prompt": "", "type": "install", "group":"", "command": "cockpit", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "cockpit", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "cockpit", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "cockpit", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Cockpit.md", "args": "" } ] } } ================================================ FILE: config/menu/config.json ================================================ { "menu": { "title": "Configuration", "description": "Please select a configuration||NOTE: changes to these settings may require reinstallation of tools||Current RetroNAS settings| User/Group: \"${OLDRNUSER}\":\"${OLDRNGROUP}\"| Directory: \"${OLDRNPATH}\"| Branch: \"${OLDRNBRANCH}\"| \"${IPADDMSG}\"", "id":"config", "prompt": "Change", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Username", "description": "Configure RetroNAS user", "id":"update-user", "prompt": "", "type": "dialog_input", "group":"", "command": "update-user", "args": "" }, { "index":"03", "title": "Group", "description": "Configure RetroNAS group", "id":"update-group", "prompt": "", "type": "dialog_input", "group":"", "command": "update-group", "args": "" }, { "index":"04", "title": "Password", "description": "Configure RetroNAS password", "id":"update-password", "prompt": "", "type": "modal", "group":"", "command": "retronas_password" }, { "index":"05", "title": "Data Directory", "description": "Configure RetroNAS top level directory", "id":"set-top-level-dir", "prompt": "", "type": "dialog_input", "group":"", "command": "set-top-level-dir", "args": "" }, { "index":"06", "title": "Permissions", "description": "Fix ALL on-disk permissions", "id":"permissions", "prompt": "Run", "type": "modal", "group":"", "command": "retronas_fixperms", "args": "" }, { "index":"08", "title": "Profiles", "description": "Install a preconfigured profile", "id":"profiles", "prompt": "", "type": "modal", "group":"", "command": "profiles", "args": "" } ] }, "update-user": { "title": "Update User", "description": "Please enter the username for all RetroNAS services to run as||This will normally default to \"pi\" on Raspberry Pi OS Install||It is recommended you leave it as default unless you know what you are doing.", "id":"update-user-menu", "prompt": "Update", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Username", "description": "", "id":"update-user", "prompt": "", "type": "input:input", "group":"retronas", "command": "update-username", "args": "" } ] }, "update-user-confirm": { "title": "Confirm User", "description": "Do you want to save this setting?|New RetroNAS user: \"${NEWVALUE}\"", "id":"update-user-confirm-menu", "prompt": "Confirm", "type": "dialog-yn", "items": [] }, "update-group": { "title": "Update Group", "description": "Please enter the group for all RetroNAS services to run as||This will normally default to \"pi\" on Raspberry Pi OS Install||It is recommended you leave it as default unless you know what you are doing.", "id":"update-group-menu", "prompt": "Update", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Group", "description": "", "id":"update-group", "prompt": "", "type": "input:input", "group":"retronas", "command": "update-group", "args": "" } ] }, "update-group-confirm": { "title": "Confirm Group", "description": "Do you want to save this setting?|New RetroNAS group: \"${NEWVALUE}\"", "id":"update-group-confirm-menu", "prompt": "Confirm", "type": "dialog-yn", "items": [] }, "update-password": { "title": "Update Password", "description": "If you are having problems with CIFS/SMB/Appletalk shares, you can reset their password here, this will also update your user password||Passwords entered here will be echoed to the backend processes||Use the up/down arrows to navigate form fields", "id":"update-password-menu", "prompt": "Update", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Update Password", "description": "Update the user Systems/Samba password", "id":"update-password", "prompt": "", "type": "input:password", "group":"retronas", "command": "TOOL COMMAND", "args": "" } ] }, "set-top-level-dir": { "title": "Set Top Level Directory", "description": "Please type in the RetroNAS top level directory", "id":"set-top-level-dir-menu", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Directory Name", "description": "Set top Level Dir", "id":"set-top-level-dir", "prompt": "", "type": "input:input", "group":"retronas", "command": "TOOL COMMAND", "args": "" } ] }, "set-top-level-dir-confirm": { "title": "Confirm EtherDFS NIC", "description": "Do you want to save this setting?|New RetroNAS top level directory: \"${NEWVALUE}\"", "id":"set-top-level-dir-confirm", "prompt": "Confirm", "type": "dialog-yn", "items": [] }, "set-etherdfs-nic": { "title": "Set EtherDFS NIC", "description": "Please enter the interface name for EtherDFS to bind to.||Normally this is something like eth0 for wired Ethernet.||If EtherDFS is installed, you will need to re-run the installer to apply the change.", "id":"set-etherdfs-nic-menu", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Set Device", "description": "Set EtherDFS device", "id":"set-etherdfs-nic", "prompt": "", "type": "input:input", "group":"etherdfs", "command": "TOOL COMMAND", "args": "" } ] }, "set-etherdfs-nic-confirm": { "title": "Confirm EtherDFS NIC", "description": "Do you want to save this setting?|New EtherDFS interface: \"${NEWVALUE}\"", "id":"set-etherdfs-nic-confirm", "prompt": "Confirm", "type": "dialog-yn", "items": [] } } ================================================ FILE: config/menu/deluge.json ================================================ { "menu": { "title": "deluge", "description": "bitorrent server/client", "id":"deluge-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install deluge application", "id":"deluge", "prompt": "Install", "type": "install", "group":"", "command": "deluge", "args": "" }, { "index":"03", "title": "Start", "description": "Start daemon", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "deluge", "args": "" }, { "index":"04", "title": "Stop", "description": "Stop daemon", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "deluge", "args": "" }, { "index":"05", "title": "Status", "description": "Query daemon", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "deluge*", "args": "" }, { "index":"06", "title": "Upgrade", "description": "Upgrade to packages from debian testing", "id":"deluge", "prompt": "Upgrade", "type": "script", "group":"", "command": "upgrade_deluge", "args": "" }, { "index":"07", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "BitTorrent.md", "args": "" } ] } } ================================================ FILE: config/menu/dexdrive.json ================================================ { "menu": { "title": "dexdrive", "description": "linux-dexdrive project read PSX/N64 memory cards and linux block devices", "id":"dexdrive-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install linux-dexdrive application", "id":"linux-dexdrive", "prompt": "Install", "type": "install", "group":"", "command": "linux-dexdrive", "args": "" }, { "index": "03", "title": "Edit", "description": "Change the serial device", "id":"", "prompt": "", "type": "form", "group":"", "command": "dexdrive_serial_edit", "args": "" }, { "index":"04", "title": "Start", "description": "Start Dex Drive daemon", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "linux-dexdrive", "args": "" }, { "index":"05", "title": "Stop", "description": "Stop Dex Drive daemon", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "linux-dexdrive", "args": "" }, { "index":"06", "title": "Status", "description": "Query Dex Drive daemon", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "linux-dexdrive", "args": "" }, { "index":"07", "title": "Dump", "description": "Dump a PS1 memory card", "id":"dexdrive_dumper", "prompt": "Dump", "type": "script", "group":"", "command": "dexdrive_dumper", "args": "" }, { "index":"08", "title": "Image", "description": "Write an image to a memory card", "id":"dexdrive_memcards", "prompt": "Dump", "type": "dialog", "group":"", "command": "dexdrive_memcards", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "linux-dexdrive.md", "args": "" } ] }, "dexdrive-serial-edit": { "title": "Dex Drive Serial Config", "description": "set Dex Drive device", "id":"dexdrive-serial-edit-menu", "prompt": "", "type": "menu", "items": [] }, "dexdrive-memcards": { "title": "Dex Drive Image Chooser", "description": "Please choose an image to write to the memory card", "id":"dexdrive-memcards", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" } ] } } ================================================ FILE: config/menu/doc.json ================================================ { "menu": { "title": "Documentation", "description": "Project documentation||Documentation will open in the Lynx browser \\(press Q to quit browser\\), documentation is an optional installation", "id":"documentation", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index": "02", "title": "README", "description": "Readme file", "id": "readme", "prompt": "", "type": "documentation", "group": "", "command": "README", "args": "" }, { "index": "03", "title": "SECURIY", "description": "SECURITY warning", "id": "security", "prompt": "", "type": "documentation", "group": "", "command": "SECURITY-WARNING.md", "args": "" }, { "index": "04", "title": "Generic Roms Folder", "description": "Information on RetroNAS generic file structure", "id": "generic-roms-folder", "prompt": "", "type": "documentation", "group": "", "command": "Generic-ROMs-folder.md", "args": "" }, { "index": "05", "title": "Supported Clients", "description": "Information on RetroNAS supported clients", "id": "supported-clients", "prompt": "", "type": "documentation", "group": "", "command": "Supported-clients.md", "args": "" }, { "index": "06", "title": "Supported Configurations", "description": "Information on RetroNAS supported configurations", "id": "supported-configurations", "prompt": "", "type": "documentation", "group": "", "command": "Supported-Configurations.md", "args": "" }, { "index": "07", "title": "Testing", "description": "Information on RetroNAS supported configurations", "id": "testing-retronas", "prompt": "", "type": "documentation", "group": "", "command": "Testing-RetroNAS.md", "args": "" }, { "index": "08", "title": "Structure", "description": "RetroNAS structure", "id": "structure-retronas", "prompt": "", "type": "documentation", "group": "", "command": "Structure.md", "args": "" }, { "index": "09", "title": "Bugs", "description": "Troubleshooting/Reporting bugs", "id": "bug", "prompt": "", "type": "documentation", "group": "", "command": "Bugs.md", "args": "" }, { "index": "98", "title": "Ideas", "description": "A list of features/projects that would be suited for inclusion in RetroNAS", "id": "ideas", "prompt": "", "type": "documentation", "group": "", "command": "Ideas.md", "args": "" }, { "index": "99", "title": "Notices", "description": "Major project change notices", "id": "notices", "prompt": "", "type": "documentation", "group": "", "command": "Notices.md", "args": "" } ] } } ================================================ FILE: config/menu/dreampi.json ================================================ { "menu": { "title": "dreampi", "description": "Install dreampi", "id":"dreampi", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install dreampi (Kazade version)", "id":"dreampi", "prompt": "", "type": "install", "group":"", "command": "dreampi", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "dreampi", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "dreampi", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "dreampi", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "DreamPi.md", "args": "" } ] } } ================================================ FILE: config/menu/etherdfs.json ================================================ { "menu": { "title": "etherdfs", "description": "Install etherdfs", "id":"etherdfs", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install etherdfs", "id":"etherdfs", "prompt": "", "type": "install", "group":"", "command": "etherdfs", "args": "" }, { "index":"03", "title": "EtherDFS", "description": "Set EtherDFS/ethflopd network interface", "id":"set-etherdfs-nic", "prompt": "", "type": "dialog_input", "group":"", "command": "set-etherdfs-nic", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "etherdfs", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "etherdfs", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "etherdfs", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "EtherDFS.md", "args": "" } ] } } ================================================ FILE: config/menu/ethflopd.json ================================================ { "menu": { "title": "ethflopd", "description": "Install ethflopd", "id":"ethflopd", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install ethflopd", "id":"ethflopd", "prompt": "", "type": "install", "group":"", "command": "ethflopd", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "ethflopd", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "ethflopd", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "ethflopd", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "ethflop.md", "args": "" } ] } } ================================================ FILE: config/menu/experimental.json ================================================ { "menu": { "title": "EXPERIMENTAL", "description": "WARNING these tools are EXPERIMENTAL, may break your system or destroy your data!||Do not use these unless you are comfortable with losing everything", "id":"experimental", "prompt": "Install", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index": "02", "title": "webui", "description": "Experimental retronas webui (cockpit)", "id":"cockpit-retronas", "prompt": "", "type": "install", "group":"", "command": "cockpit-retronas", "args": "" }, { "index": "03", "title": "network", "description": "Network presets (highly experimental!)", "id":"network", "prompt": "", "type": "dialog", "group":"", "command": "network" }, { "index": "04", "title": "xbox", "description": "Microsoft XBOX SMB config, for use w/Project Stellar", "id": "xbox", "prompt": "", "type": "install", "group": "samba", "command": "xbox", "args": "" }, { "index": "05", "title": "flippydrive", "description": "Flippydrive Network service", "id": "flippydrive", "prompt": "", "type": "dialog", "group": "", "command": "flippydrive", "args": "" }, { "index": "06", "title": "x360 netiso", "description": "Xbox360 NetISO service", "id": "xbox360_netiso", "prompt": "", "type": "dialog", "group": "", "command": "xbox360_netiso", "args": "" }, { "index": "07", "title": "netmount", "description": "DOS NetMount service", "id": "netmount", "prompt": "", "type": "dialog", "group": "", "command": "netmount", "args": "" }, { "index": "08", "title": "mister-organize", "description": "MiSTer Organize", "id": "mister-organize", "prompt": "", "type": "dialog", "group": "", "command": "mister-organize", "args": "" }, { "index": "09", "title": "sit", "description": "Create StuffIt archives on Unix systems", "id": "sit", "prompt": "", "type": "install", "group": "", "command": "sit", "args": "" }, { "index": "10", "title": "hfsutils", "description": "Install patched version of hfsutils", "id":"hfsutils", "prompt": "", "type": "install", "group":"", "command": "hfsutils", "args": "" } ] } } ================================================ FILE: config/menu/fenrirodewebserver.json ================================================ { "menu": { "title": "Fenrir-ODE Web Server", "description": "", "id":"fenrir-ode-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install the Fenrir-ODE Webserver application", "id":"fenrir-ode-webserver", "prompt": "Install", "type":"install", "group":"", "command": "fenrir-ode-webserver", "args": "" }, { "index":"03", "title": "Gamelist", "description": "Manually refresh the gamelist", "id":"", "prompt": "Refresh", "type": "service_restart", "group":"", "command": "fenrir-ode-webserver", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "fenrir-ode-webserver", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "fenrir-ode-webserver", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "fenrir-ode-webserver", "args": "" }, { "index":"05", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Fenrir-ODE-Webserver.md", "args": "" } ] } } ================================================ FILE: config/menu/flippydrive.json ================================================ { "menu": { "title": "flippydrive", "description": "Install flippydrive", "id":"flippydrive", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install flippydrive", "id":"flippydrive", "prompt": "", "type": "install", "group":"", "command": "flippydrive", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "flippydrive", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "flippydrive", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "flippydrive", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Flippydrive.md", "args": "" } ] } } ================================================ FILE: config/menu/fsp.json ================================================ { "menu": { "title": "fsp", "description": "Install fsp", "id":"fsp", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install fsp", "id":"fsp", "prompt": "", "type": "install", "group":"", "command": "fsp", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "fspd", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "fspd", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "fspd", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "FSP.md", "args": "" } ] } } ================================================ FILE: config/menu/gogrepo.json ================================================ { "menu": { "title": "GOG", "description": "Current OS: \"${OLDGOGOS}\"||Current LANG: \"${OLDGOGLANG}\"||WARNING: There is currently known issues with this tool,|see https://github.com/eddie3/gogrepo/issues/63||Please choose a task", "id":"gogrepo", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index": "02", "title": "Install", "description": "Download your GOG game installers", "id": "gogrepo", "prompt": "", "type": "install", "group": "", "command": "gogrepo", "args": "" }, { "index":"03", "title": "Authentication", "description": "Configure GOG authentication", "id":"gogrepo-auth", "prompt": "", "type": "dialog", "group":"gogrepo", "command": "gogrepo", "args": "auth-chooser" }, { "index":"04", "title": "Select OS", "description": "Change OS preferences", "id":"gog-os-input", "prompt": "", "type": "script", "group":"gogrepo", "command": "gogrepo_wrapper", "args": "select-os" }, { "index":"05", "title": "Select Lang", "description": "Change Language preferences", "id":"gog-lang-input", "prompt": "", "type": "script", "group":"gogrepo", "command": "gogrepo_wrapper", "args": "select-lang" }, { "index":"06", "title": "Sync", "description": "Syncronise my games list", "id":"gog-sync-gameslist", "prompt": "", "type": "script", "group":"gogrepo", "command": "gogrepo-wrapper", "args": "update-skip-known" }, { "index":"07", "title": "Single", "description": "Download/update a single game", "id":"gog-dl-one-game", "prompt": "", "type": "script", "group":"gogrepo", "command": "gogrepo-wrapper", "args": "update-download-single" }, { "index":"08", "title": "All", "description": "Download/update all games", "id":"gog-dl-all-game", "prompt": "", "type": "script", "group":"gogrepo", "command": "gogrepo-wrapper", "args": "download-all" }, { "index":"09", "title": "FULL", "description": "Synchronise games list & download/update all games", "id":"gog-dl-full-game", "prompt": "", "type": "script", "group":"gogrepo", "command": "gogrepo-wrapper", "args": "update-download" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "gogrepo.md", "args": "" } ] }, "gogrepo-setupos": { "title": "GOG configure OS", "description": "Current Operating Systems: ${OLDGOGOS}||Please set the Operating System\\(s\\) you would like to download GOG games for.", "id":"gogrepo-setupos", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Windows", "description": "Only Windows Games", "id":"gogos-windows", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index":"03", "title": "Mac", "description": "Only Mac Games", "id":"gogos-mac", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index":"04", "title": "Linux", "description": "Only Linux Games", "id":"gogos-linux", "prompt": "", "type": "", "group":"gogrepo", "command": "TOOL COMMAND", "args": "" }, { "index":"05", "title": "Windows & Mac", "description": "Only Windows & Mac Games", "id":"gogos-windows-mac", "prompt": "", "type": "", "group":"gogrepo", "command": "TOOL COMMAND", "args": "" }, { "index":"06", "title": "Windows & Linux", "description": "Only Windows & Linux Games", "id":"gogos-windows-linux", "prompt": "", "type": "", "group":"gogrepo", "command": "TOOL COMMAND", "args": "" }, { "index":"07", "title": "Mac & Linux", "description": "Only Mac & Linux Games", "id":"gogos-mac-linux", "prompt": "", "type": "", "group":"gogrepo", "command": "TOOL COMMAND", "args": "" }, { "index":"08", "title": "All", "description": "All Games", "id":"gogos-all", "prompt": "", "type": "", "group":"gogrepo", "command": "TOOL COMMAND", "args": "" } ] }, "gogrepo-setuplang": { "title": "GOG configure Language", "description": "Current Language: ${OLDGOGLANG}||Please set the Language you would like to download GOG games for.", "id":"gogrepo-setuplang", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"en", "title": "English", "description": "", "id":"gogos-en", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "ar", "title": "Arabic", "description": "", "id":"gogos-en", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "bl", "title": "Bulgarian", "description": "", "id":"gogos-bl", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "br", "title": "Brazilian Portuguese", "description": "", "id":"gogos-br", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "cn", "title": "Chinese", "description": "", "id":"gogos-cn", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "cz", "title": "Czech", "description": "", "id":"gogos-cz", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "da", "title": "Danish", "description": "", "id":"gogos-da", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "de", "title": "German", "description": "", "id":"gogos-de", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "es", "title": "Spanish", "description": "", "id":"gogos-es", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "fi", "title": "Finnish", "description": "", "id":"gogos-fi", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "fr", "title": "French", "description": "", "id":"gogos-fr", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "gk", "title": "Greek", "description": "", "id":"gogos-gk", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "hu", "title": "Hungarian", "description": "", "id":"gogos-hu", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "it", "title": "Italian", "description": "", "id":"gogos-it", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "jp", "title": "Japanese", "description": "", "id":"gogos-jp", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "ko", "title": "Korean", "description": "", "id":"gogos-ko", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "nl", "title": "Dutch", "description": "", "id":"gogos-nl", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "no", "title": "Norse", "description": "", "id":"gogos-no", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "pl", "title": "Polish", "description": "", "id":"gogos-pl", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "pt", "title": "Portuguese", "description": "", "id":"gogos-pt", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "ro", "title": "Romanian", "description": "", "id":"gogos-ro", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "ru", "title": "Russian", "description": "", "id":"gogos-ru", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "sb", "title": "Serbian", "description": "", "id":"gogos-sb", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "sk", "title": "Slovak", "description": "", "id":"gogos-sk", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "sv", "title": "Swedish", "description": "", "id":"gogos-sv", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" }, { "index": "tr", "title": "Turkish", "description": "", "id":"gogos-tr", "prompt": "", "type": "", "group":"gogrepo", "command": "", "args": "" } ] }, "gogrepo-gamechooser": { "title": "GOG game chooser", "description": "Please choose a game||If your game has not appeared, please synchronise your games list", "id":"gogrepo-gamechooser", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" } ] }, "gogrepo-auth": { "title": "GOG Authentication options", "description": "Please choose a option for authtenticaiton||Login can break if GOG change something, cookie import is more reliable", "id":"gogrepo-auth-chooser", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Login", "description": "Configure GOG credentials", "id":"gog-password", "prompt": "", "type": "script", "group":"gogrepo", "command": "gogrepo-wrapper", "args": "login" }, { "index":"03", "title": "Import", "description": "Import a cookies file, more reliable than login", "id":"gog-cookies", "prompt": "", "type": "script", "group":"gogrepo", "command": "gogrepo-wrapper", "args": "import-cookies" } ] } } ================================================ FILE: config/menu/hbstorecdn.json ================================================ { "menu": { "title": "PS4 Homebrew Store CDN", "description": "", "id":"hb-store-cdn-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install the PS4 Homebrew Store CDN", "id":"hb-store-cdn", "prompt": "Install", "type":"install", "group":"", "command": "hb-store-cdn", "args": "" }, { "index":"03", "title": "Package List", "description": "Manually refresh the package list", "id":"", "prompt": "Refresh", "type": "service_restart", "group":"", "command": "hb-store-cdn", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "hb-store-cdn", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "hb-store-cdn", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "hb-store-cdn", "args": "" }, { "index":"04", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "hb-store-cdn.md", "args": "" } ] } } ================================================ FILE: config/menu/hdparm.json ================================================ { "menu": { "title": "hdparm", "description": "WARNING: These changes are irreversable, USE AT YOUR OWN RISK||Try in ORDER:|APM -\\> Standby -\\> Custom service \\!\\!LAST RESORT\\!\\! \\<-||The custom service reads a random sector from the drive at random intervals every 3-5m, this should be enough to keep the drive up and reduce any impact on the drive.", "id":"hdparm-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install the hdparm application", "id":"hdparm", "prompt": "Install", "type":"install", "group":"", "command": "hdparm", "args": "" }, { "index":"10", "title": "APM", "description": "Disable Advanced Power Management (APM)", "id":"hdparm-disable-apm", "prompt": "Disable", "type": "script", "group":"", "command": "hdparm-manager-disable-apm", "args": "" }, { "index":"11", "title": "Standby", "description": "Disable drive Standy", "id":"hdparm-disable-standby", "prompt": "Disable", "type": "script", "group":"", "command": "hdparm-manager-disable-standby", "args": "" }, { "index":"20", "title": "Start", "description": "Start hdparm service", "id":"", "prompt": "", "type": "script", "group":"", "command": "hdparm-manager-start-service", "args": "" }, { "index":"21", "title": "Status", "description": "Query hdparm service status", "id":"", "prompt": "", "type":"script", "group":"", "command": "hdparm-manager-query-service", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the hdparm service", "id":"", "prompt": "", "type": "script", "group":"", "command": "hdparm-manager-stop-service", "args": "" }, { "index":"03", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "NEEDED.md", "args": "" } ] } } ================================================ FILE: config/menu/install.json ================================================ { "menu": { "title": "Install", "description": "Please select a module installer", "id": "install", "prompt": "Install", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id": "", "prompt": "", "type": "menu", "group": "", "command": "EXIT_OK", "args": "" }, { "index": "02", "title": "3ds qr codes", "description": "Nintendo 3DS FBI Homebrew installer", "id": "3ds_qr", "prompt": "", "type": "dialog", "group": "", "command": "3ds_qr", "args": "" }, { "index": "03", "title": "adtpro", "description": "Apple Disk Transfer ProDOS", "id": "adtpro", "prompt": "", "type": "dialog", "group": "", "command": "adtpro", "args": "" }, { "index": "04", "title": "affstools", "description": "Amiga Fast Filesystem tools", "id": "affstools", "prompt": "", "type": "install", "group": "", "command": "affstools", "args": "" }, { "index": "05", "title": "amiga samba", "description": "Samba share for SMBMounter", "id": "smbmounter", "prompt": "", "type": "install", "group": "", "command": "smbmounter", "args": "" }, { "index": "06", "title": "amitools", "description": "Various tools for using AmigaOS programs on other platforms", "id": "amitools", "prompt": "", "type": "install", "group": "", "command": "amitools", "args": "" }, { "index": "07", "title": "analoguepocket-cifs", "description": "Samba for Analogue Pocket", "id": "analoguepocket-cifs", "prompt": "Install", "type": "install", "group": "", "command": "analoguepocket_cifs", "args": "" }, { "index": "08", "title": "apfs-fuse", "description": "Apple File System fuse library", "id": "apfs-fuse", "prompt": "", "type": "install", "group": "", "command": "apfs-fuse", "args": "" }, { "index": "09", "title": "aria2", "description": "lightweight multi-protocol/source cli download utility", "id": "aria2", "prompt": "", "type": "install", "group": "", "command": "aria2", "args": "" }, { "index": "10", "title": "assembly64", "description": "assembly64 project (requires account)", "id": "assembly64", "prompt": "", "type": "dialog", "group": "", "command": "assembly64" }, { "index": "11", "title": "batocera", "description": "Batocera CIFS config", "id": "batocera-cifs", "prompt": "", "type": "install", "group": "", "command": "batocera_cifs", "args": "" }, { "index": "12", "title": "cockpit", "description": "Web based Linux system manager", "id": "cockpit", "prompt": "", "type": "dialog", "group": "", "command": "cockpit", "args": "" }, { "index": "13", "title": "cue2pops", "description": "Convert PS1 images for use with POPS", "id": "cue2pops", "prompt": "", "type": "install", "group": "", "command": "cue2pops" }, { "index": "14", "title": "curlftpfs", "description": "Mount ftp server as a filesystem", "id": "curlftpfs", "prompt": "", "type": "install", "group": "", "command": "curlftpfs", "args": "" }, { "index": "15", "title": "deluge", "description": "Deluge Web BitTorrent Client", "id": "deluge", "prompt": "", "type": "dialog", "group": "", "command": "deluge", "args": "" }, { "index": "16", "title": "dexdrive", "description": "Dex Drive block devices", "id": "dexdrive", "prompt": "", "type": "dialog", "group": "", "command": "dexdrive", "args": "" }, { "index": "17", "title": "discimagecreator", "description": "Disc Image Creator", "id": "disc-image-creator", "prompt": "", "type": "install", "group": "", "command": "disc-image-creator", "args": "" }, { "index": "18", "title": "documentation", "description": "Install RetroNAS documentation", "id": "documentation", "prompt": "", "type": "install", "group": "", "command": "doc", "args": "" }, { "index": "19", "title": "dreampi", "description": "dialup solution for dreamcast", "id": "dreampi", "prompt": "", "type": "dialog", "group": "", "command": "dreampi", "args": "" }, { "index": "20", "title": "emudeck-cifs", "description": "Samba for EmuDeck", "id": "emudeck-cifs", "prompt": "Install", "type": "install", "group": "", "command": "emudeck_cifs", "args": "" }, { "index": "21", "title": "emuelec", "description": "EmuElec CIFS config", "id": "emuelec-cifs", "prompt": "", "type": "install", "group": "", "command": "emuelec_cifs", "args": "" }, { "index": "22", "title": "etherdfs", "description": "EtherDFS a lightweight layer 2 network file sharing for DOS", "id": "etherdfs", "prompt": "", "type": "dialog", "group": "", "command": "etherdfs", "args": "" }, { "index": "23", "title": "ethflopd", "description": "lightweight layer 2 network floppy emulator for DOS", "id": "ethflopd", "prompt": "", "type": "dialog", "group": "", "command": "ethflopd", "args": "" }, { "index": "24", "title": "extract-xiso", "description": "XISO Tool", "id": "extract-xiso", "prompt": "", "type": "install", "group": "", "command": "extract-xiso" }, { "index": "25", "title": "far2l", "description": "far2l File Manager", "id": "far2l", "prompt": "", "type": "install", "group": "", "command": "far2l", "args": "" }, { "index": "27", "title": "fsp", "description": "Nintendo GameCube + Swiss FSP server", "id": "fsp", "prompt": "", "type": "dialog", "group": "", "command": "fsp", "args": "" }, { "index": "28", "title": "gogrepo", "description": "Download your GOG game installers", "id": "gogrepo", "prompt": "", "type": "modal", "group": "", "command": "gogrepo", "args": "" }, { "index": "29", "title": "hb-store-cdn", "description": "Ps4 Homebrew Store CDN", "id": "hbstorecdn", "prompt": "", "type": "dialog", "group": "", "command": "hbstorecdn", "args": "" }, { "index": "30", "title": "hdl-dump", "description": "Sony PS2 HDD Game management", "id": "hdldump", "prompt": "", "type": "install", "group": "", "command": "hdldump" }, { "index": "31", "title": "hdparm", "description": "Manage hdd standby mode", "id": "hdparm", "prompt": "", "type": "dialog", "group": "", "command": "hdparm", "args": "" }, { "index": "32", "title": "kermit", "description": "kermit (server mode)", "id": "kermit", "prompt": "", "type": "install", "group": "", "command": "kermit", "args": "" }, { "index": "33", "title": "laptop-ao", "description": "Disable hibernate/monitoring of laptop lid", "id": "laptop-ao", "prompt": "Install", "type": "install", "group": "", "command": "disable-laptop-lid", "args": "" }, { "index": "34", "title": "lighttpd", "description": "HTTP/Web server", "id": "lighttpd", "prompt": "", "type": "dialog", "group": "", "command": "lighttpd", "args": "" }, { "index": "35", "title": "linux-gadgets", "description": "Manage Linux OTG Gadgets", "id": "linux_gadgets", "prompt": "", "type": "dialog", "group": "", "command": "linux-gadgets", "args": "" }, { "index": "36", "title": "local-module", "description": "Run local ansible playbooks", "id": "run-local-module", "prompt": "Run", "type": "script-static", "group": "", "command": "run-local-module", "args": "" }, { "index": "37", "title": "lynx", "description": "Lynx terminal based web browser", "id": "lynx", "prompt": "", "type": "dialog", "group": "", "command": "lynx", "args": "" }, { "index": "38", "title": "macproxy classic", "description": "Proxy for retro computers", "id": "macproxy_classic", "prompt": "", "type": "dialog", "group": "", "command": "macproxy_classic", "args": "" }, { "index": "39", "title": "mc", "description": "Midnight Commander (Norton clone)", "id": "mc", "prompt": "", "type": "install", "group": "", "command": "mc", "args": "" }, { "index": "40", "title": "megatools", "description": "command line client application for Mega", "id": "megatools", "prompt": "", "type": "install", "group": "", "command": "megatools", "args": "" }, { "index": "41", "title": "minicom", "description": "minicom terminal", "id": "minicom", "prompt": "", "type": "dialog", "group": "", "command": "minicom", "args": "" }, { "index": "42", "title": "mister", "description": "MiSTer FPGA CIFS config", "id": "mister_cifs", "prompt": "", "type": "dialog", "group": "samba", "command": "mister_cifs", "args": "" }, { "index": "43", "title": "mystic", "description": "Mystic BBS", "id": "mysticbbs", "prompt": "", "type": "dialog", "group": "mysticbbs", "command": "mysticbbs", "args": "" }, { "index": "44", "title": "nabu", "description": "NABU Internet Adapter", "id": "nabu", "prompt": "", "type": "dialog", "group": "", "command": "nabu", "args": "" }, { "index": "45", "title": "nbd client", "description": "Network Block Device Client", "id": "nbd-client", "prompt": "", "type": "install", "group": "", "command": "nbd-client" }, { "index": "46", "title": "netatalk4", "description": "Apple AFP file sharing / AppleTalk, etc", "id": "netatalk4", "prompt": "", "type": "dialog", "group": "netatalk", "command": "netatalk", "args": "" }, { "index": "47", "title": "netdrive", "description": "mTCP Netdrive", "id": "mtcp-netdrive", "prompt": "", "type": "dialog", "group": "mtcp-netdrive", "command": "mtcp-netdrive", "args": "" }, { "index": "48", "title": "netlink", "description": "Sega Saturn Netlink tunneling service", "id": "netlink", "prompt": "", "type": "dialog", "group": "", "command": "netlink", "args": "" }, { "index": "49", "title": "nfs", "description": "NFS versions 2, 3 and 4", "id": "nfs", "prompt": "", "type": "install", "group": "", "command": "nfs", "args": "" }, { "index": "50", "title": "nginx", "description": "Install nginx with directory listing enabled", "id": "nginx", "prompt": "", "type": "dialog", "group": "", "command": "nginx", "args": "" }, { "index": "51", "title": "ntp", "description": "Network Time Protocol Server", "id": "ntp", "prompt": "", "type": "dialog", "group": "", "command": "ntp", "args": "" }, { "index": "52", "title": "open-iscsi", "description": "iSCSI support", "id": "open_iscsi", "prompt": "", "type": "dialog", "group": "", "command": "open-iscsi", "args": "" }, { "index": "53", "title": "openssh", "description": "SSH/SFTP/SCP Secure Shell command line and file transfer", "id": "openssh", "prompt": "", "type": "dialog", "group": "", "command": "openssh", "args": "" }, { "index": "54", "title": "pfsshell/pfsfuse", "description": "PS2 HDD filesystem tools", "id": "pfsshell", "prompt": "", "type": "install", "group": "", "command": "pfsshell" }, { "index": "55", "title": "pi1541", "description": "Setup a pi1541 SD card", "id": "pi1541", "prompt": "", "type": "dialog", "group": "", "command": "pi1541" }, { "index": "56", "title": "piscsi", "description": "PISCSI project", "id": "piscsi", "prompt": "", "type": "dialog", "group": "", "command": "piscsi" }, { "index": "57", "title": "playStation 3", "description": "ps3netsrv for CFW/HEN + webMAN-MOD", "id": "", "prompt": "ps3netsrv", "type": "dialog", "group": "", "command": "ps3netsrv", "args": "" }, { "index": "58", "title": "proftpd", "description": "FTP, File Transfer Protocol file sharing", "id": "proftpd", "prompt": "", "type": "dialog", "group": "", "command": "proftpd", "args": "" }, { "index": "59", "title": "ps2", "description": "OpenPS2Loader SMB config", "id": "ps2_openps2loader", "prompt": "", "type": "install", "group": "samba", "command": "ps2_openps2loader", "args": "" }, { "index": "60", "title": "pygopherd", "description": "Gopher protocol server", "id": "pygopherd", "prompt": "", "type": "install", "group": "", "command": "pygopherd", "args": "" }, { "index": "61", "title": "ras", "description": "Retro AIM/ICQ Server", "id": "retroaimserver", "prompt": "", "type": "dialog", "group": "retroaimserver", "command": "retroaimserver", "args": "" }, { "index": "62", "title": "rclone", "description": "rclone + webui", "id": "rclone", "prompt": "", "type": "dialog", "group": "", "command": "rclone", "args": "" }, { "index": "63", "title": "recalbox", "description": "Recalbox CIFS config", "id": "recalbox-cifs", "prompt": "", "type": "install", "group": "", "command": "recalbox_cifs", "args": "" }, { "index": "64", "title": "redumper", "description": "Redumper project", "id": "redumper", "prompt": "", "type": "install", "group": "", "command": "redumper", "args": "" }, { "index": "65", "title": "retroarch-cifs", "description": "RetroArch Based Systems CIFS config", "id": "retroarch-cifs", "prompt": "", "type": "install", "group": "", "command": "retroarch_cifs", "args": "" }, { "index": "66", "title": "retrodeck-cifs", "description": "Samba for RetroDeck", "id": "retrodeck-cifs", "prompt": "Install", "type": "install", "group": "", "command": "retrodeck_cifs", "args": "" }, { "index": "67", "title": "rom import", "description": "Import roms via Smokemonster SMDBs", "id": "romimport", "prompt": "Open", "type": "dialog", "group": "", "command": "romimport", "args": "" }, { "index": "68", "title": "sabretools", "description": "Dat Manager (x86_64 only)", "id": "sabretools", "prompt": "", "type": "install", "group": "", "command": "sabretools", "args": "" }, { "index": "69", "title": "samba", "description": "LANMan, NTLMv1/v2, NetBIOS, SMB1/2/3, CIFS file sharing", "id": "samba", "prompt": "", "type": "dialog", "group": "samba", "command": "samba", "args": "" }, { "index": "70", "title": "seaweedfs", "description": "SeaweedFS for local S3 storage", "id": "seaweedfs", "prompt": "", "type": "dialog", "group": "", "command": "seaweedfs", "args": "" }, { "index": "71", "title": "sidecart", "description": "Atari ST sidecart support", "id": "sidecart", "prompt": "", "type": "dialog", "group": "", "command": "atarist-sidecart", "args": "" }, { "index": "72", "title": "sslcert", "description": "Manage a self-signed ssl certificate", "id": "sslcert", "prompt": "", "type": "dialog", "group": "", "command": "sslcert", "args": "" }, { "index": "73", "title": "syncthing", "description": "File sync tool", "id": "syncthing", "prompt": "", "type": "dialog", "group": "", "command": "syncthing", "args": "" }, { "index": "74", "title": "tcpser", "description": "Hayes modem emulator", "id": "tcpser", "prompt": "", "type": "dialog", "group": "", "command": "tcpser", "args": "" }, { "index": "75", "title": "telnet", "description": "unencrypted remote access shell", "id": "telnet", "prompt": "", "type": "dialog", "group": "", "command": "telnet", "args": "" }, { "index": "76", "title": "tftpd-hpa", "description": "TFTP, Trivial File Transfer Protocol file sharing", "id": "tftpd-hpa", "prompt": "", "type": "dialog", "group": "", "command": "tftpd-hpa", "args": "" }, { "index": "77", "title": "tnfs", "description": "Atari 8-bit and ZX Spectrum", "id": "tnfs", "prompt": "", "type": "dialog", "group": "", "command": "tnfs", "args": "" }, { "index": "78", "title": "troubleshooting", "description": "Troubleshooting tools, iperf3, tcpdump, ethtool, smarttools, etc", "id": "troubleshooting", "prompt": "", "type": "install", "group": "", "command": "troubleshooting", "args": "" }, { "index": "79", "title": "ucon64", "description": "Multipurpose Swiss Army Knife Backup/Copier tool", "id": "ucon64", "prompt": "", "type": "install", "group": "", "command": "ucon64" }, { "index": "80", "title": "udpbd", "description": "PS2 block device service", "id": "ps2_udpbd", "prompt": "", "type": "dialog", "group": "", "command": "ps2_udpbd", "args": "" }, { "index": "81", "title": "waybackproxy", "description": "Retrocomputer web proxy for Wayback and OOcities", "id": "waybackproxy", "prompt": "", "type": "install", "group": "", "command": "waybackproxy", "args": "" }, { "index": "82", "title": "webone", "description": "HTTP 1.x proxy for a HTTP 2.x world", "id": "webone", "prompt": "", "type": "dialog", "group": "", "command": "webone", "args": "" }, { "index": "83", "title": "wrp", "description": "Proxy for retro computers, uses image maps", "id": "wrp", "prompt": "", "type": "dialog", "group": "", "command": "wrp", "args": "" }, { "index": "84", "title": "x360", "description": "Microsoft XBox360 SMB config", "id": "xbox360", "prompt": "", "type": "install", "group": "samba", "command": "xbox360", "args": "" }, { "index": "85", "title": "xboxmanager", "description": "Experimental xbox manager (cockpit)", "id": "xboxmanager", "prompt": "", "type": "install", "group": "", "command": "xboxmanager", "args": "" }, { "index": "86", "title": "xlink-kai", "description": "XLink Kai Gaming Network", "id": "xlinkkai", "prompt": "", "type": "dialog", "group": "", "command": "xlinkkai", "args": "" }, { "index": "87", "title": "ytree", "description": "Ytree File Manager (Xtree clone)", "id": "ytree", "prompt": "", "type": "install", "group": "", "command": "ytree", "args": "" }, { "index": "88", "title": "zterm", "description": "Zmodem transfer suite", "id": "zterm", "prompt": "", "type": "dialog", "group": "", "command": "zterm", "args": "" }, { "index": "89", "title": "romm", "description": "RomM CIFS config", "id": "romm_cifs", "prompt": "", "type": "dialog", "group": "samba", "command": "romm_cifs", "args": "" } ] } } ================================================ FILE: config/menu/lighttpd.json ================================================ { "menu": { "title": "lighttpd", "description": "Install lighttpd", "id":"lighttpd", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install lighttpd", "id":"lighttpd", "prompt": "", "type": "install", "group":"", "command": "lighttpd", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "lighttpd", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "lighttpd", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "lighttpd", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "NEEEDED.md", "args": "" } ] } } ================================================ FILE: config/menu/linux-gadgets.json ================================================ { "menu": { "title": "Linux Gadgets", "description": "Manage Linux OTG Gadgets", "id":"linux-gadgets", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install Gadget support", "id":"linux-gadgets", "prompt": "", "type": "install", "group":"", "command": "linux-gadgets", "args": "" }, { "index":"03", "title": "Mass Storage", "description": "Manage g_mass_storage gadgets", "id":"gadget-mass-storage-manage", "prompt": "Manage", "type": "script", "group":"", "command": "gadget-mass-storage-manage", "args": "" }, { "index":"04", "title": "Start", "description": "Start gadget", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "retronas-gadget.path", "args": "" }, { "index":"05", "title": "Stop", "description": "Stop gadget", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "retronas-gadget.path", "args": "" }, { "index":"06", "title": "Status", "description": "Query gadget", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "retronas-gadget*", "args": "" } ] } } ================================================ FILE: config/menu/litch.json ================================================ { "menu": { "title": "litch", "description": "itch.io leech script||WARNING: This tool is in an alpha state,\nsee https://github.com/sairuk/gogrepo||Please choose a task", "id":"litch", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Login", "description": "Configure your itch.io credentials", "id":"litch-login", "prompt": "", "type": "script", "group":"litch", "command": "litch_login", "args": "" }, { "index":"03", "title": "Claim", "description": "Claim bundle purchases", "id":"litch-claim", "prompt": "", "type": "script", "group":"litch", "command": "litch_claim", "args": "" }, { "index":"04", "title": "Download", "description": "Download your purchases", "id":"litch-download", "prompt": "", "type": "script", "group":"litch", "command": "litch_download", "args": "" }, { "index":"05", "title": "Down/Clean", "description": "Download(+clean) purchases", "id":"litch-download-clean", "prompt": "", "type": "script", "group":"litch", "command": "litch_download_clean", "args": "" } ] } } ================================================ FILE: config/menu/lynx.json ================================================ { "menu": { "title": "lynx", "description": "Lynx terminal based web browser", "id":"lynx", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index": "02", "title": "Install", "description": "Lynx terminal based web browser", "id": "lynx", "prompt": "", "type": "install", "group": "", "command": "lynx", "args": "" }, { "index":"03", "title": "Run", "description": "Run the Lynx browser", "id":"lynx_run", "prompt": "", "type": "command", "group":"", "command": "lynx", "args": "" } ] } } ================================================ FILE: config/menu/macproxy_classic.json ================================================ { "menu": { "title": "macproxy classic", "description": "Install macproxy classic", "id":"macproxy_classic", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install macproxy classic", "id":"macproxy_classic", "prompt": "", "type": "install", "group":"", "command": "macproxy_classic", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "macproxy", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "macproxy", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "macproxy", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "macproxy.md", "args": "" } ] } } ================================================ FILE: config/menu/main.json ================================================ { "menu": { "title": "Main", "description": "Welcome to RetroNAS|-------------------|Providing network storage, utilities and tools for different retro computers and consoles||Configure RetroNAS before installing any tools.\\(see Config menu\\)", "id":"main", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Exit", "description": "So long and thanks for all the bits", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Config", "description": "Change Global Settings", "id":"config", "prompt": "", "type": "dialog", "group":"", "command": "config", "args": "" }, { "index": "03", "title": "Install", "description": "The fun place, for things", "id":"install", "prompt": "", "type": "dialog", "group":"", "command": "install", "args": "" }, { "index": "50", "title": "Experimental", "description": "there be dragons here!", "id":"experimental", "prompt": "", "type": "dialog", "group":"", "command": "experimental", "args": "" }, { "index": "98", "title": "Update", "description": "Update core RetroNAS features", "id":"update", "prompt": "", "type": "dialog", "group":"", "command": "update", "args": "" }, { "index": "99", "title": "Documentation", "description": "View project documentation", "id":"documentation", "prompt": "", "type": "dialog", "group":"", "command": "doc", "args": "" } ] } } ================================================ FILE: config/menu/minicom.json ================================================ { "menu": { "title": "minicom", "description": "Please select an option", "id":"minicom", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install minicom application", "id":"minicom", "prompt": "Install", "type": "install", "group":"", "command": "minicom", "args": "" }, { "index": "03", "title": "Start", "description": "Run minicom", "id":"", "prompt": "", "type": "script", "group":"", "command": "minicom", "args": "" }, { "index":"04", "title": "Config", "description": "Start minicom in config mode", "id":"", "prompt": "", "type": "script", "group":"", "command": "minicom-config", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "minicom.md", "args": "" } ] } } ================================================ FILE: config/menu/mister-organize.json ================================================ { "menu": { "title": "MiSTer Organize Tool", "description": "MiSTer Organize is a project providing a curated list of software compatible with the MiSTer project||Place your software in to the romimport folder and run the tool; if identified the software will be moved into the RomRoot folder, you may then move the software onto your main MiSTer share/sd etc", "id":"mister-organize-menu", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index":"02", "title": "Install", "description": "Install", "id":"mister-organize-install", "prompt": "Install", "type": "install", "group":"", "command": "mister-organize" }, { "index":"03", "title": "Run", "description": "Run MiSTer Organize", "id":"mister-organize", "prompt": "", "type": "script", "group":"", "command": "mister-organize", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "MiSTer-Organize.md", "args": "" } ] } } ================================================ FILE: config/menu/mister_cifs.json ================================================ { "menu": { "title": "MiSTer", "description": "Install the MiSTer Samba service, enable/disable the auto disk updater or run the updater manually", "id":"mister-cifs", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install Samba for MiSTer support", "id":"mister-cifs", "prompt": "", "type": "install", "group":"", "command": "mister_cifs", "args": "" }, { "index":"03", "title": "Enable", "description": "Enable auto dir updates", "id":"", "prompt": "", "type": "service_enable_start", "group":"", "command": "retronas-mister-dirs.timer", "args": "" }, { "index":"04", "title": "Disable", "description": "Disable auto dir updater", "id":"", "prompt": "", "type": "service_disable_stop", "group":"", "command": "retronas-mister-dirs.timer", "args": "" }, { "index":"05", "title": "Status", "description": "Query auto dir updater", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "retronas-mister-dirs*", "args": "" }, { "index":"06", "title": "Run", "description": "Run directory updater now", "id":"", "prompt": "", "type": "service_start_follow", "group":"", "command": "retronas-mister-dirs.service", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "MiSTer-FPGA.md", "args": "" } ] } } ================================================ FILE: config/menu/mtcp-netdrive.json ================================================ { "menu": { "title": "mTCP Netdrive", "description": "Install mTCP Netdrive||To configure disks, access the terminal and run the create/image options as per project documentation", "id":"mtcp-netdrive", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install mTCP Netdrive", "id":"mtcp-netdrive", "prompt": "", "type": "install", "group":"", "command": "mtcp-netdrive", "args": "" }, { "index":"03", "title": "Console", "description": "Connect mTCP Netdrive console (Ctrl+A,D to detach)", "id":"mtcp-netdrive", "prompt": "", "type": "script", "group":"", "command": "mtcp-netdrive", "args": "console" }, { "index":"20", "title": "Start", "description": "Start mis service", "id":"", "prompt": "", "type": "service_enable_start", "group":"", "command": "mtcp-netdrive", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "mtcp-netdrive", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_disable_stop", "group":"", "command": "mtcp-netdrive", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "mtcp-netdrive.md", "args": "" } ] } } ================================================ FILE: config/menu/mysticbbs.json ================================================ { "menu": { "title": "Mystic BBS", "description": "Install Mystic BBS||NOTE: BBS software configuration is a manual experience, after installation create user in local mode, configure your system. Once configuration is complete start the server", "id":"mysticbbs", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install Mystic BBS", "id":"mysticbbs", "prompt": "", "type": "install", "group":"", "command": "mysticbbs", "args": "" }, { "index":"03", "title": "Local", "description": "Run Mystic BBS local mode", "id":"mysticbbs-local", "prompt": "", "type": "script", "group":"", "command": "mysticbbs", "args": "local" }, { "index":"04", "title": "Config", "description": "Mystic BBS configuration", "id":"mysticbbs-config", "prompt": "", "type": "script", "group":"", "command": "mysticbbs", "args": "config" }, { "index":"05", "title": "File Areas", "description": "Update RetroNAS file areas in Mystic", "id":"mysticbbs-filearea", "prompt": "", "type": "script", "group":"", "command": "mysticbbs", "args": "filearea" }, { "index":"06", "title": "Upload", "description": "Trigger mass uploads in Mystic", "id":"mysticbbs-upload", "prompt": "", "type": "script", "group":"", "command": "mysticbbs", "args": "upload" }, { "index":"20", "title": "Start", "description": "Start mis service", "id":"", "prompt": "", "type": "service_enable_start", "group":"", "command": "mysticbbs-mis", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "mysticbbs-mis", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_disable_stop", "group":"", "command": "mysticbbs-mis", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "mysticbbs.md", "args": "" } ] } } ================================================ FILE: config/menu/nabu.json ================================================ { "menu": { "title": "NABU Internet Adapter", "description": "Manage the NABU Internet Adapter", "id":"naubia", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install the NABU Internet Adapter software", "id":"nabu-software", "prompt": "", "type": "install", "group":"", "command": "nabu", "args": "" }, { "index":"03", "title": "Open", "description": "Open the NABU Internet Adapter", "id":"", "prompt": "", "type": "script", "group":"", "command": "nabu", "args": "" }, { "index":"05", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "NABU.md", "args": "" } ] } } ================================================ FILE: config/menu/netatalk-legacy.json ================================================ { "menu": { "title": "netatalk-legacy", "description": "Install legacy netatalk, NOTE: No longer supported, use Netatalk 4", "id":"netatalk_legacy_install", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install v2", "description": "Install netatalk2", "id":"netatalk2", "prompt": "", "type": "install", "group":"", "command": "netatalk2", "args": "" }, { "index":"03", "title": "Install v3", "description": "Install netatalk3", "id":"netatalk3", "prompt": "", "type": "install", "group":"", "command": "netatalk3", "args": "" } ] } } ================================================ FILE: config/menu/netatalk.json ================================================ { "menu": { "title": "netatalk4", "description": "Install netatalk4", "id":"netatalk4_install", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install netatalk4", "id":"netatalk4", "prompt": "", "type": "install", "group":"", "command": "netatalk4", "args": "" }, { "index":"20", "title": "Start", "description": "Start Netatalk service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "netatalk", "args": "" }, { "index":"21", "title": "Status", "description": "Query Netatalk status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "netatalk", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the Netatalk service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "netatalk", "args": "" }, { "index":"30", "title": "Start", "description": "Start AppleTalk service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "atalkd", "args": "" }, { "index":"31", "title": "Status", "description": "Query AppleTalk status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "atalkd", "args": "" }, { "index":"32", "title": "Stop", "description": "Stop the AppleTalk service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "atalkd", "args": "" }, { "index":"98", "title": "Legacy", "description": "Install legacy versions of netatalk", "id":"", "prompt": "", "type": "dialog", "group":"", "command": "netatalk-legacy", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Netatalk.md", "args": "" } ] } } ================================================ FILE: config/menu/netlink.json ================================================ { "menu": { "title": "netlink", "description": "Install netlink", "id":"netlink", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install netlink", "id":"netlink", "prompt": "", "type": "install", "group":"", "command": "netlink", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "netlink", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "netlink", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "netlink", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Netlink.md", "args": "" } ] } } ================================================ FILE: config/menu/netmount.json ================================================ { "menu": { "title": "netmount", "description": "Install netmount", "id":"netmount", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install NetMount", "id":"netmount", "prompt": "", "type": "install", "group":"", "command": "netmount", "args": "" }, { "index":"20", "title": "Start", "description": "Start RetroNAS NetMount service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "netmount-drives-retronas", "args": "" }, { "index":"21", "title": "Status", "description": "Query RetroNAS NetMount service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "netmount-drives-retronas", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop RetroNAS NetMount service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "netmount-drives-retronas", "args": "" }, { "index":"23", "title": "Build", "description": "Run the NetMount service builder script", "id":"", "prompt": "", "type": "script", "group":"", "command": "netmount-confman", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "NetMount.md", "args": "" } ] } } ================================================ FILE: config/menu/network-manual.json ================================================ { "menu": { "title": "network", "description": "Manually install networking tools", "id":"network", "prompt": "Install", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index": "02", "title": "firewalld", "description": "Basic firewalld", "id":"firewalld", "prompt": "", "type": "install", "group":"", "command": "firewalld" }, { "index": "03", "title": "dnsmasq", "description": "Basic dnsmasq", "id":"dnsmasq", "prompt": "", "type": "install", "group":"", "command": "dnsmasq" }, { "index": "04", "title": "hostapd", "description": "hostapd", "id":"hostapd", "prompt": "", "type": "install", "group":"", "command": "hostapd" }, { "index": "05", "title": "firewalld-zoning", "description": "retro (eth0)/modern (wlan0) zone", "id":"firewalld-zones", "prompt": "", "type": "install", "group":"", "command": "firewalld-zones" }, { "index": "06", "title": "dnsmasq-retro", "description": "DHCP, DNS support for retro zone", "id":"dnsmasq-retro", "prompt": "", "type": "install", "group":"", "command": "dnsmasq-retro" }, { "index": "07", "title": "dhcpcd", "description": "DHCP client", "id":"dhcpcd", "prompt": "", "type": "install", "group":"", "command": "dhcpcd" } ] } } ================================================ FILE: config/menu/network-presets.json ================================================ { "menu": { "title": "network", "description": "Install networking using pre-selected modes of operation", "id":"network", "prompt": "Install", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index": "02", "title": "preview-zoned", "description": "Preview the zoned network diagram", "id":"network-example-presets-zoned", "prompt": "", "type": "script-static", "group":"", "command": "network-example-presets-zoned" }, { "index": "03", "title": "preview-standalone", "description": "Preview the standalone network diagram", "id":"network-example-presets-standalone", "prompt": "", "type": "script-static", "group":"", "command": "network-example-presets-standalone" }, { "index": "04", "title": "net-ethernet-dhcp", "description": "Install the ethernet dhcp network configuration", "id":"network-presets-ethernet-dhcp", "prompt": "", "type": "install", "group":"", "command": "network-presets-ethernet-dhcp" }, { "index": "05", "title": "net-zoned", "description": "Install the zoned preset network configuration", "id":"network-presets-zoned", "prompt": "", "type": "install", "group":"", "command": "network-presets-zoned" }, { "index": "06", "title": "net-standalone", "description": "Install the zoned preset network configuration", "id":"network-presets-standalone", "prompt": "", "type": "install", "group":"", "command": "network-presets-standalone" } ] } } ================================================ FILE: config/menu/network-setup-modern.json ================================================ { "menu": { "title": "network", "description": "Setup the network for use when installing the network services", "id":"network", "prompt": "Install", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index":"02", "title": "modern-nic", "description": "Set the interface for the Modern network", "id":"set-retronas-net-modern-nic", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-modern-nic", "args": "" } ] } } ================================================ FILE: config/menu/network-setup-retro.json ================================================ { "menu": { "title": "retronet", "description": "Setup the retro network", "id":"network", "prompt": "Install", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index":"02", "title": "retro-nic", "description": "Set the interface for the Retro network", "id":"set-retronas-net-retro-nic", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-retro-nic", "args": "" }, { "index":"03", "title": "dns1", "description": "Set the primary DNS upstream server", "id":"set-retronas-net-upstream-dns1", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-upstream-dns1", "args": "" }, { "index":"04", "title": "dns2", "description": "Set the secondary DNS upstream server", "id":"set-retronas-net-upstream-dns2", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-upstream-dns2", "args": "" }, { "index":"05", "title": "dhcp-ntp", "description": "Set ntp server for the retro network", "id":"set-retronas-net-retro-ntp", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-retro-ntp", "args": "" }, { "index":"06", "title": "dhcp-iprange", "description": "Set the ip range for the retro network", "id":"set-retronas-net-retro-dhcprange", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-retro-dhcprange", "args": "" }, { "index":"07", "title": "dhcp-gateway", "description": "Set the gateway for the retro network", "id":"set-retronas-net-retro-router", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-retro-router", "args": "" }, { "index":"08", "title": "retro-ip", "description": "Set the ip address for the retro network", "id":"set-retronas-net-retro-ip", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-retro-ip", "args": "" }, { "index":"09", "title": "retro-subnet", "description": "Set the subnet for the retro network", "id":"set-retronas-net-retro-subnet", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-retro-subnet", "args": "" }, { "index":"10", "title": "retro-dns", "description": "Set the dns server for the retro network", "id":"set-retronas-net-retro-dns", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-retro-dns", "args": "" } ] } } ================================================ FILE: config/menu/network-setup-wifiap.json ================================================ { "menu": { "title": "wifi ap", "description": "Setup the wifi access point settings, a default password of \"retronas\" is configured at install make sure you change this", "id":"wifiip", "prompt": "Configure", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index":"02", "title": "wifi-show-pwd", "description": "Show the current wifi password", "id":"wifi-show-pw", "prompt": "", "type": "script-static", "group":"", "command": "wifi-show-passwd", "args": "" }, { "index":"03", "title": "wifi-nic", "description": "Set the wifi interface", "id":"set-retronas-net-wifi-interface", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-interface", "args": "" }, { "index":"04", "title": "wifi-ssid", "description": "Set the wifi ssid", "id":"set-retronas-net-wifi-ssid", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-ssid", "args": "" }, { "index":"05", "title": "wifi-cc", "description": "Set the wifi country code", "id":"set-retronas-net-wifi-countrycode", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-countrycode", "args": "" }, { "index":"06", "title": "wifi-hwmode", "description": "Set the wifi hardware mode", "id":"set-retronas-net-wifi-hwmode", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-hwmode", "args": "" }, { "index":"07", "title": "wifi-ip", "description": "Set the ip address for the wifi network", "id":"set-retronas-net-wifi-ip", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-ip", "args": "" }, { "index":"08", "title": "wifi-channel", "description": "Set the wifi channel", "id":"set-retronas-net-wifi-channel", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-channel", "args": "" }, { "index":"09", "title": "wifi-passwd", "description": "Configure wifi password", "id":"wifi-password", "prompt": "", "type": "modal", "group":"", "command": "wifi_password" }, { "index":"10", "title": "wifi-dns", "description": "Set the dns servers", "id":"set-retronas-net-wifi-dns", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-dns", "args": "" }, { "index":"11", "title": "wifi-dhcprange", "description": "Set the ip range for the wifi network", "id":"set-retronas-net-wifi-dhcprange", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-dhcprange", "args": "" }, { "index":"12", "title": "wifi-gateway", "description": "Set the gateway for the wifi network", "id":"set-retronas-net-wifi-router", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-router", "args": "" }, { "index":"13", "title": "wifi-subnet", "description": "Set the subnet for the wifi network", "id":"set-retronas-net-wifi-subnet", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-subnet", "args": "" }, { "index":"14", "title": "wifi-ntp", "description": "Set the subnet for the wifi network", "id":"set-retronas-net-wifi-ntp", "prompt": "", "type": "dialog_input", "group":"", "command": "set-retronas-net-wifi-ntp", "args": "" } ] } } ================================================ FILE: config/menu/network-setup.json ================================================ { "menu": { "title": "network", "description": "Setup the network for use when installing the network services", "id":"network", "prompt": "Install", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index":"02", "title": "retro-net", "description": "Set up the Retro network", "id":"network-setup-retro", "prompt": "", "type": "dialog", "group":"", "command": "network-setup-retro", "args": "" }, { "index":"12", "title": "modern-net", "description": "Set up the Modern network", "id":"network-setup-modern", "prompt": "", "type": "dialog", "group":"", "command": "network-setup-modern", "args": "" }, { "index":"22", "title": "wifi-ap", "description": "Set up the retronas wifi access point", "id":"network-setup-wifiap", "prompt": "", "type": "dialog", "group":"", "command": "network-setup-wifiap", "args": "" } ] } } ================================================ FILE: config/menu/network.json ================================================ { "menu": { "title": "network", "description": "HIGHLY EXPERIMENTAL||This menu will allow you to install firewall, dhcp and dns services. You may install these services as vanilla or install the retro/modern zones to provide isolation.||The default net is 10.99.1.0/23 for retro on eth0 while the modern net is connected over wlan0.||Traffic is forwarded from eth0 to wlan0 for internet access", "id":"network", "prompt": "Install", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index": "02", "title": "manual", "description": "Tools for manual network setup", "id":"network-manual", "prompt": "", "type": "dialog", "group":"", "command": "network-manual" }, { "index": "03", "title": "presets", "description": "Network preset setups", "id":"network-presets", "prompt": "", "type": "dialog", "group":"", "command": "network-presets" }, { "index":"04", "title": "config", "description": "Configure networking", "id":"network-setup", "prompt": "", "type": "dialog", "group":"", "command": "network-setup", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Networking.md", "args": "" } ] } } ================================================ FILE: config/menu/nginx.json ================================================ { "menu": { "title": "nginx", "description": "Install nginx", "id":"nginx", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install nginx", "id":"nginx", "prompt": "", "type": "install", "group":"", "command": "nginx", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "nginx", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "nginx", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "nginx", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "HTTP.md", "args": "" } ] } } ================================================ FILE: config/menu/ntp.json ================================================ { "menu": { "title": "ntp", "description": "Install ntp", "id":"ntp", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install ntp", "id":"ntp", "prompt": "", "type": "install", "group":"", "command": "ntp", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "openntpd", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "openntpd", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "openntpd", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "NTP.md", "args": "" } ] } } ================================================ FILE: config/menu/open-iscsi.json ================================================ { "menu": { "title": "iSCSI options", "description": "Manage iSCSI targets", "id":"open-iscsi", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install iSCSI support", "id":"open-iscsi", "prompt": "", "type": "install", "group":"", "command": "open-iscsi", "args": "" }, { "index":"03", "title": "Targets", "description": "List and login to iSCSI targets", "id":"iscsi-manager-target-login", "prompt": "Login", "type": "script", "group":"", "command": "iscsi-manager-target-login", "args": "" }, { "index":"04", "title": "Start", "description": "Start gadget", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "open-iscsi", "args": "" }, { "index":"05", "title": "Stop", "description": "Stop gadget", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "open-iscsi", "args": "" }, { "index":"06", "title": "Status", "description": "Query gadget", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "open-iscsi", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "iSCSI.md", "args": "" } ] } } ================================================ FILE: config/menu/openssh.json ================================================ { "menu": { "title": "openssh", "description": "Install openssh", "id":"openssh", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install openssh", "id":"openssh", "prompt": "", "type": "install", "group":"", "command": "openssh", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "ssh", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "ssh", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "ssh", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "ssh.md", "args": "" } ] } } ================================================ FILE: config/menu/pi1541.json ================================================ { "menu": { "title": "pi1541", "description": "Assists with setting up a pi1541 sd card device, provide a FAT32 formatted device and run setup", "id":"pi1541", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install pi1541 setup script", "id":"pi151", "prompt": "Install", "type": "install", "group":"", "command": "pi1541", "args": "" }, { "index": "03", "title": "Setup", "description": "Run the setup script", "id":"", "prompt": "", "type": "script", "group":"", "command": "pi1541", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "PI1541.md", "args": "" } ] } } ================================================ FILE: config/menu/piscsi.json ================================================ { "menu": { "title": "piscsi", "description": "Please select an option", "id":"piscsi", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index":"02", "title": "Install", "description": "Install piscsi standalone - (builds FULLSPEC)", "id":"piscsi", "prompt": "Install", "type": "install", "group":"", "command": "piscsi" }, { "index":"03", "title": "Standard", "description": "Build piscsi standalone - STANDARD", "id":"piscsi", "prompt": "Build", "type": "script", "group":"", "command": "install_piscsi_standard" }, { "index":"04", "title": "Fullspec", "description": "Build piscsi standalone - FULLSPEC", "id":"piscsi_fullspec", "prompt": "Install", "type": "script", "group":"", "command": "install_piscsi" }, { "index":"05", "title": "Start", "description": "Start piscsi", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "piscsi" }, { "index":"06", "title": "Stop", "description": "Stop piscsi", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "piscsi" }, { "index":"07", "title": "Status", "description": "Query piscsi", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "piscsi" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "PISCSI.md", "args": "" } ] } } ================================================ FILE: config/menu/profiles.json ================================================ { "menu": { "title": "Installation Profile(s)", "description": "Available installation profiles||Profile Location: \"${OLDRNPATH}/config\"", "id":"profiles", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Profiles.md", "args": "" } ] } } ================================================ FILE: config/menu/proftpd.json ================================================ { "menu": { "title": "proftpd", "description": "Install proftpd", "id":"proftpd", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install proftpd", "id":"proftpd", "prompt": "", "type": "install", "group":"", "command": "proftpd", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "proftpd", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "proftpd", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "proftpd", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "FTP.md", "args": "" } ] } } ================================================ FILE: config/menu/ps2_udpbd.json ================================================ { "menu": { "title": "udpbd", "description": "Install the UPDDB service for PS2", "id":"ps2-udpbd", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install udpbd support", "id":"ps2-udpbd", "prompt": "", "type": "install", "group":"", "command": "ps2_udpbd", "args": "" }, { "index":"03", "title": "Enable", "description": "Enable and Start service", "id":"", "prompt": "", "type": "service_enable_start", "group":"", "command": "ps2_udpbd.service", "args": "" }, { "index":"04", "title": "Disable", "description": "Disable and stop service", "id":"", "prompt": "", "type": "service_disable_stop", "group":"", "command": "ps2_udpbd.service", "args": "" }, { "index":"05", "title": "Status", "description": "Query service", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "ps2_udpbd.service", "args": "" }, { "index":"06", "title": "Restart", "description": "Restart service", "id":"", "prompt": "", "type": "service_restart", "group":"", "command": "ps2_udpbd.service", "args": "" }, { "index":"07", "title": "Select", "description": " Block Device (requires service restart)", "id":"", "prompt": "", "type": "script", "group":"", "command": "udpbd_manager", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "UDPBD.md", "args": "" } ] } } ================================================ FILE: config/menu/ps3netsrv.json ================================================ { "menu": { "title": "ps3netsrv", "description": "Install ps3netsrv", "id":"ps3netsrv", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install ps3netsrv", "id":"ps3netsrv", "prompt": "", "type": "install", "group":"", "command": "ps3netsrv", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "ps3netsrv", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "ps3netsrv", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "ps3netsrv", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "ps3netsrv.md", "args": "" } ] } } ================================================ FILE: config/menu/rclone.json ================================================ { "menu": { "title": "rclone", "description": "Install rclone", "id":"rclone", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install rclone", "id":"rclone", "prompt": "", "type": "install", "group":"", "command": "rclone", "args": "" }, { "index":"20", "title": "Start", "description": "Start webui service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "rclone-webui", "args": "" }, { "index":"21", "title": "Status", "description": "Query webui status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "rclone-webui", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop webui service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "rclone-webui", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "rclone.md", "args": "" } ] } } ================================================ FILE: config/menu/retroaimserver.json ================================================ { "menu": { "title": "RAS", "description": "Install Retro Aim Server||You must have configured your retro network interface address in the Network menu before installing this service", "id":"retroaimserver", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install retroaimserver", "id":"retroaimserver", "prompt": "", "type": "install", "group":"", "command": "retroaimserver", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "retro-aim-server", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "retro-aim-server", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "retro-aims-erver", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "retroaimserver.md", "args": "" } ] } } ================================================ FILE: config/menu/romimport.json ================================================ { "menu": { "title": "ROM Import Tool", "description": "This uses Frederic Mahe's Python scripts and Smokemonster's SMDB databases to import ROMs.||ROMs are matched by checksum, renamed and placed into the matching directory structure via space-saving hard links.||Existing ROMs will never be overwritten.||If ROMs fail to import, it means you have a ROM with a checksum not in the database, or the system type is not yet added.||Place ROMs in the import directory above use SMB/CIFS/AFP/FTP/SCP/SFTP/whatever first.||Do you wish to proceed?", "id":"romimport-menu", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK" }, { "index":"02", "title": "Install", "description": "Install", "id":"romimport", "prompt": "Install", "type": "install", "group":"", "command": "romimport" }, { "index":"04", "title": "Import By System", "description": "Import a Specific System", "id":"romimportsystem", "prompt": "", "type": "modal", "group":"", "command": "romimportsystem", "args": "" }, { "index":"05", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "ROM-import.md", "args": "" } ] } } ================================================ FILE: config/menu/romimportsystem.json ================================================ { "menu": { "title": "ROM Import by System", "description": "Import a specific system.", "id": "romimportsystem", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id": "", "prompt": "", "type": "menu", "group": "", "command": "EXIT_OK", "args": "" }, { "index": "02", "title": "Import Atari 2600", "description": "", "id": "romimport-a2600", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "03", "title": "Import PC Engine CD Redump Supplement", "description": "", "id": "romimport-pcecdrs", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "04", "title": "Import N64", "description": "", "id": "romimport-n64", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "05", "title": "Import NeoGeo Pocket", "description": "", "id": "romimport-ngp", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND" }, { "index": "06", "title": "Import Sega SG-1000", "description": "", "id": "romimport-sg1000", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "07", "title": "Import Colecovision", "description": "", "id": "romimport-cv", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "08", "title": "Import Saturn", "description": "", "id": "romimport-saturn", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "09", "title": "Import MegaDrive/Genesis", "description": "", "id": "romimport-md", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "10", "title": "Import NeoGeo", "description": "", "id": "romimport-neogeo", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "11", "title": "Import SNES/SuperFamicom", "description": "", "id": "romimport-snes", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "12", "title": "Import Watara Supervision", "description": "", "id": "romimport-supervision", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "13", "title": "Import PSX Redump Supplement", "description": "", "id": "romimport-psx", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "14", "title": "Import Sega CD/Mega CD", "description": "", "id": "romimport-megacd", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "15", "title": "Import Wonderswancolor", "description": "", "id": "romimport-wonderswancolor", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "16", "title": "Import Master System", "description": "", "id": "romimport-segams", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "17", "title": "Import Lynx", "description": "", "id": "romimport-lynx", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "18", "title": "Import Gameboy Advance", "description": "", "id": "romimport-gba", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "19", "title": "Import Gameboy Color", "description": "", "id": "romimport-gbc", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "20", "title": "Import Vectrix", "description": "", "id": "romimport-vectrix", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "21", "title": "Import Atari 7800", "description": "", "id": "romimport-a7800", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "22", "title": "Import NeoGeo Pocket Color", "description": "", "id": "romimport-ngpc", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "23", "title": "Import Gameboy", "description": "", "id": "romimport-gb", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "24", "title": "Import Jaguar", "description": "", "id": "romimport-jaguar", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "25", "title": "Import GameGear", "description": "", "id": "romimport-gg", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND" }, { "index": "26", "title": "Import NES/Famicom", "description": "", "id": "romimport-nes", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "27", "title": "Import Atari 5200", "description": "", "id": "romimport-a5200", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "28", "title": "Import PC Engine", "description": "", "id": "romimport-pce", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "29", "title": "Import Wonderswan", "description": "", "id": "romimport-wonderswan", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" }, { "index": "30", "title": "Import Famicom Disk System", "description": "", "id": "romimport-fds", "prompt": "", "type": "script", "group": "romimport", "command": "TOOL COMMAND", "args": "" } ] } } ================================================ FILE: config/menu/romm_cifs.json ================================================ { "menu": { "title": "RomM", "description": "Install the RomM Samba service", "id":"romm-cifs", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install Samba for RomM support", "id":"romm-cifs", "prompt": "", "type": "install", "group":"", "command": "romm_cifs", "args": "" }, { "index":"03", "title": "Enable", "description": "Enable auto dir updates", "id":"", "prompt": "", "type": "service_enable_start", "group":"", "command": "retronas-romm-dirs.timer", "args": "" }, { "index":"04", "title": "Disable", "description": "Disable auto dir updater", "id":"", "prompt": "", "type": "service_disable_stop", "group":"", "command": "retronas-romm-dirs.timer", "args": "" }, { "index":"05", "title": "Status", "description": "Query auto dir updater", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "retronas-romm-dirs*", "args": "" }, { "index":"06", "title": "Run", "description": "Run directory updater now", "id":"", "prompt": "", "type": "service_start_follow", "group":"", "command": "retronas-romm-dirs.service", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "ROMM.md", "args": "" } ] } } ================================================ FILE: config/menu/samba.json ================================================ { "menu": { "title": "samba", "description": "Install samba", "id":"samba", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install samba", "id":"samba", "prompt": "", "type": "install", "group":"", "command": "samba", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "smbd", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"script-static", "group":"", "command": "service-samba", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "smbd", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Samba.md", "args": "" } ] } } ================================================ FILE: config/menu/seaweedfs.json ================================================ { "menu": { "title": "wrp", "description": "Install wrp", "id":"wrp", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install seaweedfs", "id":"seaweedfs", "prompt": "", "type": "install", "group":"", "command": "seaweedfs", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "seaweedfs-retronas", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "seaweedfs-retronas", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "seaweedfs-retronas", "args": "" }, { "index":"23", "title": "Access", "description": "view access keys for the retronas identity", "id":"", "prompt": "", "type": "script", "group":"", "command": "seaweedfs-credentials", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "seaweedfs.md", "args": "" } ] } } ================================================ FILE: config/menu/services.json ================================================ { "menu": { "title": "Services", "description": "Please select a service to check", "id":"services", "prompt": "Check", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" } ] } } ================================================ FILE: config/menu/sslcert.json ================================================ { "menu": { "title": "SSL Certificate", "description": "Manage the SSL Certificate", "id":"sslcert", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Generate", "description": "Generate a self-signed certificate", "id":"sslcert", "prompt": "", "type": "install", "group":"", "command": "sslcert", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "SSL.md", "args": "" } ] } } ================================================ FILE: config/menu/syncthing.json ================================================ { "menu": { "title": "syncthing", "description": "Install syncthing", "id":"syncthing", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install syncthing", "id":"syncthing", "prompt": "", "type": "install", "group":"", "command": "syncthing", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "syncthing", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "syncthing", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "syncthing", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Syncthing.md", "args": "" } ] } } ================================================ FILE: config/menu/tcpser.json ================================================ { "menu": { "title": "tcpser", "description": "Please select an option", "id":"tcpser-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install tcpser application", "id":"tcpser", "prompt": "Install", "type": "install", "group":"", "command": "tcpser", "args": "" }, { "index":"03", "title": "Serial Device", "description": "Create/Edit Serial Device", "id":"tcpser-edit-serial", "prompt": "", "type": "form", "group":"", "command": "tcpser_edit", "args": "" }, { "index":"04", "title": "Virtual Device", "description": "Create/Edit Virtual Device (VICE RS232)", "id":"tcpser-edit-virtual", "prompt": "", "type": "form", "group":"", "command": "tcpser_edit", "args": "VIRTUAL" }, { "index":"05", "title": "Start", "description": "Start tcpser device", "id":"", "prompt": "", "type": "form", "group":"", "command": "tcpser_status", "args": "START" }, { "index":"06", "title": "Status", "description": "Query tcpser device", "id":"", "prompt": "", "type": "form", "group":"", "command": "tcpser_status", "args": "STATUS" }, { "index":"07", "title": "Stop", "description": "Stop tcpser device", "id":"", "prompt": "", "type": "form", "group":"", "command": "tcpser_status", "args": "STOP" } ] }, "tcpser-edit": { "title": "tcpser Modem Config", "description": "Config path: \"${TCPSER_CONFIG_PATH}\"||Legend:|- VIRTUAL: VICE RS232 mode|- PHYSICAL: for USB/Real serial ports||Attention: A Device is considered unique by listen port. Configurations are not read in from existing. This port config will be overwritten on close.", "id":"tcpser-edit-menu", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Edit", "description": "Edit Device", "id":"tcpser-edit-serial-input", "prompt": "", "type": "input:input", "group":"tcpser", "command": "TOOL COMMAND", "args": "" }, { "index":"03", "title": "Port", "description": "Listen Port", "id":"tcpser-edit-port-input", "prompt": "", "type": "input:input", "group":"tcpser", "command": "TOOL COMMAND", "args": "" }, { "index":"04", "title": "Speed", "description": "Baud Rate", "id":"tcpser-edit-speed-input", "prompt": "", "type": "input:input", "group":"tcpser", "command": "TOOL COMMAND", "args": "" }, { "index":"05", "title": "Init String", "description": "Hayes Modem Init String (without leading A)", "id":"tcpser-edit-init-input", "prompt": "", "type": "input:input", "group":"tcpser", "command": "TOOL COMMAND", "args": "" }, { "index":"06", "title": "Additional", "description": "Additional TCPser Options", "id":"tcpser-edit-additional-input", "prompt": "", "type": "input:input", "group":"tcpser", "command": "TOOL COMMAND", "args": "" }, { "index":"06", "title": "Mode", "description": "Device Mode", "id":"tcpser-edit-mode-input", "prompt": "", "type": "input:dropdown:disabled", "group":"tcpser", "command": "TOOL COMMAND", "args": "" } ] }, "tcpser-service": { "title": "tcpser", "description": "Please select an option", "id":"tcpser-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index": "01", "title": "Listen Port", "description": "", "id":"", "prompt": "", "type": "input:input", "group":"", "command": "", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "tcpser.md", "args": "" } ] } } ================================================ FILE: config/menu/telnet.json ================================================ { "menu": { "title": "telnet", "description": "Install telnet", "id":"telnet", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install telnet", "id":"telnet", "prompt": "", "type": "install", "group":"", "command": "telnet", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "inetd", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "inetd", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "inetd", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "Telnet.md", "args": "" } ] } } ================================================ FILE: config/menu/tftpd-hpa.json ================================================ { "menu": { "title": "tftpd-hpa", "description": "Install tftpd-hpa", "id":"tftpd-hpa", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install tftpd-hpa", "id":"tftpd-hpa", "prompt": "", "type": "install", "group":"", "command": "tftpd-hpa", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "tftpd-hpa", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "tftpd-hpa", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "tftpd-hpa", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "tftp.md", "args": "" } ] } } ================================================ FILE: config/menu/tnfs.json ================================================ { "menu": { "title": "tnfsd", "description": "Install tnfsd", "id":"tnfsd", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install tnfsd", "id":"tnfsd", "prompt": "", "type": "install", "group":"", "command": "tnfs", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "tnfsd", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "tnfsd", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "tnfsd", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "TNFS.md", "args": "" } ] } } ================================================ FILE: config/menu/tools.json ================================================ { "menu": { "title": "Tools", "description": "Please select an option to install", "id":"tools", "prompt": "Run", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" } ] } } ================================================ FILE: config/menu/update.json ================================================ { "menu": { "title": "Update", "description": "Please select an option", "id":"update", "prompt": "Update", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "RetroNAS", "description": "Update RetroNAS", "id":"update-retronas", "prompt": "", "type": "script-static", "group":"", "command": "update-retronas", "args": "" }, { "index":"03", "title": "Rom Dir(s)", "description": "Update core RetroNAS rom directories", "id":"romdir", "prompt": "", "type": "install", "group":"", "command": "romdir", "args": "" }, { "index":"04", "title": "Extra Dir(s)", "description": "Update extra RetroNAS directories (bios, saves etc)", "id":"extradirs", "prompt": "", "type": "install", "group":"", "command": "extradirs", "args": "" }, { "index":"05", "title": "GNU/Linux", "description": "Update GNU/Linux Operating System packages", "id":"update-system", "prompt": "", "type": "script-static", "group":"", "command": "update-system" }, { "index":"06", "title": "History", "description": "Update History for GNU/Linux Operating System packages", "id":"update-system-history", "prompt": "View", "type": "script-static", "group":"", "command": "update-system-history", "args": "" }, { "index":"07", "title": "Branch", "description": "Manage the active GIT branch, (test new features, etc)", "id":"git-switch-branch", "prompt": "Manage", "type": "script-static", "group":"", "command": "git-switch-branch", "args": "" }, { "index":"08", "title": "Clean", "description": "Clean up broken symlinks", "id":"clean-broken-symlinks", "prompt": "Run", "type": "script-static", "group":"", "command": "clean-broken-symlinks", "args": "" } ] } } ================================================ FILE: config/menu/webone.json ================================================ { "menu": { "title": "webone", "description": "Install webone", "id":"webone", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install webone", "id":"webone", "prompt": "", "type": "install", "group":"", "command": "webone", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "webone", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "webone", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "webone", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "WebOne.md", "args": "" } ] } } ================================================ FILE: config/menu/wrp.json ================================================ { "menu": { "title": "wrp", "description": "Install wrp", "id":"wrp", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install wrp", "id":"wrp", "prompt": "", "type": "install", "group":"", "command": "wrp", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "wrp", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "wrp", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "wrp", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "wrp.md", "args": "" } ] } } ================================================ FILE: config/menu/xbox360_netiso.json ================================================ { "menu": { "title": "Xbox360 NetISO", "description": "Install Xbox360 NetISO", "id":"xbox360_netiso", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install xbox360_netiso", "id":"xbox360_netiso", "prompt": "", "type": "install", "group":"", "command": "xbox360_netiso", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_enable_start", "group":"", "command": "xbox360_netiso", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "xbox360_netiso", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_disable_stop", "group":"", "command": "xbox360_netiso", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "NetISO.md", "args": "" } ] } } ================================================ FILE: config/menu/xlinkkai.json ================================================ { "menu": { "title": "XLink Kai", "description": "XLink Kai online gaming service for LAN based game modes||WARNING: XLink Kai works by capturing and inspecting network traffic, we recommend you isolate devices running XLink from your main net", "id":"xlinkkai-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install the XLink Kai application", "id":"xlink-kai", "prompt": "Install", "type":"install", "group":"", "command": "xlink-kai", "args": "" }, { "index":"20", "title": "Start", "description": "Start service", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "xlink-kai", "args": "" }, { "index":"21", "title": "Status", "description": "Query service status", "id":"", "prompt": "", "type":"service_status", "group":"", "command": "xlink-kai", "args": "" }, { "index":"22", "title": "Stop", "description": "Stop the service", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "xlink-kai", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "XLink-Kai.md", "args": "" } ] } } ================================================ FILE: config/menu/zterm.json ================================================ { "menu": { "title": "zterm", "description": "Please select an option", "id":"zterm-menu", "prompt": "", "type": "modal", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Install", "description": "Install zterm application", "id":"zterm", "prompt": "Install", "type": "install", "group":"", "command": "zterm", "args": "" }, { "index":"03", "title": "Serial Device", "description": "Create/Edit Serial Device", "id":"zterm-edit-serial", "prompt": "", "type": "form", "group":"", "command": "zterm_edit", "args": "" }, { "index":"04", "title": "Start", "description": "Start zterm device", "id":"", "prompt": "", "type": "service_start", "group":"", "command": "zterm", "args": "" }, { "index":"05", "title": "Stop", "description": "Stop zterm device", "id":"", "prompt": "", "type": "service_stop", "group":"", "command": "zterm", "args": "" }, { "index":"06", "title": "Status", "description": "Query zterm device", "id":"", "prompt": "", "type": "service_status", "group":"", "command": "zterm", "args": "" }, { "index":"99", "title": "Documentation", "description": "Read the service documentation", "id":"", "prompt": "", "type": "documentation", "group":"", "command": "zterm.md", "args": "" } ] }, "zterm-edit": { "title": "zterm Device Config", "description": "set zterm device", "id":"zterm-edit-menu", "prompt": "", "type": "menu", "items": [ { "index": "01", "title": "Back", "description": "Return to previous menu", "id":"", "prompt": "", "type": "menu", "group":"", "command": "EXIT_OK", "args": "" }, { "index":"02", "title": "Edit", "description": "Edit Device", "id":"zterm-edit-serial-input", "prompt": "", "type": "input:input", "group":"zterm", "command": "TOOL COMMAND", "args": "" }, { "index":"03", "title": "Speed", "description": "Baud Rate", "id":"zterm-edit-speed-input", "prompt": "", "type": "input:input", "group":"zterm", "command": "TOOL COMMAND", "args": "" } ] } } ================================================ FILE: config/retronas.cfg ================================================ #!/bin/bash # Dont allow unbound vars, this should be default eventually set -u # Set paths export RNDIR=/opt/retronas export RNDOC=${RNDIR}/doc export USER_CONFIG=${RNDIR}/etc export ANDIR=${RNDIR}/ansible export ANCFG=${ANDIR}/retronas_vars.yml export ANSIBLE_CONFIG=${ANDIR}/ansible.cfg export ACACHEDIR=${RNDIR}/cache export DIDIR=${RNDIR}/dialog export SCDIR=${RNDIR}/scripts export PCHDIR=${SCDIR}/patch/ export LANGDIR=${RNDIR}/lang export LIBDIR=${RNDIR}/lib export LOGDIR=${RNDIR}/log export CONFIGDIR=${RNDIR}/config export TDIR=/dev/shm/retronas export RNLANG="en" export RNJSONOLD=${CONFIGDIR}/retronas.json export RNJSON=${CONFIGDIR}/menu # migrate to using etc for user config export OLDAGREEMENT=${RNDIR}/user_agreement export AGREEMENT=${USER_CONFIG}/user_agreement [ -d "${TDIR}" ] && rm -rf "${TDIR}" 2>/dev/null mkdir -p "${TDIR}" 2>/dev/null # RetroNAS menu geometry export MH="80" export MW="24" export MG="${MW} ${MH}" if [ -f "${ANCFG}" ] then # Find the current config items export OLDRNBRANCH=$(cd ${RNDIR};git branch | awk '/\*/{print $2}') # GOG Settings export OLDGOGOS="$( awk -F': ' '/^retronas_gog_os:/{gsub(/"/,"");print $2}' ${ANCFG} )" export OLDGOGLANG="$( awk -F': ' '/^retronas_gog_lang:/{gsub(/"/,"");print $2}' ${ANCFG} )" IFS=$'\n' for LINE in $(<${ANCFG}) do IFS=": " read -r -a PIECES <<< $LINE VALUE=${PIECES[1]//\"/} case ${PIECES[0]} in retronas_user) OLDRNUSER=$VALUE ;; retronas_group) OLDRNGROUP=$VALUE ;; retronas_path) OLDRNPATH=$VALUE ;; retronas_net_3dsqr_interface) OLD3DSIF=$VALUE ;; retronas_etherdfs_interface) OLDETHERDFSIF=$VALUE ;; retronas_net_retro_interface) OLDRETROIF=$VALUE ;; retronas_net_modern_interface) OLDMODERNIF=$VALUE ;; retronas_net_retro_dhcprange) OLDRETRODHCP=$VALUE ;; retronas_net_retro_router) OLDRETROROUTER=$VALUE ;; retronas_net_retro_ntp) OLDRETRONTP=$VALUE ;; retronas_net_retro_dns) OLDRETRODNS=$VALUE ;; retronas_net_retro_ip) OLDRETROIP=$VALUE ;; retronas_net_retro_subnet) OLDRETROSUBNET=$VALUE ;; retronas_net_upstream_dns1) OLDUPDNS1=$VALUE ;; retronas_net_upstream_dns2) OLDUPDNS2=$VALUE ;; retronas_net_wifi_interface) OLDWIFIINT=$VALUE ;; retronas_net_wifi_ssid) OLDWIFISSID=$VALUE ;; retronas_net_wifi_channel) OLDWIFICHANNEL=$VALUE ;; retronas_net_wifi_hwmode) OLDWIFIHWMODE=$VALUE ;; retronas_net_wifi_countrycode) OLDWIFICC=$VALUE ;; retronas_net_wifi_ip) OLDWIFIIP=$VALUE ;; retronas_net_wifi_subnet) OLDWIFISUBNET=$VALUE ;; retronas_net_wifi_dhcprange) OLDWIFIDHCP=$VALUE ;; retronas_net_wifi_router) OLDWIFIROUTER=$VALUE ;; retronas_net_wifi_ntp) OLDWIFINTP=$VALUE ;; retronas_net_wifi_dns) OLDWIFIDNS=$VALUE ;; esac done fi # Find IPs #export MY_IPS=$( ip a | grep 'inet ' | awk '/inet/{print $2}' | awk -F '/' '{print $1}' | grep -v ^127 ) export MY_IPV4=$( ip -4 -br a | awk '!/127/{sub(/\/[0-9].+$/, ""); print $3}' ) export MY_IPV6=$( ip -6 -br a | awk '!/::1/{sub(/\/[0-9].+$/, ""); print $3}' ) export MY_IPS=( $MY_IPV4 $MY_IPV6 ) # Set some messages export APPNAME="RetroNAS" export PAUSEMSG='Press [Enter] to continue...' export IPADDMSG="IP: ${MY_IPS}" # reset this at the end here so it doesn't screw existing scripts set +u ================================================ FILE: dialog/adtpro_ethernet_edit.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=adtpro_ethernet_edit cd ${DIDIR} OUTDIR=/opt/adtpro SERVICE_CONFIG=${OUTDIR}/ADTPro.properties [ ! -f ${SERVICE_CONFIG} ] && echo "Install adtpro first" && PAUSE # DEFAULTS PORT="$(awk -F "=" '/^UDPServerPort/{print $2}' ${SERVICE_CONFIG})" source $_CONFIG cd ${DIDIR} rn_adtpro_ethernet_edit() { READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=( "Listen Port:" 1 5 "$PORT" 1 20 20 20 ) DLG_FORM "${MENU_TNAME}" "${MENU_ARRAY}" 8 "${MENU_BLURB}" [ ${#CHOICE[@]} -gt 0 ] && rn_adtpro_write_config } rn_adtpro_write_config() { CLEAR if [ ! -z ${CHOICE[0]} ] then echo "Updating device to ${DEVSTR}${CHOICE[0]}" sed -i -r "s#^UDPServerPort.+#UDPServerPort=${DEVSTR}${CHOICE[0]}#" $SERVICE_CONFIG #sed -i -r "s#^Condition.+#ConditionPathExists=${DEVSTR}${CHOICE[0]}#" /usr/lib/systemd/system/adtpro.service systemctl daemon-reload echo "Config file updated, now you can (re)start the service from the Ethernet menu" PAUSE else echo "No change" PAUSE fi EXIT_OK } rn_adtpro_ethernet_edit ================================================ FILE: dialog/adtpro_localhost_edit.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=adtpro_serial_edit cd ${DIDIR} OUTDIR=/opt/adtpro SERVICE_CONFIG=${OUTDIR}/ADTPro.properties [ ! -f ${SERVICE_CONFIG} ] && echo "Install adtpro first" && PAUSE # DEFAULTS SIPHOST="$(awk -F "=" '/^SerialIPHost\=.+$/{print $2}' ${SERVICE_CONFIG})" SIPPORT="$(awk -F "=" '/^SerialIPPort/{print $2}' ${SERVICE_CONFIG})" source $_CONFIG cd ${DIDIR} rn_adtpro_serial_edit() { READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=( "Remote Host:" 1 5 "$SIPHOST" 1 20 20 20 "Remote Port:" 2 5 "$SIPPORT" 2 20 20 20 ) DLG_FORM "${MENU_TNAME}" "${MENU_ARRAY}" 8 "${MENU_BLURB}" [ ${#CHOICE[@]} -gt 1 ] && rn_adtpro_write_config } rn_adtpro_write_config() { CLEAR if [ ! -z ${CHOICE[0]} ] then echo "Updating device to ${DEVSTR}${CHOICE[0]}" sed -i -r "s#^SerialIPHost\=.+#SerialIPHost=${DEVSTR}${CHOICE[0]}#" ${SERVICE_CONFIG} sed -i -r "s#^SerialIPPort.+#SerialIPPort=${DEVSTR}${CHOICE[1]}#" ${SERVICE_CONFIG} #sed -i -r "s#^Condition.+#ConditionPathExists=${DEVSTR}${CHOICE[0]}#" /usr/lib/systemd/system/adtpro.service systemctl daemon-reload echo "Config file updated, now you can (re)start the service from the Serial menu" PAUSE else echo "No change" PAUSE fi EXIT_OK } rn_adtpro_serial_edit ================================================ FILE: dialog/adtpro_serial_edit.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=adtpro_serial_edit cd ${DIDIR} OUTDIR=/opt/adtpro SERVICE_CONFIG=${OUTDIR}/ADTPro.properties [ ! -f ${SERVICE_CONFIG} ] && echo "Install adtpro first" && PAUSE # DEFAULTS DEVICE="$(awk -F "=" '/^CommPort\=.+$/{print $2}' ${SERVICE_CONFIG})" SPEED="$(awk -F "=" '/^CommPortSpeed/{print $2}' ${SERVICE_CONFIG})" BSPEED="$(awk -F "=" '/^CommPortBootstrapSpeed/{print $2}' ${SERVICE_CONFIG})" BPACING="$(awk -F "=" '/^CommPortBootstrapPacing/{print $2}' ${SERVICE_CONFIG})" HANDSHAKE="$(awk -F "=" '/^HardwareHandshaking/{print $2}' ${SERVICE_CONFIG})" source $_CONFIG cd ${DIDIR} rn_adtpro_serial_edit() { READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=( "Comm Port Device:" 1 5 "$DEVICE" 1 27 20 20 "Comm Port Speed:" 2 5 "$SPEED" 2 27 20 20 "Bootstrap Speed:" 3 5 "$BSPEED" 3 27 20 20 "Bootstrap Pacing:" 4 5 "$BPACING" 4 27 20 20 "Hardware Handshaking:" 5 5 "$HANDSHAKE" 5 27 20 20 ) DLG_FORM "${MENU_TNAME}" "${MENU_ARRAY}" 8 "${MENU_BLURB}" [ ${#CHOICE[@]} -gt 1 ] && rn_adtpro_write_config } rn_adtpro_write_config() { CLEAR if [ ! -z ${CHOICE[0]} ] then echo "Updating device to ${DEVSTR}${CHOICE[0]}" sed -i -r "s#^CommPort\=.+#CommPort=${DEVSTR}${CHOICE[0]}#" ${SERVICE_CONFIG} sed -i -r "s#^CommPortSpeed.+#CommPortSpeed=${DEVSTR}${CHOICE[1]}#" ${SERVICE_CONFIG} sed -i -r "s#^CommPortBootstrapSpeed.*#CommPortBootstrapSpeed=${DEVSTR}${CHOICE[2]}#" ${SERVICE_CONFIG} sed -i -r "s#^CommPortBootstrapPacing.*#CommPortBootstrapPacing=${DEVSTR}${CHOICE[3]}#" ${SERVICE_CONFIG} sed -i -r "s#^HardwareHandshaking.*#HardwareHandshaking=${DEVSTR}${CHOICE[4]}#" ${SERVICE_CONFIG} #sed -i -r "s#^Condition.+#ConditionPathExists=${DEVSTR}${CHOICE[0]}#" /usr/lib/systemd/system/adtpro.service systemctl daemon-reload echo "Config file updated, now you can (re)start the service from the Serial menu" PAUSE else echo "No change" PAUSE fi EXIT_OK } rn_adtpro_serial_edit ================================================ FILE: dialog/d_input.sh ================================================ _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh cd ${DIDIR} MENU_NAME=$1 CLEAR ### this needs to be smarter oneday case $MENU_NAME in set-retronas-net-3dsqr-interface) OLDVALUE=${OLD3DSIF} DATASET=($(ip link show | awk '/^[0-9]/{gsub(/:/,"");print $2}')) PATTERN="retronas_net_3dsqr_interface:" ;; set-etherdfs-nic) OLDVALUE=${OLDETHERDFSIF} DATASET=($(ip link show | awk '/^[0-9]/{gsub(/:/,"");print $2}')) PATTERN="retronas_etherdfs_interface:" ;; set-top-level-dir) OLDVALUE="${OLDRNPATH}" DATASET=() PATTERN="retronas_path:" ;; update-user) OLDVALUE="${OLDRNUSER}" DATASET=($(awk -F':' '{print $1}' /etc/passwd | paste -d" " -s)) PATTERN="retronas_user:" ;; update-group) OLDVALUE="${OLDRNGROUP}" DATASET=($(awk -F':' '{print $1}' /etc/group | paste -d" " -s)) PATTERN="retronas_group:" ;; set-retronas-net-modern-nic) OLDVALUE=${OLDMODERNIF} DATASET=($(ip link show | awk '/^[0-9]/{gsub(/:/,"");print $2}')) PATTERN="retronas_net_modern_interface:" ;; set-retronas-net-retro-nic) OLDVALUE=${OLDRETROIF} DATASET=($(ip link show | awk '/^[0-9]/{gsub(/:/,"");print $2}')) PATTERN="retronas_net_retro_interface:" ;; set-retronas-net-retro-dns) OLDVALUE=${OLDRETRODNS} DATASET=() PATTERN="retronas_net_retro_dns:" ;; set-retronas-net-retro-dhcprange) OLDVALUE=${OLDRETRODHCP} DATASET=() PATTERN="retronas_net_retro_dhcprange:" ;; set-retronas-net-retro-router) OLDVALUE=${OLDRETROROUTER} DATASET=() PATTERN="retronas_net_retro_router:" ;; set-retronas-net-retro-ntp) OLDVALUE=${OLDRETRONTP} DATASET=() PATTERN="retronas_net_retro_ntp:" ;; set-retronas-net-retro-ip) OLDVALUE=${OLDRETROIP} DATASET=() PATTERN="retronas_net_retro_ip:" ;; set-retronas-net-retro-subnet) OLDVALUE=${OLDRETROSUBNET} DATASET=() PATTERN="retronas_net_retro_subnet:" ;; set-retronas-net-upstream-dns1) OLDVALUE=${OLDUPDNS1} DATASET=() PATTERN="retronas_net_upstream_dns1:" ;; set-retronas-net-upstream-dns2) OLDVALUE=${OLDUPDNS2} DATASET=() PATTERN="retronas_net_upstream_dns2:" ;; set-retronas-net-wifi-countrycode) OLDVALUE=${OLDWIFICC} DATASET=(AE AR AT AU BG BH BM BO BR CA CH CL CN CO CR CS CY CZ DE DK DO DZ EC EE EG ES FI FR GB GR GT HK HN ID IE IL IN IS IT JM JO JP3 KE KR KW KW LB LI LI LK LT LT LU MA MA MU MX MX NL NO NZ NZ OM PA PA PE PH PK PL PL PR PR PT QA RO RU RU SA SG SI SI SK SK SV TH TH TN TR TT TW UA US UY UY VE VN ZA) PATTERN="retronas_net_wifi_countrycode:" ;; set-retronas-net-wifi-interface) OLDVALUE=${OLDWIFIINT} DATASET=() PATTERN="retronas_net_wifi_interface:" ;; set-retronas-net-wifi-ssid) OLDVALUE=${OLDWIFISSID} DATASET=() PATTERN="retronas_net_wifi_ssid:" ;; set-retronas-net-wifi-channel) OLDVALUE=${OLDWIFICHANNEL} DATASET=() PATTERN="retronas_net_wifi_channel:" ;; set-retronas-net-wifi-hwmode) OLDVALUE=${OLDWIFIHWMODE} DATASET=(a bg) PATTERN="retronas_net_wifi_hwmode:" ;; set-retronas-net-wifi-ip) OLDVALUE=${OLDWIFIIP} DATASET=() PATTERN="retronas_net_wifi_ip:" ;; set-retronas-net-wifi-subnet) OLDVALUE=${OLDWIFISUBNET} DATASET=() PATTERN="retronas_net_wifi_subnet:" ;; set-retronas-net-wifi-dhcprange) OLDVALUE=${OLDWIFIDHCP} DATASET=() PATTERN="retronas_net_wifi_dhcprange:" ;; set-retronas-net-wifi-router) OLDVALUE=${OLDWIFIROUTER} DATASET=() PATTERN="retronas_net_wifi_router:" ;; set-retronas-net-wifi-ntp) OLDVALUE=${OLDWIFINTP} DATASET=() PATTERN="retronas_net_wifi_ntp:" ;; set-retronas-net-wifi-dns) OLDVALUE=${OLDWIFIDNS} DATASET=() PATTERN="retronas_net_wifi_dns:" ;; *) echo "Menu not supported" PAUSE EXIT_CANCEL ;; esac rn_input() { local MENU_NAME="${1}" READ_MENU_TDESC "${MENU_NAME}" DLG_INPUTBOX "${MENU_TNAME}" "${MENU_BLURB}" "${OLDVALUE}" export NEWVALUE="${CHOICE}" if [ ! -z $NEWVALUE ] then COMPARE_VALUES "${NEWVALUE}" "${OLDVALUE}" if [ $CONFIRM -eq 1 ] then rn_input_confirm else rn_input $MENU_NAME fi fi } rn_input_confirm() { unset CHOICE # hacky fix for menu fix [ $MENU_NAME == "update-user" ] && OLDRNUSER=$NEWVALUE [ $MENU_NAME == "update-group" ] && OLDRNGROUP=$NEWVALUE local MENU_PARENT=${MENU_NAME} local MENU_NAME="${MENU_NAME}-confirm" READ_MENU_TDESC "${MENU_NAME}" DLG_YN "${MENU_TNAME}" "${MENU_BLURB}" case ${CHOICE} in 0) # this is crap, fix it later - mostly just for directories atm [ ${#DATASET[@]} -eq 0 ] && DATASET=($(ls -lad "${NEWVALUE}" 2>/dev/null | awk '{print $9}')) echo ${DATASET[*]} | grep -qF ${NEWVALUE} if [ $? -eq 0 ] || [ ${#DATASET[@]} -eq 0 ] then CLEAR source $_CONFIG sed -i "/${PATTERN}/d" "${ANCFG}" echo "${PATTERN} \"${NEWVALUE}\"" >> "${ANCFG}" source $_CONFIG EXIT_OK else CLEAR RN_LOG "${NEWVALUE} is not a valid choice, please confirm your choice" PAUSE rn_input $MENU_PARENT fi ;; *) exit ${CHOICE} ;; esac } rn_input $MENU_NAME ================================================ FILE: dialog/d_menu.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=$1 cd ${DIDIR} CHOICE="" rn_menu() { source $_CONFIG READ_MENU_JSON "${MENU_NAME}" READ_MENU_TDESC "${MENU_NAME}" DLG_MENUJ "${MENU_TNAME}" 10 "${MENU_BLURB}" } CLEAR while true do rn_menu if [ ! -z "${CHOICE}" ] then READ_MENU_COMMAND ${MENU_NAME} ${CHOICE} else EXIT_CANCEL fi done ================================================ FILE: dialog/d_yn.sh ================================================ #!/bin/bash clear _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=$1 cd ${DIDIR} CLEAR rn_dialog_yn() { source $_CONFIG READ_MENU_JSON "${MENU_NAME}" READ_MENU_TDESC "${MENU_NAME}" DLG_YN "${MENU_TNAME}" "${MENU_BLURB}" if [ ! -z "${CHOICE}" ] then READ_MENU_COMMAND ${MENU_NAME} ${CHOICE} else EXIT_CANCEL fi } rn_dialog_yn ${MENU_NAME} ================================================ FILE: dialog/dexdrive_memcards.sh ================================================ #!/bin/bash #set -x _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh cd ${DIDIR} CLEAR DEXEXT="*.mc*" DEXPATH=/data/retronas/saves/sony/playstation1 DEXDEV=/dev/dexdrive0 IFS=";" case $1 in N64) DEXEXT="*.n64" DEXPATH=/data/retronas/saves/nintendo/nintendo64 echo "N64 is untested, let me know what raw save format is for N64" PAUSE exit 0 ;; esac rn_dexdrive_game() { local MENU_NAME=dexdrive_gamechooser READ_MENU_JSON "${MENU_NAME}" READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=() MENU_ARRAY2=() MENU_ARRAY2+=("${DEXPATH}"/${DEXEXT}) if [ "${#MENU_ARRAY2[@]}" -le 0 ] || [ $(echo ${MENU_ARRAY2[@]} | grep "*" ) ] then echo "No memcards found" PAUSE exit 1 fi IFS=";" for ITEM in "${MENU_ARRAY2[@]}" do UPDATED=$(stat -c %y "${ITEM}" | awk '{print $1}') ITEM2="${ITEM##*/}" MEMCARD="${ITEM2%%.*}" TYPE=${ITEM2##*.} MENU_ARRAY+="$ITEM2;$UPDATED;" done echo ${MENU_ARRAY[@]} dialog \ --backtitle "${MENU_TNAME}" \ --title "${MENU_TNAME}" \ --clear \ --menu "${MENU_BLURB}" ${MW} ${MH} 10 \ ${MENU_ARRAY[@]} \ 2> ${TDIR}/rn_dexdrive [ $? -eq 0 ] && rn_dexdrive_image } rn_dexdrive_image() { CLEAR NMEMCARD="$(cat ${TDIR}/rn_dexdrive)" echo "Going to write \"${NMEMCARD}\" to ${DEXDEV}" if [ ! -z "${NMEMCARD}" ] then if [ -b ${DEXDEV} ] then echo "Writing ${NMEMCARD} to ${DEXDEV}, please wait ..." dd if="${DEXPATH}/${NMEMCARD}" of=${DEXDEV} PAUSE else echo "No Dex Drive found at ${DEXDEV}" PAUSE exit 1 fi else exit 1 fi PAUSE } rn_dexdrive_game ================================================ FILE: dialog/dexdrive_serial_edit.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=dexdrive_serial_edit cd ${DIDIR} # DEFAULTS DEVICE="/dev/ttyUSB0" source $_CONFIG cd ${DIDIR} rn_dexdrive_serial_edit() { READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=( "Serial Device:" 1 5 "$DEVICE" 1 27 20 20 ) DLG_FORM "${MENU_TNAME}" "${MENU_ARRAY}" 8 "${MENU_BLURB}" if [ ${#CHOICE[@]} -gt 0 ] then sed -r "s#^(.*)\s(.*)\s(.*)#\1 \2 ${CHOICE[0]}#" -i /etc/systemd/system/linux-dexdrive.service systemctl daemon-reload fi EXIT_OK } rn_dexdrive_serial_edit ================================================ FILE: dialog/disclaimer.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh # MIGRATION [ ! -d $(dirname $AGREEMENT) ] && mkdir $(dirname $AGREEMENT) [ -f $OLDAGREEMENT ] && mv $OLDAGREEMENT $AGREEMENT # User has already agreed, thanks all if [ -f $AGREEMENT ] then EXIT_OK fi clear ## Check our information is available REQFAIL=0 [ ! -f $RNDIR/SECURITY ] && echo "SECURITY information is missing, please reinstall" REQFAIL=1 [ ! -f $RNDIR/LICENSE ] && echo "LICENSE information was not found" && REQFAIL=1 [ $REQFAIL -ne 0 ] && "Required information could not be found, see previous errors" && exit $REQFAIL cat $RNDIR/SECURITY echo -e "\n" read -p "LICENSE will follow, press Enter" echo "" cat $RNDIR/LICENSE echo "" read -p "type AGREE to accept the above in use of this project: " INPUT case $INPUT in "agree"|"AGREE") touch $AGREEMENT EXIT_OK ;; *) EXIT_CANCEL esac ================================================ FILE: dialog/gogrepo.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh cd ${DIDIR} ## Manifests and cookies stored in ~/.gogrepo CLEAR # dumb workaround chmod 755 ${SCDIR} rn_gog_chooser() { local MENU_NAME=gogrepo READ_MENU_JSON "${MENU_NAME}" READ_MENU_TDESC "${MENU_NAME}" DLG_MENUJ "${MENU_TNAME}" 10 "${MENU_BLURB}" while true do source $_CONFIG case ${CHOICE} in 01) EXIT_OK ;; 02) READ_MENU_COMMAND ${MENU_NAME} ${CHOICE} ;; 03) # auth menu rn_gog_auth ;; 04) # OS rn_gog_setos ;; 05) # LANG rn_gog_setlang ;; 06) # sync games list CLEAR DROP_ROOT ${SCDIR}/gogrepo_update.sh -skipknown -os ${OLDGOGOS} -lang ${OLDGOGLANG} PAUSE rn_gog_chooser ;; 07) # download 1 game rn_gog_gameslist rn_gog_game ;; 08) # download all games CLEAR DROP_ROOT ${SCDIR}/gogrepo_download.sh PAUSE ;; 09) # sync and download CLEAR DROP_ROOT ${SCDIR}/gogrepo_update.sh -os ${OLDGOGOS} -lang ${OLDGOGLANG} DROP_ROOT ${SCDIR}/gogrepo_download.sh PAUSE rn_gog_chooser ;; *) EXIT_CANCEL ;; esac unset CHOICE done } rn_gog_setlang() { source $_CONFIG local MENU_NAME=gogrepo READ_MENU_JSON "${MENU_NAME}" "${MENU_NAME}-setuplang" READ_MENU_TDESC "${MENU_NAME}" "${MENU_NAME}-setuplang" DLG_MENUJ "${MENU_TNAME}" 10 "${MENU_BLURB}" case ${CHOICE} in 01) rn_gog_chooser ;; ${CHOICE} ) NEWLANG="${CHOICE}" sed -i '/retronas_gog_lang:/d' "${ANCFG}" echo "retronas_gog_lang: \"${NEWLANG}\"" >> "${ANCFG}" ;; *) rn_gog_chooser ;; esac rn_gog_chooser } rn_gog_auth() { source $_CONFIG local MENU_NAME=gogrepo READ_MENU_JSON "${MENU_NAME}" "${MENU_NAME}-auth" READ_MENU_TDESC "${MENU_NAME}" "${MENU_NAME}-auth" DLG_MENUJ "${MENU_TNAME}" 10 "${MENU_BLURB}" case ${CHOICE} in 02) # login CLEAR DROP_ROOT ${SCDIR}/gogrepo_login.sh PAUSE ;; 03) # import cookies CLEAR bash ${SCDIR}/gogrepo_import-cookies.sh PAUSE ;; *) rn_gog_chooser ;; esac } rn_gog_setos() { source $_CONFIG local MENU_NAME=gogrepo READ_MENU_JSON "${MENU_NAME}" "${MENU_NAME}-setupos" READ_MENU_TDESC "${MENU_NAME}" "${MENU_NAME}-setupos" DLG_MENUJ "${MENU_TNAME}" 10 "${MENU_BLURB}" case ${CHOICE} in 02) NEWOS="windows" ;; 03) NEWOS="mac" ;; 04) NEWOS="linux" ;; 05) NEWOS="windows mac" ;; 06) NEWOS="windows linux" ;; 07) NEWOS="mac linux" ;; 08) NEWOS="windows mac linux" ;; *) rn_gog_chooser ;; esac if [ ! -z $NEWOS ]; then sed -i '/retronas_gog_os:/d' "${ANCFG}" echo "retronas_gog_os: \"${NEWOS}\"" >> "${ANCFG}" fi rn_gog_chooser } rn_gog_gameslist() { rm ${TDIR}/rn_gog_gameslist 2>/dev/null RNUDIR=$( getent passwd | grep ^${OLDRNUSER}\: | awk -F ':' '{print $6}' ) if [ ! -f ${RNUDIR}/.gogrepo/gog-manifest.dat ] then echo "GOG Manifest not found, you'll need to login/sync first" PAUSE echo 1 else grep \'title\'\: ${RNUDIR}/.gogrepo/gog-manifest.dat | awk -F \' '{print $4}' | sort | while read RN_GOG_ID do echo "${RN_GOG_ID}" >>${TDIR}/rn_gog_gameslist done fi } rn_gog_game() { local MENU_NAME=gogrepo READ_MENU_JSON "${MENU_NAME}" "${MENU_NAME}-gamechooser" READ_MENU_TDESC "${MENU_NAME}" "${MENU_NAME}-gamechooser" declare -a MENU_ARRAY mapfile -t PIECES < ${TDIR}/rn_gog_gameslist MENU_ARRAY+=("Back" ".") for PIECE in ${PIECES[@]} do MENU_ARRAY+=($PIECE ".") done DLG_MENU "${MENU_TNAME}" "${MENU_ARRAY}" 10 "${MENU_BLURB}" case ${CHOICE} in Back) rn_gog_chooser ;; ${CHOICE}) CLEAR DROP_ROOT ${SCDIR}/gogrepo_update.sh -os ${OLDGOGOS} -id ${CHOICE} -lang ${OLDGOGLANG} DROP_ROOT ${SCDIR}/gogrepo_download.sh -id ${CHOICE} PAUSE unset CHOICE rn_gog_game ;; *) rn_gog_chooser ;; esac unset MENU_ARRAY } rn_gog_chooser ================================================ FILE: dialog/profiles.sh ================================================ #!/bin/bash #set -x clear _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh PROFILED="${OLDRNPATH}/config" cd ${DIDIR} CLEAR if [ ! -d "${PROFILED}" ] then echo "${PROFILED} not found, exiting" PAUSE exit 1 fi rn_profile_chooser() { local MENU_NAME=profiles READ_MENU_JSON "${MENU_NAME}" READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=() MENU_ARRAY2+=("$PROFILED"/*.ini ) if [ "${#MENU_ARRAY2[@]}" -le 0 ] || [ $(echo ${MENU_ARRAY2[@]} | grep "*" ) ] then echo "No profiles found" PAUSE exit 1 fi IFS=";" for ITEM in "${MENU_ARRAY2[@]}" do #TITLE="$(grep -E "^title\s=" "${ITEM}" | cut -d' ' -f3-)" UPDATED=$(grep -E "^last_updated\s=" "${ITEM}" | cut -d' ' -f3-) [ -z "${TITLE}" ] && TITLE="Unknown" [ -z "${UPDATED}" ] && UPDATED="00-00-0000" ITEM2=${ITEM##*/} ININAME="${ITEM2%%.*}" MENU_ARRAY+="$ININAME;$UPDATED;" done dialog \ --backtitle "${MENU_NAME}" \ --title "${MENU_NAME}" \ --clear \ --menu "${MENU_BLURB}" ${MW} ${MH} 10 \ ${MENU_ARRAY[@]} \ 2> ${TDIR}/rn_profile CLEAR PROFILE="$(cat ${TDIR}/rn_profile)" if [ ! -z "$PROFILE" ] then python3 ${SCDIR}/maint/install-profile.py --profile "${PROFILED}/${PROFILE}.ini" else exit 1 fi } rn_profile_chooser ================================================ FILE: dialog/retronas_fixperms.sh ================================================ #!/bin/bash set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh cd ${DIDIR} rn_get_dirs() { COUNT=3 cd "${OLDRNPATH}" find . -maxdepth 1 -type d | sed 's#^\./##g' | grep -v ^\.$ | sort | while read PATHITEM do printf "%s\n%s\n" "${PATHITEM}" "${PATHITEM}" COUNT=$((${COUNT}+1)) done } rn_fix_perms() { cd ${DIDIR} local MENU_ARRAY=( 1 "Back" all "ALL" $(rn_get_dirs) ) local MENU_BLURB="\nPlease choose a directory below ${OLDRNPATH} to fix. \ \n\nThis will reset all the file ownership to the user \"${OLDRNUSER}\" \ \n\nPlease be careful, as this is irreversible. If unsure, exit now." DLG_MENU "Fix Permissions" $MENU_ARRAY 10 "${MENU_BLURB}" } CLEAR rn_fix_perms case ${CHOICE} in 1) EXIT_OK ;; *) CLEAR bash $SCDIR/static/permissions.sh ${CHOICE} PAUSE ;; esac ================================================ FILE: dialog/retronas_password.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=update-password cd ${DIDIR} rn_retronas_password() { source ${LIBDIR}/common.sh READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=( "Password:" 1 10 "" 1 20 20 20 "Repeat:" 2 10 "" 2 20 20 20 ) DLG_PASSWORD "${MENU_TNAME}" "${MENU_ARRAY}" 5 "${MENU_BLURB}" # if we can't create the sub-window report it and exit echo ${CHOICE[0]} | grep "make sub-window" &> /dev/null if [ $? -eq 0 ] then echo "Failed to create sub-window, if possible resize your terminal window and try again" PAUSE exit fi PASS_ONE=${CHOICE[0]} PASS_TWO=${CHOICE[1]} if [ ! -z "${PASS_ONE}" ] then if [ "${PASS_ONE}" == "${PASS_TWO}" ] then CLEAR /opt/retronas/scripts/static/update-passwd.sh "${PASS_ONE}" PAUSE else RN_LOG "Passwords do not match" PAUSE rn_retronas_password fi else RN_LOG "Password was blank" EXIT_CANCEL fi } CLEAR rn_retronas_password ================================================ FILE: dialog/romimportsystem.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh cd ${DIDIR} CLEAR rn_import_system() { local MENU_NAME=romimportsystem READ_MENU_JSON "${MENU_NAME}" READ_MENU_TDESC "${MENU_NAME}" DLG_MENUJ "${MENU_TNAME}" 10 "${MENU_BLURB}" I=2 while IFS=" ";read -ra LINE; do if [[ "${LINE[0]}" == "id:" ]]; then SYSTEMS+=${LINE[1]}' ' SYSTEM_ARR[$I]=${LINE[1]} ((++I)) fi done < <(/opt/retronas/scripts/romimport.sh -l) while true do source $_CONFIG case ${CHOICE} in 01) EXIT_OK ;; [0-9][0-9]) CLEAR DROP_ROOT /opt/retronas/scripts/romimport.sh -t ${SYSTEM_ARR[10#$CHOICE]} PAUSE ;; *) EXIT_CANCEL ;; esac unset CHOICE done } rn_import_system ================================================ FILE: dialog/tcpser_edit.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=tcpser-edit cd ${DIDIR} # DEFAULTS DEVICE="/dev/ttyUSB0" LISTEN=23456 SPEED=9600 INIT=Z ADDN="" MODE="PHYSICAL" source $_CONFIG cd ${DIDIR} MODE=${1:-PHYSICAL} rn_tcpser_edit() { [ $MODE == "VIRTUAL" ] && DEVICE=25232 TCPSER_CONFIG_PATH=/opt/retronas/etc/tcpser TCPSER_CONFIG=${TCPSER_CONFIG_PATH}/tcpser-${LISTEN} READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=( "Device:" 1 5 "$DEVICE" 1 20 20 20 "Listen Port:" 2 5 "$LISTEN" 2 20 20 20 "Speed:" 3 5 "$SPEED" 3 20 20 20 "Init String:" 4 5 "$INIT" 4 20 20 20 "Additional" 5 5 "$ADDN" 5 20 20 20 "Mode" 6 5 "$MODE" 6 20 20 20 ) DLG_FORM "${MENU_TNAME}" "${MENU_ARRAY}" 8 "${MENU_BLURB}" [ ${#CHOICE[@]} -gt 0 ] && rn_tcpser_write_envfile } rn_tcpser_write_envfile() { if [ "${#CHOICE[1]}" -gt 1 ] then local TCPSER_CONFIG=/opt/retronas/etc/tcpser/tcpser-${CHOICE[1]} [ ${#CHOICE[0]} -le 1 ] && DATA[0]=$DEVICE [ ${#CHOICE[2]} -le 1 ] && DATA[2]=$SPEED [ ${#CHOICE[3]} -le 1 ] && DATA[3]=$INIT [ ${#CHOICE[4]} -le 1 ] && DATA[4]=$ADDN [ ${#CHOICE[5]} -le 1 ] && DATA[5]=$MODE DEVSTR="d" [ ${DATA[5]} == "VIRTUAL" ] && DEVSTR="v" echo "DEVICE=-${DEVSTR}${CHOICE[0]}" > "${TCPSER_CONFIG}" echo "LISTEN=-p${CHOICE[1]}" >> "${TCPSER_CONFIG}" echo "SPEED=-s${CHOICE[2]}" >> "${TCPSER_CONFIG}" echo "INIT=-i${CHOICE[3]}" >> "${TCPSER_CONFIG}" echo "ADDN=${CHOICE[4]}" >> "${TCPSER_CONFIG}" EXIT_OK else echo "No data available for LISTEN port, so we won't be writing a file" PAUSE rn_tcpser_edit fi } rn_tcpser_edit ================================================ FILE: dialog/tcpser_status.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=tcpser-service cd ${DIDIR} rn_tcpser_status() { source $_CONFIG local MODE="${1}" READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=( "Listen Port:" 1 5 "$LISTEN" 2 20 20 20 ) DLG_FORM "${MENU_TNAME}" "${MENU_ARRAY}" 8 "${MENU_BLURB}" [ ${#CHOICE[@]} -gt 0 ] && RN_SYSTEMD_$(echo ${MODE} | tr '[a-z]' '[A-Z]') tcpser@${CHOICE}.service PAUSE } CLEAR rn_tcpser_status "${1}" ================================================ FILE: dialog/wifi_password.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=update-wifi-password cd ${DIDIR} rn_wifi_password() { source ${LIBDIR}/common.sh READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=( "Password:" 1 10 "" 1 20 20 20 "Repeat:" 2 10 "" 2 20 20 20 ) DLG_PASSWORD "${MENU_TNAME}" "${MENU_ARRAY}" 10 "${MENU_BLURB}" PASS_ONE=${CHOICE[0]} PASS_TWO=${CHOICE[1]} if [ ! -z "${PASS_ONE}" ] then if [ "${PASS_ONE}" == "${PASS_TWO}" ] then CLEAR /opt/retronas/scripts/static/wifi-update-passwd.sh "${PASS_ONE}" PAUSE else RN_LOG "Passwords do not match" PAUSE rn_wifi_password fi else RN_LOG "Password was blank" EXIT_CANCEL fi } CLEAR rn_wifi_password ================================================ FILE: dialog/zterm_edit.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh MENU_NAME=zterm-edit cd ${DIDIR} [ ! -f /opt/zterm/zconfig ] && echo "Install zterm first" && PAUSE # DEFAULTS DEVICE="$(awk -F "=" '/^DEV/{print $2}' /opt/zterm/zconfig)" SPEED="$(awk -F "=" '/^SPEED/{print $2}' /opt/zterm/zconfig)" ADDN="$(awk -F "=" '/^ADDN/{print $2}' /opt/zterm/zconfig)" OUTDIR=/opt/zterm source $_CONFIG cd ${DIDIR} rn_zterm_edit() { READ_MENU_TDESC "${MENU_NAME}" MENU_ARRAY=( "Device:" 1 5 "$DEVICE" 1 20 20 20 "Speed:" 2 5 "$SPEED" 2 20 20 20 "Additional" 3 5 "$ADDN" 3 20 20 20 ) DLG_FORM "${MENU_TNAME}" "${MENU_ARRAY}" 8 "${MENU_BLURB}" [ ${#CHOICE[@]} -gt 1 ] && rn_zterm_write_config } rn_zterm_write_config() { CLEAR if [ ! -z ${CHOICE[0]} ] then echo "Updating device to ${DEVSTR}${CHOICE[0]}" sed -i -r "s#^DEV.+#DEV=${DEVSTR}${CHOICE[0]}#" $OUTDIR/zconfig sed -i -r "s#^SPEED.+#SPEED=${DEVSTR}${CHOICE[1]}#" $OUTDIR/zconfig sed -i -r "s#^ADDN.*#ADDN=${DEVSTR}${CHOICE[2]}#" $OUTDIR/zconfig sed -i -r "s#^Condition.+#ConditionPathExists=${DEVSTR}${CHOICE[0]}#" /usr/lib/systemd/system/zterm.service systemctl daemon-reload systemctl restart zterm.service else echo "No change" PAUSE fi EXIT_OK } rn_zterm_edit ================================================ FILE: dist/install_preseed.sh ================================================ #!/bin/sh # # This is intended to be used to preseed a debian iso # as part of d-i preseed/late_command # # needs to be cleaned up or replaced, just for testing # if [ ! -f /opt/retronas/retronas_deployed ] && [ ! -f /opt/retronas/retronas_running ] then touch /opt/retronas/retronas_running /usr/bin/curl -so /tmp/install_retronas.sh https://raw.githubusercontent.com/retronas/retronas/main/install_retronas.sh /usr/bin/chmod a+x /tmp/install_retronas.sh /tmp/install_retronas.sh cd /opt/retronas/ansible cp retronas_vars.yml.default retronas_vars.yml /usr/bin/ansible-playbook -vv retronas_dependencies.yml /usr/bin/ansible-playbook -vv install_filesystems.yml /usr/bin/ansible-playbook -vv install_cockpit.yml /usr/bin/ansible-playbook -vv install_cockpit-packages.yml #/usr/bin/ansible-playbook -vv install_cockpit-retronas.yml rm /opt/retronas/retronas_running touch /opt/retronas/retronas_deployed fi ================================================ FILE: dist/retronas ================================================ #!/bin/bash sudo -E /opt/retronas/retronas.sh $* ================================================ FILE: install_retronas.sh ================================================ #!/bin/bash set -u GITREPO='https://github.com/retronas/retronas.git' FORCE=0 TARGET=/opt/retronas MYID=$( whoami ) _usage() { echo "Usage $0" echo "-h this help" echo "-o override git repo/branch to install from" echo "-f force re-installation (EXPERT)" exit 0 } if [ "${MYID}" != "root" ] then echo "This script needs to be run as sudo/root" echo "Please re-run:" echo "sudo $0" exit 1 fi OPTSTRING="fho:" while getopts $OPTSTRING ARG do case $ARG in h) _usage ;; o) GITREPO="${OPTARG}" ;; f) FORCE=1 ;; esac done # handle existing installations [ -f ${TARGET}/.git/config ] && [ $FORCE -eq 0 ] && echo "Existing installation pass -f to overwrite" && exit 1 [ -f ${TARGET}/.git/config ] && [ $FORCE -eq 1 ] && echo "Installation exists, -f passed, removing" && rm -rf "${TARGET}/" echo echo "Updating repo cache..." apt update echo echo "Installing necessary tools..." apt install -y ansible git dialog jq pandoc lynx sudo if [ ! -f ${TARGET}/.git/config ] then echo echo "Downloading RetroNAS...from ${GITREPO}" cd /opt git clone "$GITREPO" chmod a+x /opt/retronas/retronas.sh if [ $? -eq 0 ] then # docs if [ ! -f ${TARGET}/doc/.git/config ] then echo "Downloading RetroNAS documentation ...from ${GITREPO}" git clone https://github.com/retronas/retronas.wiki.git ${TARGET}/doc fi #installing a simple starup script cp /opt/retronas/dist/retronas /usr/local/bin/retronas chmod a+x /usr/local/bin/retronas echo echo "All done. You can now run the RetroNAS config tool with the following command:" echo echo "retronas" echo else echo "Installation FAILED, check previous messages" fi fi ================================================ FILE: lib/ansible_runner.sh ================================================ #!/bin/bash # # Ansible wrapper to trigger playbooks # or roles through tags # set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG PREFIX=install_ SUFFIX=.yml ANSCMD="/usr/bin/ansible-playbook" cd "${ANDIR}" function run_ansible { local PLAYBOOK="${1}" [ ! -f ${PLAYBOOK} ] && echo "Failed to find playbook: ${PLAYBOOK}" && exit 1 ${ANSCMD} "${PLAYBOOK}" } [ -z "${1}" ] && echo "No options passed" && exit 1 [ ! -f ${ANSCMD} ] && echo "Ansible is not installed, install it first" && exit 1 IFS=':' read -r -a PLAYBOOKS <<< "${1}" [ ${#PLAYBOOKS[@]} -eq 0 ] && echo "Failed to read args, exiting" && exit 1 run_ansible ${ANDIR}/retronas_dependencies.yml for PLAYBOOK in ${PLAYBOOKS[@]} do run_ansible "${ANDIR}/${PREFIX}${PLAYBOOK}${SUFFIX}" done ================================================ FILE: lib/common.sh ================================================ #!/bin/bash set -u export SC="systemctl --no-pager --full" ############################################################################### # # Logging # ############################################################################### # # use RN_LOG instead of echo, so we can centralise logging approach # RN_LOG() { echo "${1}" } ############################################################################### # # Package # ############################################################################### CHECK_PACKAGE_CACHE() { case $1 in *) # check if apt was updated in the last 24 hours if find /var/cache/apt -maxdepth 1 -type f -mtime -1 -exec false {} + then echo "APT repositories are old, syncing..." apt update fi ;; esac } ############################################################################### # # GENERAL reusable functions # ############################################################################### # # Compare two values # COMPARE_VALUES() { local STROLD=$1 local STRNEW=$2 export CONFIRM=0 if [ ! -z ${STRNEW} ] then if [ "${STRNEW}" != "${STROLD}" ] then # Confirm the input #CHECK_USER_EXISTS $STRNEW $STROLD export CONFIRM=1 else CLEAR RN_LOG "Item not changed" PAUSE fi else CLEAR RN_LOG "No values to process" PAUSE fi } # # CONFIRM A VALUE # CONFIRM_VALUE() { echo $1 } ############################################################################### # # PRIVILEGE handlers # ############################################################################### ## If this is run as root, switch to our RetroNAS user DROP_ROOT() { sudo -u ${OLDRNUSER} -s $* } ### Check if we have the correct privs for op CHECK_ROOT() { [ $UID -ne 0 ] && echo "You must run this as root, try sudo " && exit 1 } ############################################################################### # # LANGUAGE handlers # ############################################################################### ### Get LANG file GET_LANG() { [ ! -z "${LANG}" ] && RNLANG=$(echo $LANG | awk -F'_' '{print $1}') [ -z ${RNLANG} ] && RNLANG="en" if [ -f ${LANGDIR}/${RNLANG} ] then source ${LANGDIR}/${RNLANG} else echo "Failed to load language file, check config is complete" exit 1 fi } ############################################################################### # # MENU data loaders # ############################################################################### # # Read menu items from the json config # export the data for use in dialogs # READ_MENU_TDESC() { export MENU_TITLE="$1" export MENU="$2" # handle submenus [ -z "$MENU" ] && MENU="menu" if [ -f ${RNJSON}/${MENU_TITLE}.json ] then local MENU_TDESC_DATA=$(<${RNJSON}/${MENU_TITLE}.json jq -r ".\"${MENU}\" | \"\(.title);\(.description)\"") elif [ -f ${RNJSONOLD} ] then local MENU_TDESC_DATA=$(<${RNJSONOLD} jq -r ".dialog.\"${MENU_TITLE}\" | \"\(.title);\(.description)\"") else local MENU_TDESC_DATA=$(<${RNJSON}/main.json jq -r ".menu | \"\(.title);\(.description)\"") fi local IFS=$'\n' IFS=";" read -r -a PIECES <<< ${MENU_TDESC_DATA} export MENU_TNAME=${PIECES[0]} # eval ... yes i'm so terribly sorry export MENU_BLURB=$(eval "echo $(echo ${PIECES[@]:1} | sed 's/|/\\\\n/g')" ) } # # Read menu items from the json config # export the data for use in dialogs # READ_MENU_JSON() { local MENU_TITLE="${1}" local MENU="${2}" # handle submenus [ -z "$MENU" ] && MENU="menu" if [ -f ${RNJSON}/${MENU_TITLE}.json ] then export MENU_DATA=$(<${RNJSON}/${MENU_TITLE}.json jq -r ".\"${MENU}\".items[] | \"\(.index)|\(.title)|\(.description)|\(.type)\"") elif [ -f ${RNJSONOLD} ] then export MENU_DATA=$(<${RNJSONOLD} jq -r ".dialog.\"${MENU}\".items[] | \"\(.index)|\(.title)|\(.description);\"") else export MENU_DATA=$(<${RNJSON}/main.json jq -r ".menu.items[] | \"\(.index)|\(.title)|\(.description);\"") fi } # # Looks up the menu item in the json file. returns both type and command values # type determines the action taken # command is a colon separated list of actions taken by helper functions # READ_MENU_COMMAND() { local MENU_NAME="$1" local MENU_CHOICE=$2 cd "${RNDIR}" if [ -f ${RNJSON}/${MENU_TITLE}.json ] then MENU_DATA=$(<${RNJSON}/${MENU_TITLE}.json jq -r ".menu.items[] | select(.index == \"${MENU_CHOICE}\") | \"\(.type)|\(.command)|\(.args)\"") elif [ -f ${RNJSONOLD} ] then MENU_DATA=$(<${RNJSONOLD} jq -r ".dialog.${MENU_NAME}.items[] | select(.index == \"${MENU_CHOICE}\") | \"\(.type)|\(.command)\"") else MENU_DATA=$(<${RNJSON}/main.json jq -r ".menu.items[] | select(.index == \"${MENU_CHOICE}\") | \"\(.type)|\(.command)|\(.args)\"") fi IFS="|" read -r -a PIECES <<< ${MENU_DATA} local MENU_TYPE=${PIECES[0]} local MENU_SELECT=${PIECES[1]} local MENU_ARGS=${PIECES[@]:2} CLEAR if [ ! -z "${MENU_SELECT}" ] && [ "${MENU_SELECT}" != "null" ] then case $MENU_TYPE in install) RN_INSTALL_EXECUTE $MENU_SELECT ;; modal) EXEC_SCRIPT "m-${MENU_SELECT}" ;; dialog) EXEC_SCRIPT "d-${MENU_SELECT}" ;; dialog_input) EXEC_SCRIPT "i-${MENU_SELECT}" ;; dialog_yn) EXEC_SCRIPT "y-${MENU_SELECT}" ;; form) EXEC_SCRIPT "f-${MENU_SELECT}" $MENU_ARGS ;; script) EXEC_SCRIPT $MENU_SELECT $MENU_ARGS ;; script-static) EXEC_SCRIPT "s-${MENU_SELECT}" ;; service_status) RN_SYSTEMD_STATUS "${MENU_SELECT}" ;; service_enable_start) RN_SYSTEMD_ENABLE "${MENU_SELECT}" RN_SYSTEMD_START "${MENU_SELECT}" ;; service_start) RN_SYSTEMD_START "${MENU_SELECT}" ;; service_start_follow) RN_SYSTEMD_START "${MENU_SELECT}" RN_JOURNAL_FOLLOW "${MENU_SELECT}" ;; service_restart) RN_SYSTEMD_RESTART "${MENU_SELECT}" ;; service_disable_stop) RN_SYSTEMD_DISABLE "${MENU_SELECT}" RN_SYSTEMD_STOP "${MENU_SELECT}" ;; service_stop) RN_SYSTEMD_STOP "${MENU_SELECT}" ;; menu) "${MENU_SELECT}" ;; command) bash -c "${MENU_SELECT}" ;; documentation) RN_DOCUMENTATION "${MENU_SELECT}" ;; *) echo "Not supported, why are you here?" PAUSE ;; esac else echo "Failed to select item for $MENU_CHOICE" PAUSE fi unset MENU_SELECT } ############################################################################### # # EXIT handlers # ############################################################################### EXIT_OK() { CLEAR exit 0 } EXIT_CANCEL() { CLEAR exit 1 } ### Clear function, standardised CLEAR() { clear } ### Wait for user input PAUSE() { echo "${PAUSEMSG}" read -s } ############################################################################### # # COMMAND handlers # ############################################################################### ### Run a script EXEC_SCRIPT() { local SCRIPT="${1}" #CLEAR #CHECK_PACKAGE_CACHE CLEAR shift /opt/retronas/lib/script_runner.sh "${SCRIPT}" $* cd ${DIDIR} unset SCRIPT } # # Install Ansible Dependencies, runs with every installer # # !!! this function will be deprecated # RN_INSTALL_DEPS() { source $_CONFIG cd ${ANDIR} CLEAR CHECK_PACKAGE_CACHE ansible-playbook -vv retronas_dependencies.yml cd ${DIDIR} } # # Run the playbook # RN_INSTALL_EXECUTE() { source $_CONFIG local PLAYBOOK=$1 CLEAR CHECK_PACKAGE_CACHE CLEAR /opt/retronas/lib/ansible_runner.sh "${PLAYBOOK}" PAUSE #cd ${ANDIR} #ansible-playbook -vv "${PLAYBOOK}" cd ${DIDIR} unset PLAYBOOK } # # Run the pandoc/lynx # RN_DOCUMENTATION() { source $_CONFIG local DOCUMENTATION=$1 CLEAR /opt/retronas/lib/markup_runner.sh "${DOCUMENTATION}" cd ${DIDIR} unset DOCUMENTATION } ############################################################################### # # SERVICE query/type handlers # ############################################################################### # # Service status formatting # RN_SERVICE_STATUS() { local CMD="$1" CLEAR echo "${CMD}" echo ; eval $CMD ; echo #PAUSE } # # SYSTEMD status checks # RN_SYSTEMD_STATUS() { RN_SYSTEMD "${1}" "status" PAUSE } # # SYSTEMD enable # RN_SYSTEMD_ENABLE() { RN_SYSTEMD "${1}" "enable" } # # SYSTEMD start # RN_SYSTEMD_START() { RN_SYSTEMD "${1}" "start" } # # SYSTEMD restart # RN_SYSTEMD_RESTART() { RN_SYSTEMD "${1}" "restart" } # # SYSTEMD disable # RN_SYSTEMD_DISABLE() { RN_SYSTEMD "${1}" "disable" } # # SYSTEMD stop # RN_SYSTEMD_STOP() { RN_SYSTEMD "${1}" "stop" } # # SYSTEMD # RN_SYSTEMD() { local SERVICE="$1" local COMMAND="${2:-status}" RN_SERVICE_STATUS "${SC} ${COMMAND} ${SERVICE}" } # # JOURNAL follow # RN_JOURNAL_FOLLOW() { journalctl --follow -u "${1}" } # # DIRECTLY call a status command, and pass args # RN_DIRECT_STATUS() { source $_CONFIG local SERVICE="$1" local ARGS="$2" if [ -x "$(which $SERVICE)" ] then RN_SERVICE_STATUS "${SERVICE} ${ARGS}" fi } ############################################################################### # # DIALOG builder functions # based on: https://stackoverflow.com/questions/4889187/dynamic-dialog-menu-box-in-bash # ############################################################################### # # MENU # DLG_MENUJ() { local IFS=$'\n' local TITLE="$1" local MENU_H=$2 local MENU_BLURB=$3 local MENU_DESC="${IPADDMSGNO}${MENU_BLURB}" DIALOG=(dialog \ --backtitle "${APPNAME}" \ --title "${APPNAME} ${TITLE} Menu" \ --clear \ --no-shadow \ --menu "$MENU_DESC" ${MW} ${MH} ${MENU_H}) declare -a MENU_ARRAY for ITEM in ${MENU_DATA[@]} do IFS="|" read -r -a PIECES <<< $ITEM INDEX=${PIECES[0]} TITLE=${PIECES[1]} DESC=${PIECES[2]} TYPE=${PIECES[3]} [ "${TYPE}" == "dialog" ] && DESC="${DESC} >>" MENU_ARRAY+=(${INDEX} "${TITLE} - ${DESC}") done export CHOICE=$("${DIALOG[@]}" "${MENU_ARRAY[@]}" 2>&1 >/dev/tty) unset MENU_ARRAY } # # MENU # DLG_MENU() { local IFS=$'\n' local TITLE="$1" MENU_ARRAY=$2 local MENU_H=$3 local MENU_BLURB=$4 local MENU_DESC="${IPADDMSGNO}${MENU_BLURB}" DIALOG=(dialog \ --backtitle "${APPNAME}" \ --title "${APPNAME} ${TITLE} Menu" \ --clear \ --no-shadow \ --menu "$MENU_DESC" ${MW} ${MH} ${MENU_H}) export CHOICE=$("${DIALOG[@]}" "${MENU_ARRAY[@]}" 2>&1 >/dev/tty) unset MENU_ARRAY } # # YES/NO # DLG_YN() { local IFS=$'\n' local TITLE="$1" local MENU_BLURB=$2 local MENU_DESC="${IPADDMSGNO}${MENU_BLURB}" DIALOG=(dialog \ --backtitle "${APPNAME}" \ --title "${APPNAME} ${TITLE} Menu" \ --clear \ --no-shadow \ --defaultno \ --yesno "${MENU_DESC}" ${MW} ${MH}) "${DIALOG[@]}" 2>&1 >/dev/tty export CHOICE=$? } # # DIRECTORY SELECTOR # DLG_DSELECT() { local IFS=$'\n' local TITLE="$1" local MENU_BLURB=$2 local MENU_DESC="${IPADDMSGNO}${MENU_BLURB}" DIALOG=(dialog \ --backtitle "${APPNAME}" \ --title "${APPNAME} ${TITLE} Menu" \ --clear \ --no-shadow \ --dselect "${MENU_BLURB}" ${MW} ${MH}) export CHOICE=$("${DIALOG[@]}" 2>&1 >/dev/tty) } # # INPUTBOX SELECTOR # DLG_INPUTBOX() { local IFS=$'\n' local TITLE="$1" local MENU_BLURB=$2 local MENU_INIT=$3 local MENU_DESC="${IPADDMSGNO}${MENU_BLURB}" DIALOG=(dialog \ --backtitle "${APPNAME}" \ --title "${APPNAME} ${TITLE} Menu" \ --clear \ --no-shadow \ --inputbox "${MENU_BLURB}" ${MW} ${MH} $MENU_INIT) export CHOICE=$("${DIALOG[@]}" 2>&1 >/dev/tty) } # # PASSWORD INPUT # DLG_PASSWORD() { local IFS=$'\n' local TITLE="$1" MENU_ARRAY=$2 local MENU_H=$3 local MENU_BLURB=$4 local MENU_DESC="${IPADDMSGNO}${MENU_BLURB}" DIALOG=(dialog \ --backtitle "${APPNAME}" \ --title "${APPNAME} ${TITLE} Menu" \ --clear \ --no-shadow \ --insecure \ --passwordform "\n$MENU_DESC" ${MW} ${MH} ${MENU_H}) export CHOICE=($("${DIALOG[@]}" "${MENU_ARRAY[@]}" 2>&1 >/dev/tty)) unset MENU_ARRAY } # # FORM INPUT # DLG_FORM() { local IFS=$'\n' local TITLE="$1" MENU_ARRAY=$2 local MENU_H=$3 local MENU_BLURB=$4 local MENU_DESC="${IPADDMSGNO}${MENU_BLURB}" DIALOG=(dialog \ --backtitle "${APPNAME}" \ --title "${APPNAME} ${TITLE} Menu" \ --clear \ --no-shadow \ --form "\n$MENU_DESC" ${MW} ${MH} ${MENU_H}) export CHOICE=($("${DIALOG[@]}" "${MENU_ARRAY[@]}" 2>&1 >/dev/tty)) unset MENU_ARRAY } set +u ================================================ FILE: lib/markup_runner.sh ================================================ #!/bin/bash set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG PBIN=/usr/bin/pandoc LBIN=/usr/bin/lynx INPUT=${1} if [ ! -f ${RNDOC}/${INPUT} ] then #echo "Documentation has not been installed, will display README.md" INPUT="${RNDIR}/README.md" else INPUT="${RNDOC}/${INPUT}" fi ${PBIN} "${INPUT}" | ${LBIN} -stdin ================================================ FILE: lib/script_runner.sh ================================================ #!/bin/bash # # SCRIPTrunner # # This is called by the cockpit webui to run scripts, it should only ever run # scripts from the scripts directory and should sanitize the input # #set -u -x _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh PREFIX= SUFFIX=.sh KEY="${1}" VALUE="${2:-}" X_SANITIZE=1 # check for static type TYPE=${KEY::2} SCRIPT=${KEY:2} case ${TYPE} in s-) # STATIC SCDIR="${SCDIR}/static" ;; m-) # MODAL SCDIR="${DIDIR}" ;; i-) # DIALOG (input) SCDIR="${DIDIR}" SCRIPT="d_input" X_SANITIZE=0 VALUE=${KEY:2} ;; d-) # DIALOGS (auto run) SCDIR="${DIDIR}" SCRIPT="d_menu" X_SANITIZE=0 VALUE=${KEY:2} ;; f-) # FORMS SCDIR="${DIDIR}" PARTS=($(echo "${KEY}" | sed 's/\// /g')) SCRIPT=${PARTS[0]:2} X_SANITIZE=0 VALUE="${PARTS[1]}" ;; y-) # DIALOGS (yes/no) SCDIR="${DIDIR}" SCRIPT="d_yn" X_SANITIZE=0 VALUE=${KEY:2} ;; *) # EVERYTHING ELSE SCRIPT="${KEY}" ;; esac ## make this better, its a hail mary anyway since the script is called from client-side SANITIZED=$(echo "${SCRIPT}" | sed 's/[;]//g') ## ADDITIONAL if [ $X_SANITIZE -eq 1 ] then SANITIZED=$(echo "${SCRIPT}" | sed 's/[\.]//g') fi # build script name SCRIPT="${PREFIX}${SANITIZED}${SUFFIX}" cd "${SCDIR}" [ -z "${1}" ] && echo "No options passed" && exit 1 [ ! -f ${SCRIPT} ] && echo "Failed to find script for ${SCRIPT}" && PAUSE && exit 1 [ -z ${SCDIR} ] && echo "SCDIR cannot be empty, something is terribly wrong" && exit 2 shift # this can be abused, find a better option bash ${SCDIR}/${SCRIPT} ${VALUE} $* 2>&1 ================================================ FILE: retronas.sh ================================================ #!/bin/bash # ansible 2.14 workaround export LC_ALL=${LANG} _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh DISABLE_GITOPS=0 CF="$ANCFG" TCHOICE="" # # CHECK we are running as ROOT # CHECK_ROOT _usage() { echo "Usage $0" echo "-h this help" echo "-d show disclaimer" echo "-g disable git operations" echo "-l show license" echo "-t terminal choice (current|vterm)" echo "-v run in vt100 mode" echo "-a ask for terminal selection at statup" exit 0 } OPTSTRING="hdgvat:" while getopts $OPTSTRING ARG do case $ARG in h) _usage ;; g) DISABLE_GITOPS=1 ;; t) TCHOICE=${"":-OPTARG} ;; v) TCHOICE=vt100 ;; a) TICHOICE="ASK" ;; d) # redisplay agreement [ -f $AGREEMENT ] && rm -f $AGREEMENT ;; l) # display license cat $RNDIR/LICENSE ;; *) _usage ;; esac done #### DO NOT TOUCH THE SYSTEM UNTIL USER AGREES TO DISCLAIMER if [ ! -f $AGREEMENT ] then bash $DIDIR/disclaimer.sh [ $? -ne 0 ] && echo "User did not accept terms of use, exiting" && EXIT_CANCEL fi ### ANSIBLE_VARS cd $RNDIR [ ! -f "${ANCFG}" ] && cp "${ANCFG}.default" "${ANCFG}" # # MIGRATIONS # bash ${PCHDIR}/git-config.sh bash ${PCHDIR}/install-jq.sh bash ${PCHDIR}/update-retronas_vars.sh bash ${PCHDIR}/new-startup-file.sh bash ${PCHDIR}/cache-dir.sh # # END MIGRATIONS # ### source the config to update vars on first run source $_CONFIG ### LANG UTF-8 patch (this probably needs more testing) export LANG=$(echo $LANG | sed -r 's/(\.| )UTF(-?)8//gi') ### DIALOG display patch for NCURSES UTF-8, might cause other issues with other tools export NCURSES_NO_UTF8_ACS=1 ### Manage install through git if [ $DISABLE_GITOPS -eq 0 ] && [ ! -f ${USER_CONFIG}/disable_gitops ] && [ -f ${RNDIR}/.git/config ] then echo "Fetching latest RetroNAS scripts..." git config pull.rebase false git reset --hard HEAD git pull if [ -f "${RNDOC}/Ideas.md" ] then echo "Updating local documentation..." cd $RNDOC git pull cd - fi else echo "Skipping git updates, git operations were disabled" fi ### Make sure log dir exists [ ! -d $LOGDIR ] && mkdir $LOGDIR && chmod 755 $LOGDIR ### Set term emulation, RNSECONDS=3 if [ "${TICHOICE}" == "ASK" ] then CLEAR echo echo "Terminal encoding:" echo echo "1) Current - ${TERM} (default in 3s)" echo "2) vt100 (best for telnet and retro computers)" echo read -r $TCHOICE -t 5 -n 1 -p "Please choose: " fi case "${TCHOICE}" in VT100|vt100|2*) echo "Setting TERM to vt100" export TERM=vt100 ;; *) echo "Leaving TERM as ${TERM}" ;; esac ### Start RetroNAS echo "Running RetroNAS..." cd $DIDIR ### check default user exists if ! id $OLDRNUSER &>/dev/null then echo -e "The currently configured USER $OLDRNUSER does not exist on this system you will now be prompted to update the config" PAUSE bash d_input.sh update-user fi ### check default group exists if ! getent group $OLDRNGROUP &>/dev/null then echo -e "The currently configured GROUP $OLDRNGROUP does not exist on this system you will now be prompted to update the config" PAUSE bash -c d_input.sh update-group fi bash d_menu.sh main ================================================ FILE: scripts/maint/git-changes-summary.sh ================================================ #!/bin/bash # # Helper script to build a basic change log for pull requests # has to be a better way to do this - sairuk # MAIN=$(git log origin/main --oneline -n1 --pretty="format:%h") COMMIT=$(git log --oneline --pretty="format:%h" | grep -B1 $MAIN | head -n1) TESTING=$(git log origin/testing --oneline -n1 --pretty="format:%h") git log --oneline --pretty="format:* %s [%an]" --ancestry-path ${COMMIT}..${TESTING} git log --oneline --pretty="format:* %s [%an]" ${COMMIT} -n1 ================================================ FILE: scripts/maint/install-profile.py ================================================ #!/usr/bin/env python3 import os import json import argparse import subprocess from configparser import ConfigParser rn_dir = "/opt/retronas" rn_ansible_runner = os.path.join(rn_dir, "lib/ansible_runner.sh") rn_section = "package" def ini2dict(profile): if os.path.exists(profile): config= ConfigParser() config.read(profile) return config else: print("Couldn't read from profile: %s" % profile) return None def ansible_run(profile): p = subprocess.Popen([rn_ansible_runner, profile]) p.wait() return def main(args): config = ini2dict(args.profile) if config is not None: if rn_section in config.keys(): for item in config[rn_section]: ansible_run(item) else: print("Incompatible profile, could not find %s entry" % rn_section) return if __name__ == "__main__": parser = argparse.ArgumentParser(description='replay installation profile') parser.add_argument('--profile', help='profile name to replay', type=str, required=True) args = parser.parse_args() main(args) ================================================ FILE: scripts/maint/migrate_romdirs.py ================================================ #!/usr/bin/env python3 # # hacky little script to see if the yaml # to migrate directories based on last entry # in retronas_systems # import yaml import argparse import os import shutil RN_VARS="../../ansible/retronas_vars.yml" RN_SYSTEMS="../../ansible/retronas_systems.yml" RN_IGNORE = [ "system_map", "system_links", "system_template", "system_unsupported", "system_idsoftware", "system_tools" ] RN_ROMDIR='roms' def _log(s, level=0): log_level = "INFO" if level >= 1: log_level = "WARN" elif level >= 2: log_level = "ERRR" print("[%s] %s" % (log_level, s)) def read_yaml(ydata): with open(ydata,'r') as file: try: return yaml.safe_load(file) except yaml.YAMLError as e: _log(e) return None def process_dir(dirname, tree=[]): # loop over the old dir files _log("Building entries for %s" % dirname) dir_contents = os.listdir(dirname) for entry in dir_contents: path = os.path.join(dirname, entry) if os.path.isdir(path): process_dir(path, tree) else: tree.append(path) path = None return tree def main(args): yaml_data = None if not os.path.exists(RN_VARS): _log("vars file not found did you start retronas yet?", 2) exit(1) rn_vars = read_yaml(RN_VARS) rn_path = rn_vars['retronas_path'] rn_systems = read_yaml(RN_SYSTEMS) if rn_systems is not None: for manufacturer in rn_systems: if manufacturer not in RN_IGNORE: for system in rn_systems[manufacturer]: if system['last'] != "": entries = [] # yes our dest here is the src key dest = os.path.join(rn_path,RN_ROMDIR,system['src']) # last location of this system last = os.path.join(rn_path,RN_ROMDIR,system['last']) move = False move_files = False if os.path.exists(last) and os.path.isdir(last): # parent directory parent = os.path.dirname(dest) if not os.path.isdir(parent): _log("Creating parent directory: %s" % parent) os.makedirs(parent) # if dest is a symlink remove it if os.path.islink(dest): _log("Destination is a symlink, removing: %s" % dest) os.remove(dest) move = True # move if dest isn't a dir if not os.path.isdir(dest): _log("Dest %s, doesn't exist, this is good we can move to this location" % dest) move = True else: _log("Can't move %s, already exists: %s, already migrated? (try --file-mode?)" % (last, dest), 1) if args.file_mode: _log("We are in file-mode so flagging to move files instead for %s" % last) move_files = True move = False # if dest is a file cancel dont move if os.path.isfile(dest): _log("%s is a file, check and remove this manually" % dest, 1) move = False # dir mode if move and not move_files: try: _log("Moving %s to %s (file-mode not needed)" % (last, dest)) shutil.move(last, dest) except: _log("Move failed for %s" % (last), 1) else: _log("Flagged for no dir-mode move: %s" % last) # file mode ... though shutil.move was going to cover this but OK. if not move and move_files: _log("We are in file-mode") _log("We will be COPYING found files and confirm they are preset in %s before removing it from %s" % (dest, last)) # loop over the old dir files entries = process_dir(last, []) _log("Found %d file(s) for %s" % ( len(entries), last)) for entry in entries: # dirs last_dirname = os.path.dirname(entry) dest_dirname = os.path.dirname(entry).replace(last, dest) if not os.path.exists(dest_dirname): _log("Creating directory %s" % dest_dirname ) os.makedirs(dest_dirname) dest_dirname = None # files src_file = entry dest_file = entry.replace(last, dest) if src_file == dest_file: _log("something is wrong, src/dest should not match, exiting", 2) exit(1) # check src filesize for use later src_stat = os.path.getsize(src_file) _log("%s size is %s" % (src_file, src_stat)) # check disk usage if shutil.disk_usage(dest).free <= src_stat: _log("You are out of space on %s, free up space and try try again" % dest, 2) exit(1) else: _log("You have enough free space on %s for %s" % (dest, dest_file)) # copy the file _log("Attempting to COPY file %s to %s" % (src_file, dest_file)) if not os.path.exists(dest_file): shutil.copy2(src_file, dest_file) else: _log("Destination %s already exists, it will be checked against the src file in the next step" % dest_file) if os.path.exists(dest_file): # check dest filesize for use later dest_stat = os.path.getsize(dest_file) _log("%s size is %s" % (dest_file, dest_stat)) # only remove the file if the copy was successful # this way the user will have at least one copy if os.path.exists(dest_file) and os.path.isfile(dest_file) and src_stat == dest_stat: _log("%s exists, is a file and is the correct size, so it is OK to remove the old file" % dest_file) os.remove(src_file) if not os.path.exists(src_file): _log("%s removed successfully from %s" % (src_file, last)) else: _log("%s exists, but does not match %s remove it manually to replace" % (dest, src_file), 2) else: _log("%s does not exist, can't process a file that not there" % src_file, 1) """ # remove the empy src dir if os.path.exists(last_dirname): _log('Trying to remove the old dir %s' % last_dirname) try: os.rmdir(last_dirname) except OSError as e: _log("Directory %s isn't empty yet, going for another round" % last_dirname) if not os.path.exists(last_dirname): _log("%s removed successfully" % last_dirname) """ else: _log("Flagged for no file-mode move: %s" % last) _log("----") else: _log("Not found: %s, do not need to migrate" % last) pass else: pass return if __name__ == "__main__": parser = argparse.ArgumentParser(description='validate retronas_systems.yml') parser.add_argument('--file-mode', help='move the individual files (default is dir-mode)', default=False, const=True, nargs='?', required=False) args = parser.parse_args() main(args) ================================================ FILE: scripts/maint/retronas-systems-manager.py ================================================ #!/usr/bin/env python3 import os import argparse import yaml import copy retronas_systems = "../../ansible/retronas_systems.yml" ignored = ["system_links"] def main(args): with open(retronas_systems, "r") as input: data = yaml.safe_load(input) for key in ignored: data.pop(key) if args.add_new_system or args.add_new_project: if args.add_new_system and args.add_new_system not in data.keys(): new = copy.deepcopy(data["system_template"]) new[0]['pretty_name'] = args.add_new_system data["system_map"].append(new[0]) if args.add_new_project: for key in data.keys(): for entry in data[key]: if not args.add_new_project in entry.keys(): entry[args.add_new_project] = "" print(yaml.dump(data, sort_keys=False, default_flow_style=False)) elif args.check_project: chk_ignored = ["system_links"] for key in data.keys(): for entry in data[key]: if args.check_project not in entry.keys() and key not in chk_ignored: print(f"{args.check_project} not found in {entry['src']} ({key})") print(f"Check for {args.check_project} completed") else: print("Nothing to do, try asking for --help") if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('--add-new-system', type=str, help='process system, add new if not exists') parser.add_argument('--add-new-project', type=str, help='add new project to all systems') parser.add_argument('--check-project', type=str, help='check if project is included in all systems') args = parser.parse_args() main(args) ================================================ FILE: scripts/maint/sort_menu_json.py ================================================ #!/usr/bin/env python3 # # reindex items in a menu # code is fairly jank but will do for now # import os, json, argparse def main(args): tmp = {} input_file = args.input if os.path.exists(input_file): data = None with open(input_file, 'r') as f: data = json.load(f) menu = data["menu"] items = [] # grab items and stick them in a temp dict back = None for item in menu["items"]: if item["title"] != "Back": tmp[item["title"].lower()] = item else: back = item # soft the dict tmp_sorted = sorted(tmp.items() ) tmp_sorted.insert(0, ( "back", back )) for idx, item in enumerate(tmp_sorted): entry = item[1] pidx = str(idx + 1).zfill(2) entry["index"] = pidx items.append(entry) data["menu"]["items"] = items output_data = json.dumps(data) print(output_data) return if __name__ == '__main__': parser = argparse.ArgumentParser() parser.add_argument('--input', type=str, required=True) args = parser.parse_args() main(args) ================================================ FILE: scripts/maint/tests/lint-yaml.sh ================================================ #!/bin/bash PROFILE=${1:-min} if [ ! -x /usr/bin/ansible-lint ] then sudo apt-get install -y ansible-lint fi for i in $(ls /opt/retronas/ansible/*.yml); do echo -n "$i: ";ansible-lint --profile=$PROFILE $i; done ================================================ FILE: scripts/maint/tests/test-retronas-json.py ================================================ #!/usr/bin/env python3 # # # import os import json from random import randint retronas_json = '../../../config/retronas.json' def _log(s): print(s) def main(): if os.path.exists(retronas_json): _log("[START] Starting tests") try: data = None with open(retronas_json, 'r') as f: data = json.load(f) if data is not None: _log(" [TEST] JSON config Version: %s" % data['version']) # menus titles menus = [] for menu in data['dialog']: menus.append(menu) # random item menu = randint(0,len(data['dialog'])-1) _log(" [TEST] Random Menu: \"%s\"" % data['dialog'][menus[menu]]['title']) _log("[RESULT] PASS can process the json data") except json.JSONDecodeError as e: _log("Failed to read json data: %s" % e) else: _log("Failed to find %s" % retronas_json) if __name__ == "__main__": main() ================================================ FILE: scripts/patch/cache-dir.sh ================================================ #!/bin/sh _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG [ ! -d $ACACHEDIR ] && mkdir -p $ACACHEDIR ================================================ FILE: scripts/patch/git-config.sh ================================================ #!/bin/bash touch $HOME/.gitconfig git config list --global | grep -E "safe\.directory=*" &>/dev/null if [ $? -eq 1 ] then git config --global --add safe.directory '*' fi ================================================ FILE: scripts/patch/install-jq.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh # jq, kept here to handle migration to new menu system if [ ! -f /usr/bin/jq ] then CHECK_PACKAGE_CACHE apt-get -y install jq [ $? -ne 0 ] && PAUSE && EXIT_CANCEL fi ================================================ FILE: scripts/patch/new-startup-file.sh ================================================ #!/bin/bash ### Checking for new startup, old installs wont have it if [ ! -x /usr/local/bin/retronas ] then clear #installing a simple starup script cp /opt/retronas/dist/retronas /usr/local/bin/retronas chmod a+x /usr/local/bin/retronas echo -e "We have upgraded your RetroNAS, you can now run the RetroNAS config tool with the following command:\n\nretronas\n\nThis message will appear only once\n" echo "Press enter to continue" read -s fi ================================================ FILE: scripts/patch/update-retronas_vars.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh export ANDCFG=${ANDIR}/retronas_vars.yml.default # check for CR on last line if ! tail -n1 ${ANDCFG} | egrep -l $'\r'\$ then sed -i -e '$a\' ${ANCFG} fi update_config() { local CHECK=$1 local MATCH=$2 local FORCE=$3 local FVAL=$4 if [ -z "${CHECK}" ] then if ! awk "/^${MATCH}/" ${ANCFG} &>/dev/null then # look up defaults if awk "/^${MATCH}/" ${ANDCFG} &>/dev/null then VALUE=$(awk "/^${MATCH}:/{gsub(/\"/,\"\");print \$2}" ${ANDCFG} ) echo "${MATCH}: \"${VALUE}\"" >> ${ANCFG} else echo "Failed to match on $MATCH the default config may be broken" exit 1 fi else if [ $FORCE -ne 0 ] then sed -i "s/${MATCH}:.*/${MATCH}: \"${FVAL}\"/" ${ANCFG} fi fi fi } ETH_DEV=$(ip -4 -br a | awk '/^e[nt]/{print $1}' | head -n1) [ ! -z $ETH_DEV ] && ETH_IP=$(ip -4 -br a show dev $ETH_DEV | awk '!/127/{sub(/\/[0-9].+$/, ""); print $3}' | head -n1) WL_DEV=$(ip -4 -br a | awk '/^wl/{print $1}' | head -n1) [ ! -z $WL_DEV ] && WL_IP=$(ip -4 -br a show dev $WL_DEV | awk '!/127/{sub(/\/[0-9].+$/, ""); print $3}' | head -n1) ######################################################################################################### # |CHECK |MATCH |FORCE |VALUE update_config "${OLDRNGROUP}" "retronas_group" 1 "${OLDRNUSER}" # 2024-05-31 - networking update_config "${OLDRETROIF}" "retronas_net_retro_interface" 0 update_config "${OLDMODERNIF}" "retronas_net_modern_interface" 0 update_config "${OLDRETRODHCP}" "retronas_net_retro_dhcprange" 0 update_config "${OLDRETROROUTER}" "retronas_net_retro_router" 0 update_config "${OLDRETRONTP}" "retronas_net_retro_ntp" 0 update_config "${OLDRETROIP}" "retronas_net_retro_ip" 0 update_config "${OLDRETROSUBNET}" "retronas_net_retro_subnet" 0 update_config "${OLDRETRODNS}" "retronas_net_retro_dns" 0 update_config "${OLDUPDNS1}" "retronas_net_upstream_dns1" 0 update_config "${OLDUPDNS2}" "retronas_net_upstream_dns2" 0 update_config "${OLDWIFIINT}" "retronas_net_wifi_interface" 0 update_config "${OLDWIFISSID}" "retronas_net_wifi_ssid" 0 update_config "${OLDWIFICHANNEL}" "retronas_net_wifi_channel" 0 update_config "${OLDWIFIHWMODE}" "retronas_net_wifi_hwmode" 0 update_config "${OLDWIFICC}" "retronas_net_wifi_countrycode" 0 update_config "${OLDWIFIIP}" "retronas_net_wifi_ip" 0 update_config "${OLDWIFISUBNET}" "retronas_net_wifi_subnet" 0 update_config "${OLDWIFIDHCP}" "retronas_net_wifi_dhcprange" 0 update_config "${OLDWIFIROUTER}" "retronas_net_wifi_router" 0 update_config "${OLDWIFINTP}" "retronas_net_wifi_ntp" 0 update_config "${OLDWIFIDNS}" "retronas_net_wifi_dns" 0 # 2024-06-10 update_config "${OLDW3DSQRIP}" "retronas_net_3dsqr_interface" 0 ================================================ FILE: scripts/static/check-samba-user.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh USERNAME=${OLDRNUSER} # hack to check if the user exists smbpasswd -e $USERNAME &> /dev/null if [ $? -eq 1 ] then # run the smbpasswd config cd /opt/retronas/dialog/ bash retronas_password.sh fi ================================================ FILE: scripts/static/clean-broken-symlinks.sh ================================================ #!/bin/bash set -ue _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh echo "Running Checks" [ $OLDRNPATH == "/" ] && exit 1 [ ! -d $OLDRNPATH ] && echo "Path not found: $OLDRNPATH" && exit 1 echo "Starting scan for path: $OLDRNPATH" find "$OLDRNPATH" -xtype l -exec rm "{}" \; echo "Done" PAUSE ================================================ FILE: scripts/static/get-drives.sh ================================================ #!/bin/bash # Get Available drives SELECT_DRIVE() { PS3="Please select a drive ($1): " DRIVES=("$(grep -E "/dev/(sd|hd)[a-z]+" /proc/mounts | awk '{print $1}') exit") select DRIVE in "${DRIVES[@]}" do [ $DRIVE == "exit" ] && echo "Exiting..." && exit 0 read -p "Are you sure? [y/N]: " ANSWER case $ANSWER in y|Y) [ ! -z "$DRIVE" ] && echo $DRIVE exit ;; *) SELECT_DRIVE $1 ;; esac done } SELECT_DRIVE ================================================ FILE: scripts/static/get-interfaces.sh ================================================ #!/bin/bash ================================================ FILE: scripts/static/git-switch-branch.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh # Get Available branches SELECT_BRANCH() { cd /opt/retronas # remove deleted remote branches from output git fetch --prune origin &> /dev/null PS3="Please select a branch ($OLDRNBRANCH): " select BRANCH in $(git branch --remotes | awk -F'/' '!/HEAD/{print $2}' ) exit do [ $BRANCH == "exit" ] && echo "Exiting..." && exit 0 read -p "Are you sure? [y/N]: " ANSWER case $ANSWER in y|Y) if [ ! -z "$BRANCH" ] then git clean -d -f git reset --hard git checkout $BRANCH 1>/dev/null echo "Changed branched to $BRANCH, please restart RetroNAS (press CTRL-C key combination)" PAUSE fi exit ;; *) SELECT_BRANCH $OLDRNBRANCH ;; esac done } SELECT_BRANCH ================================================ FILE: scripts/static/network-example-presets-standalone.sh ================================================ #!/bin/bash # _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh cat << EOD # standalone option # # retro network is available on both ethernet and wifi intefaces # # a wifi access point is available to connect retro devices # # internet access must be provided through an additional (temporary interface) # | | ingress | ingress +--------------+--------------+ | | | ethernet | retro retro-ap | wifi (eth0) | 10.99.1 10.99.2 | (wlan0) | | | +--------------+--------------+ | ssid: retronas | pass: auto | EOD PAUSE ================================================ FILE: scripts/static/network-example-presets-zoned.sh ================================================ #!/bin/bash # _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh cat << EOD # zoned option # # in this mode the the retro network is available on the ethernet interface # of the pi while access to the modern network in avalable on the wifi interface. # # the retro network is able to access services in its own domain. access to the # main network is provided _out_ of the wifi interface and subsequently the # internet # # firewalld is used to provide isolation between the networks, traffic is # permitted out of the wifi interface. Incoming traffic is permitted through # firewall rulesets | | ingress | egress +--------------+--------------+ | | | ethernet | retro ---+--> modern | wifi (eth0) | 10.99.x | | (wlan0) | | | +--+---+---+---+---+---+---+--+ | | | | | | | p/service | | | | | | | ssh (22/tcp) >--------------+ | | | | | +--------------< samba | | | | | samba (445/tcp) >------------------+ | | | +------------------< dhcp|(m)dns|icmp|ntp | | | cockpit (9090/tcp) >----------------------+ | +----------------------< EOD PAUSE ================================================ FILE: scripts/static/permissions.sh ================================================ #!/bin/bash # # This should mimic the old dialog and let the user select a folder # #set -x set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh PROCSUB=${1:-all} case $PROCSUB in all) PROCDIR="${OLDRNPATH}" ;; *) PROCDIR="${OLDRNPATH}/${PROCSUB}" ;; esac echo "Processing: ${PROCDIR}" sudo chown -Rc ${OLDRNUSER}:${OLDRNGROUP} "${PROCDIR}" sudo chmod -Rc a-st,u+rwX,g+rwX,o+rX "${PROCDIR}" echo "Done, if there was anything to do output will be listed above" ================================================ FILE: scripts/static/run-local-module.sh ================================================ #!/bin/bash # # allow users to run a playbook from their retronas local config dir # this will allow for custom managed options for users atop the available # modules in retronas # set -u RETRONAS_PATH="$(awk -F '"' '/retronas_path/{print $2}' ../../ansible/retronas_vars.yml)" [ -z $RETRONAS_PATH ] && exit 1 MODULE_PATH="${RETRONAS_PATH}/config/modules" [ ! -d $MODULE_PATH ] && exit 1 cd $RETRONAS_PATH/config/modules if [ -f $RETRONAS_PATH/config/modules/main.yml ] then ansible-playbook ./main.yml fi ================================================ FILE: scripts/static/service-samba.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh RN_SYSTEMD_STATUS "smbd" RN_DIRECT_STATUS "smbstatus" "-vv" ================================================ FILE: scripts/static/set-etherdfs-nic.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh NEWINT=${1} if [ ! -z "${NEWINT}" ] then # Delete the old value sudo sed -i '/retronas_etherdfs_interface:/d' "${ANCFG}" # Add the new value and re-source echo "retronas_etherdfs_interface: \"${NEWINT}\"" | sudo tee -a "${ANCFG}" else echo "int can't be null" exit 1 fi ================================================ FILE: scripts/static/set-top-level-dir.sh ================================================ #!/bin/bash -x _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh NEWRNPATH="${1}" [ ! -d "${NEWRNPATH}" ] && echo "Directory does not exist" && exit 1 # Delete the old value sudo sed -i '/retronas_path:/d' "${ANCFG}" # Add the new value and re-source echo "retronas_path: \"${NEWRNPATH}\"" | sudo tee -a "${ANCFG}" ================================================ FILE: scripts/static/update-group.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh CHECK_GROUP_EXISTS() { local NEWRNGROUP=$1 local OLDRNGROUP=$2 } UPDATE_GROUP() { } CHECK_GROUP $NEWRNGROUP $OLDRNGROUP ================================================ FILE: scripts/static/update-passwd.sh ================================================ #!/bin/bash set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh USERNAME=${OLDRNUSER} PASSWD="${1}" [ -z "$PASSWD" ] && echo "No password supplied, exiting" && PAUSE && EXIT_CANCEL # SYSTEM echo "Updating system password for $USERNAME" echo -e "${PASSWD}\n${PASSWD}" | sudo passwd $USERNAME 2>/dev/null # SAMBA SMB_SYSTEMD=$(systemctl show smbd.service --full --property FragmentPath --value) if [ ! -z "${SMB_SYSTEMD}" ] && [ -f "${SMB_SYSTEMD}" ] then echo "Updating Samba password for $USERNAME" echo -e "${PASSWD}\n${PASSWD}" | sudo smbpasswd -s -a $USERNAME 2>/dev/null fi # ATALK ATALK_SYSTEMD=$(systemctl show atalkd.service --full --property FragmentPath --value) if [ ! -z "${ATALK_SYSTEMD}" ] && [ -f "${ATALK_SYSTEMD}" ] then ATALKDIR=/opt/retronas/bin/netatalk2x echo "Updating AppleTalk password for $USERNAME" if [ -f ${ATALKDIR}/etc/netatalk/afppasswd ] then touch ${ATALKDIR}/etc/netatalk/afppasswd sudo ${ATALKDIR}/bin/afpexpect.sh -a "${USERNAME}" "${PASSWD}" 2>/dev/null else echo "Appears you are using Netatalk 4 or above, password not managed here" fi fi # X11VNC X11VNC=$(which x11vnc) if [ ! -z "${X11VNC}" ] then echo "Updating X11VNC password for $USERNAME" sudo $X11VNC -storepasswd "${PASSWD}" /etc/vncpasswd_retronas sudo -u $USERNAME $X11VNC -storepasswd "${PASSWD}" /home/$USERNAME/vncpasswd_retronas fi # RASCSI if [ -f /opt/retronas/bin/RASCSI/rascsi ] then echo "Updating RASCSI password for $USERNAME" RASCSI_PASSWD=/etc/rascsi_passwd touch ${RASCSI_PASSWD} chmod 600 ${RASCSI_PASSWD} echo -e "${PASSWD}" | sudo tee ${RASCSI_PASSWD} fi # HTPASSWD (MD5 Apache) HTPASSWD=/etc/retronas.htpasswd if [ -f $HTPASSWD ] then echo "Updating htpasswd password for $USERNAME" sed -i "/^${USERNAME}:.*/d" $HTPASSWD echo -e "${USERNAME}:$(openssl passwd -apr1 $PASSWD)" >> $HTPASSWD fi ================================================ FILE: scripts/static/update-retronas.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG cd ${RNDIR} git config pull.rebase false git reset --hard HEAD git pull ================================================ FILE: scripts/static/update-system-history.sh ================================================ #!/bin/bash set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh source /etc/os-release CHECK_ROOT case $ID in debian|ubuntu) more /var/log/apt/history.log PAUSE ;; *) echo "Unsupported OS type $ID" PAUSE EXIT_CANCEL ;; esac ================================================ FILE: scripts/static/update-system.sh ================================================ #!/bin/bash set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh source /etc/os-release CHECK_ROOT case $ID in debian|ubuntu) apt-get update apt-get -y upgrade apt-get -y dist-upgrade apt-get -y autoremove PAUSE ;; *) echo "Unsupported OS type $ID" PAUSE EXIT_CANCEL ;; esac ================================================ FILE: scripts/static/update-username.sh ================================================ #!/bin/bash _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh CHECK_USER_EXISTS() { local NEWRNUSER=$1 local OLDRNUSER=$2 } UPDATE_USERNAME() { } CHECK_USERNAME $NEWRNUSER $OLDRNUSER ================================================ FILE: scripts/static/wifi-show-passwd.sh ================================================ #!/bin/bash set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh #HOSTAPD_CONF=/etc/hostapd/hostapd-retronas.conf #if [ -f "${HOSTAPD_CONF}" ] #then # CLEAR # PASS="$(sed -rn 's/^wpa_passphrase=(.*)/\1/p' HOSTAPD_CONF)" # SSID="$(sed -rn 's/^ssid=(.*)/\1/p' $NMWIFIAP_CONF)" # echo "SSID: $SSID PASS:$PASS" #fi NMWIFIAP_CONF=/etc/NetworkManager/system-connections/wifi-retronas.nmconnection if [ -f "${NMWIFIAP_CONF}" ] then CLEAR nmcli device wifi show-password else echo "Wireless AP is not installed" fi PAUSE ================================================ FILE: scripts/static/wifi-update-passwd.sh ================================================ #!/bin/bash set -u _CONFIG=/opt/retronas/config/retronas.cfg source $_CONFIG source ${LIBDIR}/common.sh PASSWD="${1}" [ -z "$PASSWD" ] && echo "No password supplied, exiting" && PAUSE && EXIT_CANCEL #HOSTAPD_CONF=/etc/hostapd/hostapd-retronas.conf #if [ -f "${HOSTAPD_CONF}" ] #then # sed -ri "/^wpa_passphrase=/d" $HOSTAPD_CONF 2>/dev/null # if sed "wpa_passphrase=${PASSWD}" >> $HOSTAPD_CONF # 2>/dev/null # then # echo "wifi password updated successfully" # fi #else # echo "Config file not found, assuming hostapd is not installed" #fi NMWIFIAP_CONF=/etc/NetworkManager/system-connections/wifi-retronas.conf if [ -f "${NMWIFIAP_CONF}" ] then if nmcli connection modify wifi-retronas wifi-sec.psk "${PASSWD}" then echo "Password updated successfully" fi else echo "Wireless AP is not installed" fi