feat: Add jupiter-hw-support-bazzite spec that lacks drive handling scripts.

chore: Initial add of drive handling scripts from jupiter-hw-support package to our repo.
This commit is contained in:
Kyle Gospodnetich 2023-07-07 22:15:11 -07:00 committed by RJ Trujillo
parent 2c68978bd4
commit 6f6f1dbca5
3 changed files with 441 additions and 0 deletions

View File

@ -0,0 +1,108 @@
%define packagename jupiter-hw-support
Name: %{packagename}-bazzite
Version: {{{ git_dir_version }}}
Release: 1%{?dist}
Summary: Steam Deck Hardware Support Package
License: GPLv3
URL: https://github.com/ublue-os/bazzite
Source: https://gitlab.com/evlaV/%{packagename}/-/archive/master/%{packagename}-master.tar.gz
Patch0: fedora.patch
Requires: python3
Requires: python3-libevdev
Requires: python3-crcmod
Requires: python3-click
Requires: python3-progressbar2
Requires: python3-hid
Requires: hidapi
Requires: dmidecode
Requires: jq
Requires: alsa-utils
Requires: parted
Requires: e2fsprogs
BuildRequires: systemd-rpm-macros
%description
SteamOS 3.0 Steam Deck Hardware Support Package
# Disable debug packages
%define debug_package %{nil}
%prep
%setup -n %{packagename}-master
%patch 0 -p1
%build
%install
export QA_RPATHS=0x0003
mkdir -p %{buildroot}%{_datadir}/
mkdir -p %{buildroot}%{_unitdir}/
mkdir -p %{buildroot}%{_bindir}/
mkdir -p %{buildroot}%{_sysconfdir}/
cp -rv usr/share/* %{buildroot}%{_datadir}
cp -rv usr/lib/systemd/system/* %{buildroot}%{_unitdir}/
cp -rv usr/lib/hwsupport %{buildroot}%{_prefix}/lib/hwsupport
cp -rv usr/lib/udev %{buildroot}%{_prefix}/lib/udev
cp -rv usr/bin/* %{buildroot}%{_bindir}
cp -rv usr/lib/systemd/system/* %{buildroot}%{_unitdir}
cp -rv etc/* %{buildroot}%{_sysconfdir}
# Remove unneeded files
rm %{buildroot}%{_sysconfdir}/default/grub-steamos
rm %{buildroot}%{_datadir}/jupiter_bios_updater/h2offt-g
rm %{buildroot}%{_datadir}/jupiter_bios_updater/H2OFFTx64-G.sh
rm -rf %{buildroot}%{_datadir}/jupiter_bios_updater/driver
rm -rf %{buildroot}%{_unitdir}/multi-user.target.wants
rm %{buildroot}%{_prefix}/lib/udev/rules.d/99-steamos-automount.rules
rm %{buildroot}%{_prefix}/lib/hwsupport/format-device.sh
rm %{buildroot}%{_prefix}/lib/hwsupport/steamos-automount.sh
# Do post-installation
%post
%systemd_post jupiter-biosupdate.service
%systemd_post jupiter-controller-update.service
# Do before uninstallation
%preun
%systemd_preun jupiter-biosupdate.service
%systemd_preun jupiter-controller-update.service
# Do after uninstallation
%postun
%systemd_postun_with_restart jupiter-biosupdate.service
%systemd_postun_with_restart jupiter-controller-update.service
# This lists all the files that are included in the rpm package and that
# are going to be installed into target system where the rpm is installed.
%files
%{_sysconfdir}/systemd/system/*
%{_bindir}/amd_system_info
%{_bindir}/foxnet-biosupdate
%{_bindir}/jupiter-biosupdate
%{_bindir}/jupiter-check-support
%{_bindir}/jupiter-controller-update
%{_bindir}/steamos-polkit-helpers/*
%{_bindir}/thumbstick_cal
%{_bindir}/thumbstick_fine_cal
%{_bindir}/trigger_cal
%{_prefix}/lib/hwsupport/*
%{_prefix}/lib/systemd/system/*
%{_prefix}/lib/udev/rules.d/*
%{_datadir}/alsa/ucm2/conf.d/acp5x/*
%{_datadir}/icons/steam/*
%{_datadir}/steamos/steamos.png
%{_datadir}/jupiter_bios/*
%{_datadir}/jupiter_bios_updater/*
%{_datadir}/jupiter_controller_fw_updater/*
%{_datadir}/plymouth/themes/steamos/*
%{_datadir}/polkit-1/actions/org.valve.steamos.policy
%{_datadir}/polkit-1/rules.d/org.valve.steamos.rules
%{_datadir}/steamos/steamos-cursor-config
%{_datadir}/steamos/steamos-cursor.png
# Finally, changes from the latest release of your application are generated from
# your project's Git history. It will be empty until you make first annotated Git tag.
%changelog
{{{ git_dir_changelog }}}

View File

@ -0,0 +1,148 @@
#!/bin/bash
set -e
exec &> >(tee | logger -t steamos-format-device)
RUN_VALIDATION=1
EXTENDED_OPTIONS="nodiscard"
# default owner for the new filesystem
OWNER="1000:1000"
OPTS=$(getopt -l force,skip-validation,full,quick,owner:,device: -n format-device.sh -- "" "$@")
eval set -- "$OPTS"
while true; do
case "$1" in
--force) RUN_VALIDATION=0; shift ;;
--skip-validation) RUN_VALIDATION=0; shift ;;
--full) EXTENDED_OPTIONS="discard"; shift ;;
--quick) EXTENDED_OPTIONS="nodiscard"; shift ;;
--owner) OWNER="$2"; shift 2;;
--device) STORAGE_DEVICE="$2"; shift 2 ;;
--) shift; break ;;
esac
done
if [[ "$#" -gt 0 ]]; then
echo "Unknown option $1"; exit 22
fi
EXTENDED_OPTIONS="$EXTENDED_OPTIONS,root_owner=$OWNER"
# We only support SD/MMC and USB mass-storage devices
case "$STORAGE_DEVICE" in
"")
echo "Usage: $(basename $0) [--force] [--skip-validation] [--full] [--quick] [--owner <uid>:<gid>] --device <device>"
exit 19 #ENODEV
;;
/dev/mmcblk?)
STORAGE_PARTITION="${STORAGE_DEVICE}p1"
;;
/dev/sd?)
STORAGE_PARTITION="${STORAGE_DEVICE}1"
;;
*)
echo "Unknown or unsupported device: $STORAGE_DEVICE"
exit 19 #ENODEV
esac
if [[ ! -e "$STORAGE_DEVICE" ]]; then
exit 19 #ENODEV
fi
# Prevent accidental formatting of system drives
if [[ $(lsblk -d -n -r -o hotplug "$STORAGE_DEVICE") != "1" ]]; then
echo "$STORAGE_DEVICE is not a hotplug device"
exit 19 #ENODEV
fi
STORAGE_PARTBASE="${STORAGE_PARTITION#/dev/}"
systemctl stop steamos-automount@"$STORAGE_PARTBASE".service
# lock file prevents the mount service from re-mounting as it gets triggered by udev rules.
#
# NOTE: Uses a shared lock filename between this and the auto-mount script to ensure we're not double-triggering nor
# automounting while formatting or vice-versa.
MOUNT_LOCK="/var/run/jupiter-automount-${STORAGE_PARTBASE//\/_}.lock"
MOUNT_LOCK_FD=9
exec 9<>"$MOUNT_LOCK"
if ! flock -n "$MOUNT_LOCK_FD"; then
echo "Failed to obtain lock $MOUNT_LOCK, failing"
exit 5
fi
# If any partitions on the device are mounted, unmount them before continuing
# to prevent problems later
for m in $(lsblk -n "$STORAGE_DEVICE" -o MOUNTPOINTS| awk NF | sort -u); do
if ! umount "$m"; then
echo "Failed to unmount filesystem: $m"
exit 32 # EPIPE
fi
done
# Test the sdcard
# Some fake cards advertise a larger size than their actual capacity,
# which can result in data loss or other unexpected behaviour. It is
# best to try to detect these issues as early as possible.
if [[ "$RUN_VALIDATION" != "0" ]]; then
echo "stage=testing"
if ! f3probe --destructive "$STORAGE_DEVICE"; then
# Fake sdcards tend to only behave correctly when formatted as exfat
# The tricks they try to pull fall apart with any other filesystem and
# it renders the card unusuable.
#
# Here we restore the card to exfat so that it can be used with other devices.
# It won't be usable with the deck, and usage of the card will most likely
# result in data loss. We return a special error code so we can surface
# a specific error to the user.
echo "stage=rescuing"
echo "Bad sdcard - rescuing"
for i in {1..3}; do # Give this a couple of tries since it fails sometimes
echo "Create partition table: $i"
dd if=/dev/zero of="$STORAGE_DEVICE" bs=512 count=1024 # see comment in similar statement below
if ! parted --script "$STORAGE_DEVICE" mklabel msdos mkpart primary 0% 100% ; then
echo "Failed to create partition table: $i"
continue # try again
fi
echo "Create exfat filesystem: $i"
sync
if ! mkfs.exfat "$STORAGE_PARTITION"; then
echo "Failed to exfat filesystem: $i"
continue # try again
fi
echo "Successfully restored device"
break
done
# Return a specific error code so the UI can warn the user about this bad device
exit 14 # EFAULT
fi
fi
# Clear out the garbage bits generated by f3probe from the partition table sectors
# Otherwise parted may think we have existing partitions in a bogus state
dd if=/dev/zero of="$STORAGE_DEVICE" bs=512 count=1024
# Format as EXT4 with casefolding for proton compatibility
echo "stage=formatting"
sync
parted --script "$STORAGE_DEVICE" mklabel gpt mkpart primary 0% 100%
sync
mkfs.ext4 -m 0 -O casefold -E "$EXTENDED_OPTIONS" -F "$STORAGE_PARTITION"
sync
udevadm settle
# trigger the mount service
flock -u "$MOUNT_LOCK_FD"
if ! systemctl start steamos-automount@"$STORAGE_PARTBASE".service; then
echo "Failed to start mount service"
journalctl --no-pager --boot=0 -u steamos-automount@"$STORAGE_PARTBASE".service
exit 5
fi
exit 0

View File

@ -0,0 +1,185 @@
#!/bin/bash
set -euo pipefail
# Originally from https://serverfault.com/a/767079
# This script is called from our systemd unit file to mount or unmount
# a USB drive.
usage()
{
echo "Usage: $0 {add|remove} device_name (e.g. sdb1)"
exit 1
}
if [[ $# -ne 2 ]]; then
usage
fi
ACTION=$1
DEVBASE=$2
DEVICE="/dev/${DEVBASE}"
# Shared between this and the auto-mount script to ensure we're not double-triggering nor automounting while formatting
# or vice-versa.
MOUNT_LOCK="/var/run/jupiter-automount-${DEVBASE//\/_}.lock"
# Obtain lock
exec 9<>"$MOUNT_LOCK"
if ! flock -n 9; then
echo "$MOUNT_LOCK is active: ignoring action $ACTION"
# Do not return a success exit code: it could end up putting the service in 'started' state without doing the mount
# work (further start commands will be ignored after that)
exit 1
fi
# Wait N seconds for steam
wait_steam()
{
local i=0
local wait=$1
echo "Waiting up to $wait seconds for steam to load"
while ! pgrep -x steamwebhelper &>/dev/null && (( i++ < wait )); do
sleep 1
done
}
send_steam_url()
{
local command="$1"
local arg="$2"
local encoded=$(urlencode "$arg")
if pgrep -x "steam" > /dev/null; then
# TODO use -ifrunning and check return value - if there was a steam process and it returns -1, the message wasn't sent
# need to retry until either steam process is gone or -ifrunning returns 0, or timeout i guess
systemd-run -M 1000@ --user --collect --wait sh -c "./.steam/root/ubuntu12_32/steam steam://${command}/${encoded@Q}"
echo "Sent URL to steam: steam://${command}/${arg} (steam://${command}/${encoded})"
else
echo "Could not send steam URL steam://${command}/${arg} (steam://${command}/${encoded}) -- steam not running"
fi
}
# From https://gist.github.com/HazCod/da9ec610c3d50ebff7dd5e7cac76de05
urlencode()
{
[ -z "$1" ] || echo -n "$@" | hexdump -v -e '/1 "%02x"' | sed 's/\(..\)/%\1/g'
}
do_mount()
{
# Get info for this drive: $ID_FS_LABEL, and $ID_FS_TYPE
dev_json=$(lsblk -o PATH,LABEL,FSTYPE --json -- "$DEVICE" | jq '.blockdevices[0]')
ID_FS_LABEL=$(jq -r '.label | select(type == "string")' <<< "$dev_json")
ID_FS_TYPE=$(jq -r '.fstype | select(type == "string")' <<< "$dev_json")
# Global mount options
OPTS="rw,noatime"
# File system type specific mount options
#if [[ ${ID_FS_TYPE} == "vfat" ]]; then
# OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
#fi
# We need symlinks for Steam for now, so only automount ext4 as that'll Steam will format right now
if [[ ${ID_FS_TYPE} != "ext4" ]]; then
echo "Error mounting ${DEVICE}: wrong fstype: ${ID_FS_TYPE} - ${dev_json}"
exit 2
fi
# Prior to talking to udisks, we need all udev hooks (we were started by one) to finish, so we know it has knowledge
# of the drive. Our own rule starts us as a service with --no-block, so we can wait for rules to settle here
# safely.
if ! udevadm settle; then
echo "Failed to wait for \`udevadm settle\`"
exit 1
fi
# Ask udisks to auto-mount. This needs a version of udisks that supports the 'as-user' option.
ret=0
reply=$(busctl call --allow-interactive-authorization=false --expect-reply=true --json=short \
org.freedesktop.UDisks2 \
/org/freedesktop/UDisks2/block_devices/"${DEVBASE}" \
org.freedesktop.UDisks2.Filesystem \
Mount 'a{sv}' 3 \
as-user s deck \
auth.no_user_interaction b true \
options s "$OPTS") || ret=$?
if [[ $ret -ne 0 ]]; then
echo "Error mounting ${DEVICE} (status = $ret)"
exit 1
fi
# Expected reply is of the format
# {"type":"s","data":["/run/media/deck/home"]}
mount_point=$(jq -r '.data[0] | select(type == "string")' <<< "$reply" || true)
if [[ -z $mount_point ]]; then
echo "Error when mounting ${DEVICE}: udisks returned success but could not parse reply:"
echo "---"$'\n'"$reply"$'\n'"---"
exit 1
fi
# Create a symlink from /run/media to keep compatibility with apps
# that use the older mount point (for SD cards only).
case "${DEVBASE}" in
mmcblk0p*)
if [[ -z "${ID_FS_LABEL}" ]]; then
old_mount_point="/run/media/${DEVBASE}"
else
old_mount_point="/run/media/${mount_point##*/}"
fi
if [[ ! -d "${old_mount_point}" ]]; then
rm -f -- "${old_mount_point}"
ln -s -- "${mount_point}" "${old_mount_point}"
fi
;;
esac
echo "**** Mounted ${DEVICE} at ${mount_point} ****"
# If Steam is running, notify it
send_steam_url "addlibraryfolder" "${mount_point}"
}
do_unmount()
{
# If Steam is running, notify it
local mount_point=$(findmnt -fno TARGET "${DEVICE}" || true)
if [[ -n $mount_point ]]; then
send_steam_url "removelibraryfolder" "${mount_point}"
# Remove symlink to the mount point that we're unmounting
find /run/media -maxdepth 1 -xdev -type l -lname "${mount_point}" -exec rm -- {} \;
else
# If we don't know the mount point then remove all broken symlinks
find /run/media -maxdepth 1 -xdev -xtype l -exec rm -- {} \;
fi
}
do_retrigger()
{
local mount_point=$(findmnt -fno TARGET "${DEVICE}" || true)
[[ -n $mount_point ]] || return 0
# In retrigger mode, we want to wait a bit for steam as the common pattern is starting in parallel with a retrigger
wait_steam 10
# This is a truly gnarly way to ensure steam is ready for commands.
# TODO literally anything else
sleep 6
send_steam_url "addlibraryfolder" "${mount_point}"
}
case "${ACTION}" in
add)
do_mount
;;
remove)
do_unmount
;;
retrigger)
do_retrigger
;;
*)
usage
;;
esac