Skip to content

Instantly share code, notes, and snippets.

@udance4ever
Last active March 26, 2025 02:41
Show Gist options
  • Save udance4ever/9fbd6f2044e1daac388b875e67c7fd4b to your computer and use it in GitHub Desktop.
Save udance4ever/9fbd6f2044e1daac388b875e67c7fd4b to your computer and use it in GitHub Desktop.
macOS (& Linux) RPCS3 launcher that handles .ps3.squashfs & PSN dev mounts
#!/usr/bin/env python3
import argparse
import os
import atexit
import platform
import re
# boolean: https://stackoverflow.com/a/52403318/9983389
parser = argparse.ArgumentParser()
parser.add_argument("--tmpmount", help='mount in /tmp', default=False, action='store_true')
parser.add_argument("--app", help='specify custom executable')
parser.add_argument("file")
parser.add_argument("--devmount", help='mount in dev_hdd0/game', default=False, action='store_true')
parser.add_argument("--intel", help='use Intel executable', default=False, action='store_true')
args = parser.parse_args()
mount = None
def exit_handler():
if mount:
if os.path.exists(mount):
if os.path.ismount(mount):
print("Unmounting and removing:", mount)
os.system('umount "{}"'.format(mount))
os.rmdir(mount)
atexit.register(exit_handler)
file = args.file
if not os.path.exists(file):
print(file, "not found. Exiting.")
exit(1)
devpath = "/Users/Shared/system/configs/rpcs3/dev_hdd0/game/"
devmount = False
rompath = file
if file.endswith(".squashfs"):
(mount, ext) = os.path.splitext(file)
# https://stackoverflow.com/a/8569258/9983389
serial = None
m = re.search(r"\[hdd0,([A-Za-z0-9_]+)\]", mount)
if m:
serial = m.group(1)
print("Found serial:", serial)
# $$ hack to redirect mount to dev_hdd0/game if "[hdd0,<serial>]" in filename
if args.devmount or serial:
devmount = True
if devmount:
if not serial:
print("no serial in filename to mount in dev_hdd0/game. Exiting")
exit(1)
mount = devpath + serial
# https://stackoverflow.com/a/2113511/9983389
if (not os.access(os.path.dirname(os.path.realpath(mount)), os.W_OK)) or args.tmpmount:
mount = "/tmp/ps3Launch.{}.ps3".format(os.getpid())
print("Using mount:", mount)
if not os.path.exists(mount):
os.mkdir(mount)
elif os.path.ismount(mount):
print("unmounting:", mount)
os.system("umount '{}'".format(mount))
cmd = '/usr/local/bin/squashfuse "{}" "{}"'.format(file, mount)
print("cmd:", cmd)
status = os.system(cmd)
if status != 0:
print("Failed to mount:", file)
exit(1)
# https://learnpython.com/blog/python-if-in-one-line/
r = "r" if os.access(mount, os.R_OK) else "-"
w = "w" if os.access(mount, os.W_OK) else "-"
x = "x" if os.access(mount, os.X_OK) else "-"
print("permissions: {}{}{}".format(r,w,x))
if not os.access(mount, os.R_OK | os.X_OK):
print("Mounted file system inaccessible ({}{}{}):".format(r,w,x), mount)
print(" You may need to run `mksquashfs source FILESYSTEM -all-root`")
exit(1)
# override
rompath = mount
# ---
if rompath.endswith(".psn"):
handle = open(rompath, "r")
serial = handle.read()
rompath = devpath + serial.rstrip()
elif not rompath.endswith(".ps3") and not devmount:
print(rompath, "not .ps3 folder. Exiting.")
exit(1)
app = None
if args.app:
app = args.app
elif platform.uname().system == "Linux":
app = '/mnt/dev/bin/rpcs3'
else:
if args.intel:
app = '/Applications/#emu/RPCS3 (Intel).app/Contents/MacOS/rpcs3'
else:
app = '/Applications/#emu/RPCS3.app/Contents/MacOS/rpcs3'
if not os.path.exists(app):
print("app '{}' does not exist. Exiting.".format(app))
exit(1)
cmd = '"{}" --no-gui "{}"'.format(app, rompath)
# ---
print("cmd:", cmd)
status = os.system(cmd)
if status != 0:
print("{} failed to exit cleanly (status={})".format(cmd.split()[0], status))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment