Compare commits
51 Commits
69ca3a957c
...
testing
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
185d098bdd | ||
|
|
140a1c8f88 | ||
|
|
695b9e2f75 | ||
|
|
acf8327949 | ||
|
|
08123ea6e9 | ||
|
|
db6a4880b3 | ||
|
|
1a36316cfd | ||
|
|
ccec75c4c5 | ||
|
|
d8056278d2 | ||
|
|
3d62262849 | ||
|
|
fbd1c3f671 | ||
|
|
f4e91f7ee2 | ||
|
|
3f2dc0b492 | ||
|
|
aceda3f1f8 | ||
|
|
013b3d11ac | ||
|
|
dfd2609461 | ||
|
|
b4704295ec | ||
|
|
855be1afcd | ||
|
|
3df5017766 | ||
|
|
34f1e24e10 | ||
|
|
3176d951b6 | ||
|
|
370d351887 | ||
|
|
c31612ca51 | ||
|
|
1964121c8c | ||
|
|
68cbe3c0bb | ||
|
|
a7e28c018f | ||
|
|
3c5490ea24 | ||
|
|
fffe426d29 | ||
|
|
45b3c230e1 | ||
|
|
fa9585a0e1 | ||
|
|
5e144e7955 | ||
|
|
e39c1cedec | ||
|
|
8a7fb83be3 | ||
|
|
f80ea1e056 | ||
|
|
696ddd9bfb | ||
|
|
e0806e51da | ||
|
|
3612787274 | ||
|
|
41a0592f20 | ||
|
|
3ebb6f36cf | ||
|
|
c88bd17709 | ||
|
|
c1af07bf18 | ||
|
|
a88a386ef4 | ||
|
|
034c561a53 | ||
|
|
2108f02719 | ||
|
|
06282f5ea8 | ||
|
|
6bb5267b91 | ||
|
|
b87647756f | ||
|
|
505028ab44 | ||
|
|
9657719613 | ||
|
|
3e4c4d18ee | ||
|
|
9beea608ed |
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
AGENTS.md
|
||||
CLAUDE.md
|
||||
*.qcow2
|
||||
*.img
|
||||
*.sha1sum
|
||||
*.xz
|
||||
*.zst
|
||||
96
pi4/build/README.md
Normal file
96
pi4/build/README.md
Normal file
@@ -0,0 +1,96 @@
|
||||
# Stormux Pi Image Builder
|
||||
|
||||
Stormux provides an Arch-based Raspberry Pi image that already includes Fenrir, Orca, and other screen-reader friendly defaults. This repository hosts the scripts maintained by the Stormux community (originally crafted by Storm) so anyone can rebuild the image, customize the overlay, and share accessible Pi spins.
|
||||
|
||||
## Purpose & Scope
|
||||
This repo captures the complete build pipeline for the Stormux Raspberry Pi images: downloading Arch Linux ARM, layering the accessible defaults, compiling Fenrir and helper tools, and producing a ready-to-flash `.img`. Running the script yourself lets you reproduce the same system the project ships for the Pi 4/400, tweak it, and publish new spins without reverse-engineering the original release.
|
||||
|
||||
## What You Need
|
||||
- A 64-bit Arch Linux host (bare metal or VM) with at least 20 GB free disk space.
|
||||
- Root access on that host. The builder partitions loopback devices and must run as root.
|
||||
- Required packages: `arch-install-scripts`, `dosfstools`, `parted`, `wget`, `qemu-user-static`, `qemu-user-static-binfmt`, plus standard developer tools that Arch already ships.
|
||||
- A Raspberry Pi 4/400 or similar board (a Pi 3 works with the `-v 32` option) and a microSD card (8 GB or larger recommended).
|
||||
|
||||
Install dependencies on the build host with:
|
||||
```bash
|
||||
sudo pacman -S arch-install-scripts dosfstools parted wget qemu-user-static qemu-user-static-binfmt
|
||||
```
|
||||
|
||||
## Getting the Source
|
||||
Clone the canonical repo (or your fork) someplace with plenty of space:
|
||||
```bash
|
||||
git clone https://git.stormux.org/storm/stormux.git
|
||||
cd stormux
|
||||
```
|
||||
All build logic lives in `pi4/`. The `pi4/files/` tree mirrors the root filesystem you want inside the image (configs in `etc`, helper scripts in `usr/local/bin`, and so on).
|
||||
|
||||
### Where to Run the Builder
|
||||
The script is designed for an x86_64 Arch host so it can emulate ARM binaries with QEMU while building. You can run it natively on an ARM board (including a Pi) running Arch or Stormux, but expect much longer build times and make sure the same packages are installed. Whatever the CPU, you **must** run as root and ensure `/mnt` is free so the loopback rootfs can mount safely.
|
||||
|
||||
## Building Your First Image
|
||||
1. Become root (`sudo -i`) so the script can create loop devices and mount them.
|
||||
2. From `/path/to/stormux`, run:
|
||||
```bash
|
||||
sudo ./pi4/build/build-stormux.sh -v 64 -l en_US -s 6
|
||||
```
|
||||
- `-v 64` builds the aarch64 image (use `-v 32` for the Pi 3/armv7h).
|
||||
- `-l en_US` selects the locale (use `es_ES`, `fr_FR`, etc.).
|
||||
- `-s 6` sets the image size in gigabytes.
|
||||
- Add `-n my-stormux.img` to override the default filename.
|
||||
3. Grab coffee. The script downloads the latest Arch Linux ARM tarball, provisions packages (Fenrir, Orca, NetworkManager, PipeWire, etc.), copies the overlay from `pi4/files/`, and cleans up.
|
||||
4. When the `build-stormux.sh` command returns, you should have an `.img` file in your working directory (for example `stormux-pi4-aarch64-YYYY-MM-DD.img`).
|
||||
|
||||
If the build is interrupted, run `sudo umount -R /mnt && sudo losetup -D` to be sure nothing is still mounted.
|
||||
|
||||
## Customizing the Image
|
||||
- **Overlay files**: Add or edit files in `pi4/files/` using the same paths they should have inside the Pi. Example: to add a custom MOTD, edit `pi4/files/etc/motd`.
|
||||
- **Packages**: Edit the package list inside `pi4/build/build-stormux.sh` (search for `pacman -Su --needed`). Add or remove entries as needed, then rebuild.
|
||||
- **AUR components**: The script already compiles Fenrir (`fenrir-git`), `growpartfs`, `log2ram`, and `yay`. To add more AUR packages, append them to the `aurPackages` array near the middle of the script.
|
||||
- **First-boot behavior**: Modify `pi4/files/usr/local/bin/configure-stormux` to change the guided setup that runs when the image boots the first time.
|
||||
|
||||
Remember to keep permissions sensible (`chmod 755` for scripts, `644` for configs) so rsync copies them correctly.
|
||||
|
||||
## Keeping Up with Upstream Updates
|
||||
Storm and other contributors actively improve these scripts. To sync your local clone with the latest changes:
|
||||
```bash
|
||||
cd /path/to/stormux
|
||||
git pull --ff-only
|
||||
```
|
||||
Rebuild after pulling so your custom image inherits any upstream fixes (new packages, service tweaks, security patches). If you maintain your own fork, merge or rebase onto the upstream `main` branch before publishing updated images.
|
||||
|
||||
## Flashing and Booting
|
||||
1. Verify the image:
|
||||
```bash
|
||||
ls -lh stormux-pi4-*.img
|
||||
```
|
||||
2. Write it to an SD card (replace `/dev/sdX` with your card, not a partition):
|
||||
```bash
|
||||
sudo dd if=stormux-pi4-aarch64-*.img of=/dev/sdX bs=4M status=progress conv=fsync
|
||||
```
|
||||
3. Insert the card into your Pi 4/400 and power it on. You should hear Fenrir start speaking once the user session loads.
|
||||
4. Log in using the default credentials (username `stormux`, password `stormux`). Root uses `root`/`root` until you change it.
|
||||
5. Run `sudo configure-stormux` (or follow the automatic prompt) to finish the guided setup: configure networking via `nmtui`, update the clock, optionally resize the SD card with `growpartfs`, and toggle Fenrir’s layout.
|
||||
|
||||
## Testing Without Hardware
|
||||
You can boot the image in a container to verify services before flashing:
|
||||
```bash
|
||||
sudo systemd-nspawn -i stormux-pi4-aarch64-*.img --boot
|
||||
```
|
||||
Use `machinectl` to connect to the console and ensure critical services start. For unit files you edit, run `systemd-analyze verify path/to/unit` inside the container or the Pi.
|
||||
|
||||
## Troubleshooting Tips
|
||||
- **Locale or package errors**: Ensure your host’s pacman keyring is up to date (`sudo pacman -Sy archlinux-keyring`).
|
||||
- **Loop device cleanup**: After failures run `sudo losetup -a` to find stray devices, then `sudo losetup -d /dev/loopX`.
|
||||
- **Disk too small**: Increase the `-s` argument or remove packages.
|
||||
- **Accessibility tweaks**: If Fenrir is too quiet or you prefer Orca, install the `orca` package inside the overlay and add it to the autostart configuration in `pi4/files/etc/xdg/autostart/`.
|
||||
|
||||
## Sharing Your Image
|
||||
When you are happy with your customizations:
|
||||
1. Rebuild so you have a clean `.img` file named clearly (for example, `stormux-pi4-a11y-v1.img`).
|
||||
2. Compress it (`xz -T0 -z stormux-pi4-a11y-v1.img`).
|
||||
3. Publish the image along with the exact commit you built from and any extra scripts you used. The README and `AGENTS.md` in this repo explain the layout so others can reproduce your work.
|
||||
|
||||
## Huge Thanks to Storm
|
||||
Storm did the heavy lifting—curating packages, wiring up Fenrir/Orca defaults, scripting the first-boot assistant, and sharing the whole build process so the community can remix it. This repo exists because accessibility was treated as a first-class feature from day one, and the documentation lets anyone extend that work. If the image improves your Pi experience, consider contributing improvements or telling Storm thanks.
|
||||
|
||||
With these steps you can take the same base image Storm released, tweak it to your needs, and ship a fully accessible Arch image for other Pi fans. Happy hacking!
|
||||
@@ -25,16 +25,25 @@ set -e # Don't want to destroy stuff if this goes majorly wrong.
|
||||
trap cleanup EXIT # make sure the script cleans up after itself before closing.
|
||||
|
||||
|
||||
# shellcheck disable=SC2329 # cleanup is invoked via trap EXIT
|
||||
cleanup() {
|
||||
status=$? # capture original exit status so failures propagate
|
||||
|
||||
if [[ $mounted -eq 0 ]]; then
|
||||
umount -R /mnt
|
||||
partx -d "${loopdev}"
|
||||
losetup --detach "${loopdev}"
|
||||
umount -R /mnt || true
|
||||
fi
|
||||
if [[ -n "${imageFileName}" ]]; then
|
||||
rm "${imageFileName}"
|
||||
|
||||
if [[ -n "${loopdev:-}" ]]; then
|
||||
partx -d "${loopdev}" || true
|
||||
losetup --detach "${loopdev}" || true
|
||||
fi
|
||||
exit 0
|
||||
|
||||
# Clean up temporary pacman config directory
|
||||
if [[ -n "${tmpDir:-}" && -d "${tmpDir:-}" ]]; then
|
||||
rm -rf "${tmpDir}"
|
||||
fi
|
||||
|
||||
exit "$status"
|
||||
}
|
||||
|
||||
help() {
|
||||
@@ -50,9 +59,8 @@ help() {
|
||||
declare -A command=(
|
||||
[h]="This help screen."
|
||||
[l:]="Language default is en_US."
|
||||
[n:]="Image name, default is stormux-pi<32|64>-<yyyy-mm-dd>.img"
|
||||
[s:]="image size in GB, default is 4."
|
||||
[v:]="Version of the Raspberry Pi for which you are building. (32|64) default is 64."
|
||||
[n:]="Image name, default is stormux-pi4-aarch64-<yyyy-mm-dd>.img"
|
||||
[s:]="image size in GB, default is 6."
|
||||
)
|
||||
|
||||
# Convert the keys of the associative array to a format usable by getopts
|
||||
@@ -75,14 +83,6 @@ while getopts "${args}" i ; do
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
v)
|
||||
if [[ "${OPTARG}" =~ ^32|64$ ]]; then
|
||||
imageVersion="${OPTARG}"
|
||||
else
|
||||
echo "Image version must be 32 for 32 bit (armv7h), or 64 for 64 bit (aarch64 default)."
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
exit 1
|
||||
;;
|
||||
@@ -90,11 +90,8 @@ while getopts "${args}" i ; do
|
||||
done
|
||||
|
||||
# make sure variables are set, or use defaults.
|
||||
export imageVersion="${imageVersion:-64}"
|
||||
export imageSize="${imageSize:-6G}"
|
||||
imageName="${imageName:-stormux-pi4-${imageVersion}-$(date '+%Y-%m-%d').img}"
|
||||
imageName="${imageName/-64-/-aarch64-}"
|
||||
imageName="${imageName/-32-/-armv7h-}"
|
||||
imageName="${imageName:-stormux-pi4-aarch64-$(date '+%Y-%m-%d').img}"
|
||||
export imageName
|
||||
export imageLanguage="${imageLanguage:-en_US.UTF-8}"
|
||||
|
||||
@@ -121,7 +118,7 @@ if [[ "$(uname -m)" == "x86_64" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
for i in arch-install-scripts dosfstools parted wget ; do
|
||||
for i in arch-install-scripts dosfstools parted ; do
|
||||
if ! pacman -Q $i &> /dev/null ; then
|
||||
echo "Please install $i before continuing."
|
||||
exit 1
|
||||
@@ -129,85 +126,190 @@ for i in arch-install-scripts dosfstools parted wget ; do
|
||||
done
|
||||
|
||||
|
||||
# Url for the image to be downloaded.
|
||||
url[32]="http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-armv7-latest.tar.gz"
|
||||
url[64]="http://os.archlinuxarm.org/os/ArchLinuxARM-rpi-aarch64-latest.tar.gz"
|
||||
|
||||
fallocate -l "$imageSize" "$imageName"
|
||||
loopdev="$(losetup --find --show "${imageName}")"
|
||||
parted --script "${loopdev}" mklabel msdos mkpart primary fat32 0% 200M mkpart primary ext4 200M 100%
|
||||
mkfs.vfat -F32 "${loopdev}p1"
|
||||
mkfs.ext4 -F "${loopdev}p2"
|
||||
parted --script "${loopdev}" mklabel msdos mkpart primary fat32 0% 512M mkpart primary ext4 512M 100%
|
||||
mkfs.vfat -F32 -n STRMX_BOOT "${loopdev}p1"
|
||||
mkfs.ext4 -F -L STRMX_ROOT "${loopdev}p2"
|
||||
mount "${loopdev}p2" /mnt
|
||||
mkdir /mnt/boot
|
||||
mount "${loopdev}p1" /mnt/boot
|
||||
# Things are mounted now, so set mounted to 0 (bash true)
|
||||
mounted=0
|
||||
imageFileName=$(mktemp)
|
||||
wget "${url[$imageVersion]}" -O "${imageFileName}"
|
||||
if [[ $imageVersion -eq 32 ]]; then
|
||||
# Workaround for bsdtar errors when extracting 32 bit image.
|
||||
set +e
|
||||
fi
|
||||
bsdtar -xpf "${imageFileName}" -C /mnt
|
||||
# Set -e in case it got unset for 32 bit image
|
||||
set -e
|
||||
arch-chroot /mnt << EOF
|
||||
|
||||
# Set up temporary pacman configuration for ARM bootstrap
|
||||
echo "Setting up pacman configuration for aarch64..."
|
||||
tmpDir=$(mktemp -d)
|
||||
mkdir -p "${tmpDir}/pacman.d"
|
||||
|
||||
# Create mirrorlist for Arch Linux ARM
|
||||
cat > "${tmpDir}/pacman.d/mirrorlist" << 'MIRRORLIST'
|
||||
Server = http://mirror.archlinuxarm.org/$arch/$repo
|
||||
Server = http://fl.us.mirror.archlinuxarm.org/$arch/$repo
|
||||
Server = http://il.us.mirror.archlinuxarm.org/$arch/$repo
|
||||
Server = http://tx.us.mirror.archlinuxarm.org/$arch/$repo
|
||||
Server = http://nj.us.mirror.archlinuxarm.org/$arch/$repo
|
||||
MIRRORLIST
|
||||
|
||||
# Create pacman.conf for ARM
|
||||
cat > "${tmpDir}/pacman.conf" << PACMANCONF
|
||||
[options]
|
||||
HoldPkg = pacman glibc
|
||||
Architecture = aarch64
|
||||
CheckSpace
|
||||
SigLevel = Never
|
||||
LocalFileSigLevel = Never
|
||||
|
||||
[core]
|
||||
Include = ${tmpDir}/pacman.d/mirrorlist
|
||||
|
||||
[extra]
|
||||
Include = ${tmpDir}/pacman.d/mirrorlist
|
||||
|
||||
[alarm]
|
||||
Include = ${tmpDir}/pacman.d/mirrorlist
|
||||
PACMANCONF
|
||||
|
||||
# Bootstrap the system with pacstrap
|
||||
echo "Running pacstrap to install base system..."
|
||||
pacstrap -c -G -M -C "${tmpDir}/pacman.conf" /mnt base base-devel linux-rpi raspberrypi-bootloader firmware-raspberrypi archlinuxarm-keyring
|
||||
|
||||
# Clean up temporary config
|
||||
rm -rf "${tmpDir}"
|
||||
|
||||
# Copy override files into place before chroot (except skel to avoid conflicts)
|
||||
cp -rv ../files/boot/* /mnt/boot
|
||||
cp -rv ../files/var/* /mnt/var
|
||||
cp -rv ../files/usr/* /mnt/usr
|
||||
# Copy etc files but exclude skel directory to avoid package conflicts
|
||||
find ../files/etc -mindepth 1 -maxdepth 1 ! -name skel -exec cp -rv {} /mnt/etc/ \;
|
||||
|
||||
PS1="(Chroot) [\u@\h \W] \$" arch-chroot /mnt << EOF
|
||||
echo "Chroot started."
|
||||
set -euo pipefail
|
||||
# Disable pacman sandboxing (doesn't work in chroot)
|
||||
sed -i '/^\[options\]/a DisableSandbox' /etc/pacman.conf
|
||||
# set up pacman
|
||||
pacman-key --init
|
||||
pacman-key --populate archlinuxarm
|
||||
pacman -Syy
|
||||
# Change kernels for aarch64
|
||||
if [[ "$imageVersion" == "64" ]]; then
|
||||
pacman -R --noconfirm linux-aarch64 uboot-raspberrypi
|
||||
pacman -S --noconfirm linux-rpi
|
||||
|
||||
# Add stormux repository
|
||||
echo "Downloading stormux repository key..."
|
||||
curl -s https://packages.stormux.org/stormux_repo.pub > /tmp/stormux_repo.pub
|
||||
echo "Adding key to pacman keyring..."
|
||||
pacman-key --add /tmp/stormux_repo.pub
|
||||
echo "Locally signing key..."
|
||||
pacman-key --lsign-key 52ADA49000F1FF0456F8AEEFB4CDE1CD56EF8E82
|
||||
rm /tmp/stormux_repo.pub
|
||||
# Add repository before core in pacman.conf
|
||||
sed -i '/^\[core\]/i[stormux]\nSigLevel = Required DatabaseOptional\nServer = https://packages.stormux.org/\$arch\n' /etc/pacman.conf
|
||||
|
||||
# Test mirrors and configure based on responsiveness
|
||||
echo "Testing mirror responsiveness..."
|
||||
mirrors=(
|
||||
"mirror.archlinuxarm.org"
|
||||
"fl.us.mirror.archlinuxarm.org"
|
||||
"il.us.mirror.archlinuxarm.org"
|
||||
"tx.us.mirror.archlinuxarm.org"
|
||||
"nj.us.mirror.archlinuxarm.org"
|
||||
)
|
||||
|
||||
working_mirrors=()
|
||||
for mirror in "\${mirrors[@]}"; do
|
||||
echo "Testing \$mirror..."
|
||||
if curl -m 5 -f -s "http://\$mirror/aarch64/core/core.db" > /dev/null 2>&1; then
|
||||
echo " \$mirror: OK"
|
||||
working_mirrors+=("\$mirror")
|
||||
else
|
||||
echo " \$mirror: FAILED"
|
||||
fi
|
||||
done
|
||||
|
||||
# Create mirrorlist with working mirrors first, then fallback to all mirrors
|
||||
> /etc/pacman.d/mirrorlist
|
||||
if [[ \${#working_mirrors[@]} -gt 0 ]]; then
|
||||
echo "Using \${#working_mirrors[@]} working mirrors"
|
||||
for mirror in "\${working_mirrors[@]}"; do
|
||||
echo "Server = http://\$mirror/\\\$arch/\\\$repo" >> /etc/pacman.d/mirrorlist
|
||||
done
|
||||
else
|
||||
echo "No mirrors responded, using all mirrors as fallback"
|
||||
for mirror in "\${mirrors[@]}"; do
|
||||
echo "Server = http://\$mirror/\\\$arch/\\\$repo" >> /etc/pacman.d/mirrorlist
|
||||
done
|
||||
fi
|
||||
|
||||
# Install packages
|
||||
pacman -Su --needed --noconfirm \
|
||||
alsa-firmware \
|
||||
alsa-utils \
|
||||
base \
|
||||
base-devel \
|
||||
bash-completion \
|
||||
bluez \
|
||||
bluez-utils \
|
||||
brltty \
|
||||
cloud-utils \
|
||||
cronie \
|
||||
espeak-ng \
|
||||
fake-hwclock \
|
||||
firmware-raspberrypi \
|
||||
git \
|
||||
go \
|
||||
magic-wormhole \
|
||||
man \
|
||||
man-pages \
|
||||
networkmanager \
|
||||
pipewire \
|
||||
pipewire-alsa \
|
||||
pipewire-jack \
|
||||
pipewire-pulse \
|
||||
poppler \
|
||||
python-pyudev \
|
||||
python-daemonize \
|
||||
python-evdev \
|
||||
python-dbus \
|
||||
python-pyenchant \
|
||||
python-pyte \
|
||||
raspberrypi-utils \
|
||||
realtime-privileges \
|
||||
rhvoice-voice-bdl \
|
||||
rng-tools \
|
||||
rsync \
|
||||
screen \
|
||||
sox \
|
||||
w3m \
|
||||
wget \
|
||||
wireless-regdb \
|
||||
wireplumber \
|
||||
xdg-user-dirs \
|
||||
pacman -Syy
|
||||
|
||||
# Install all packages (stormux repo has priority since it's listed first)
|
||||
packages=(
|
||||
alsa-firmware
|
||||
alsa-utils
|
||||
base
|
||||
base-devel
|
||||
bash-completion
|
||||
bluez
|
||||
bluez-utils
|
||||
brltty
|
||||
cronie
|
||||
dialog
|
||||
espeak-ng
|
||||
fake-hwclock
|
||||
fenrir
|
||||
firmware-raspberrypi
|
||||
linux-firmware
|
||||
git
|
||||
gstreamer
|
||||
gst-plugins-base
|
||||
gst-plugins-good
|
||||
ii
|
||||
magic-wormhole
|
||||
man
|
||||
man-pages
|
||||
networkmanager
|
||||
openssh
|
||||
parted
|
||||
pipewire
|
||||
pipewire-alsa
|
||||
pipewire-jack
|
||||
pipewire-pulse
|
||||
poppler
|
||||
python-dbus
|
||||
python-gobject
|
||||
python-pyenchant
|
||||
python-pyte
|
||||
python-pyperclip
|
||||
raspberrypi-utils
|
||||
socat
|
||||
realtime-privileges
|
||||
rhvoice-voice-bdl
|
||||
rng-tools
|
||||
rsync
|
||||
screen
|
||||
sox
|
||||
w3m-git
|
||||
wget
|
||||
wireless-regdb
|
||||
wireplumber
|
||||
vi
|
||||
xdg-user-dirs
|
||||
xdg-utils
|
||||
yay
|
||||
)
|
||||
|
||||
pacman -Su --needed --noconfirm "\${packages[@]}"
|
||||
|
||||
# Fix mkinitcpio preset for linux-rpi - kms hook fails on aarch64
|
||||
# See: https://archlinuxarm.org/forum/viewtopic.php?t=16672
|
||||
if [[ -f /etc/mkinitcpio.d/linux-rpi.preset ]]; then
|
||||
echo "Configuring mkinitcpio preset to skip kms hook..."
|
||||
sed -i "s/^default_options=.*/default_options=\"--skiphook kms\"/" /etc/mkinitcpio.d/linux-rpi.preset
|
||||
sed -i "s/^fallback_options=.*/fallback_options=\"-S autodetect --skiphook kms\"/" /etc/mkinitcpio.d/linux-rpi.preset
|
||||
fi
|
||||
|
||||
# Regenerate initramfs with the corrected settings
|
||||
echo "Regenerating initramfs..."
|
||||
mkinitcpio -P
|
||||
|
||||
# Restart gpg agents.
|
||||
gpgconf --kill all
|
||||
@@ -221,43 +323,22 @@ systemctl enable rngd.service
|
||||
# Set the distribution name.
|
||||
echo 'Stormux \r (\l)' > /etc/issue
|
||||
echo >> /etc/issue
|
||||
# Change the alarm user to be stormux
|
||||
usermod -a -g users -G wheel,realtime,audio,video,network,brlapi -m -d /home/stormux -l stormux alarm
|
||||
# Create the stormux user
|
||||
useradd -m -g users -G wheel,realtime,audio,video,network,brlapi -s /bin/bash stormux
|
||||
# Grant sudo privileges to the stormux user for package installation.
|
||||
echo 'stormux ALL=(ALL) NOPASSWD: ALL' >> /etc/sudoers.d/wheel
|
||||
# Set the password for the root user
|
||||
echo -e "root\nroot" | passwd "root"
|
||||
# Set the password for the stormux user
|
||||
echo -e "stormux\nstormux" | passwd "stormux"
|
||||
# Change to the stormux user and install some packages
|
||||
|
||||
# Change to the stormux user for user configuration
|
||||
sudo -iu stormux
|
||||
# suppress git spam about default branch name
|
||||
git config --global init.defaultBranch master
|
||||
# Create desktop, downloads, music, and other directories.
|
||||
xdg-user-dirs-update
|
||||
# Build AUR packages
|
||||
export aurPackages=(fenrir \
|
||||
growpartfs \
|
||||
log2ram \
|
||||
python-pythondialog \
|
||||
yay)
|
||||
export PKGDEST=~/packages
|
||||
for p in "\${aurPackages[@]}" ; do
|
||||
git clone https://aur.archlinux.org/\${p}.git
|
||||
cd ~/\${p}
|
||||
if [[ "\${p}" == "python-pythondialog" ]]; then
|
||||
gpg --import keys/pgp/*.asc
|
||||
fi
|
||||
makepkg -A
|
||||
cd ~
|
||||
rm -rf \${p}
|
||||
done
|
||||
exit
|
||||
# Install built packages
|
||||
for p in /home/stormux/packages/* ; do
|
||||
pacman -U --noconfirm \${p}
|
||||
done
|
||||
rm -rf /home/stormux/packages/
|
||||
# Enable linger so that hopefully sound will start at login.
|
||||
mkdir -p /var/lib/systemd/linger
|
||||
touch /var/lib/systemd/linger/stormux
|
||||
@@ -270,21 +351,41 @@ echo '%wheel ALL=(ALL) ALL' > /etc/sudoers.d/wheel
|
||||
echo stormux > /etc/hostname
|
||||
# Configure services
|
||||
systemctl disable systemd-networkd.service systemd-networkd.socket
|
||||
systemctl enable brltty.path cronie.service fake-hwclock.service fenrirscreenreader.service log2ram.service NetworkManager.service
|
||||
# Cleanup packages
|
||||
pacman -Sc --noconfirm
|
||||
pacman -R --noconfirm go
|
||||
# Enable services
|
||||
services=(
|
||||
brltty.path
|
||||
cronie.service
|
||||
fake-hwclock.service
|
||||
fenrirscreenreader.service
|
||||
log-to-ram-setup.service
|
||||
log-to-ram-sync.timer
|
||||
log-to-ram-shutdown.service
|
||||
NetworkManager.service
|
||||
sshd.service
|
||||
ssh-login-monitor.service
|
||||
)
|
||||
|
||||
for service in "\${services[@]}"; do
|
||||
echo "Enabling \$service..."
|
||||
if systemctl enable "\$service"; then
|
||||
echo " \$service: OK"
|
||||
else
|
||||
echo " \$service: FAILED"
|
||||
fi
|
||||
done
|
||||
|
||||
pacman -Sc --noconfirm
|
||||
|
||||
# Re-enable pacman sandboxing for the final image
|
||||
sed -i '/^DisableSandbox/d' /etc/pacman.conf
|
||||
|
||||
# Update fstab for Raspberry Pi 4. Not needed until linux-aarch64 works.
|
||||
# [[ $imageVersion -eq 4 ]] && sed -i 's/mmcblk0/mmcblk1/g' /etc/fstab
|
||||
EOF
|
||||
|
||||
# Copy override files into place.
|
||||
cp -rv ../files/boot/* /mnt/boot
|
||||
cp -rv ../files/etc/* /mnt/etc
|
||||
cp -rv ../files/var/* /mnt/var
|
||||
cp -rv ../files/usr/* /mnt/usr
|
||||
# Copy skel files to stormux user home (after user rename in chroot)
|
||||
find ../files/etc/skel/ -mindepth 1 -exec cp -rv "{}" /mnt/home/stormux/ \;
|
||||
|
||||
# Copy boot files again to ensure custom config overrides any package changes
|
||||
cp -rv ../files/boot/* /mnt/boot
|
||||
|
||||
# Exiting calls the cleanup function to unmount.
|
||||
exit 0
|
||||
|
||||
198
pi4/build/chroot-image.sh
Executable file
198
pi4/build/chroot-image.sh
Executable file
@@ -0,0 +1,198 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
# Copyright 2025, Stormux, <storm_dragon@stormux.org>
|
||||
#
|
||||
# This is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the GNU General Public License as published by the Free
|
||||
# Software Foundation; either version 3, or (at your option) any later
|
||||
# version.
|
||||
#
|
||||
# This software is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this package; see the file COPYING. If not, write to the Free
|
||||
# Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
# 02110-1301, USA.
|
||||
#
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
mountedPoints=()
|
||||
loopDev=""
|
||||
mountRoot=""
|
||||
rootPart=""
|
||||
bootPart=""
|
||||
imagePath=""
|
||||
|
||||
cleanup() {
|
||||
statusCode=$?
|
||||
set +e
|
||||
|
||||
if [[ ${#mountedPoints[@]} -gt 0 ]]; then
|
||||
for ((index=${#mountedPoints[@]}-1; index>=0; index--)); do
|
||||
if mountpoint -q "${mountedPoints[$index]}"; then
|
||||
umount "${mountedPoints[$index]}" || true
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [[ -n "${mountRoot}" && -d "${mountRoot}" && "${mountRoot}" != "/mnt" ]]; then
|
||||
rmdir "${mountRoot}" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
if [[ -n "${loopDev}" ]]; then
|
||||
partx -d "${loopDev}" 2>/dev/null || true
|
||||
losetup --detach "${loopDev}" 2>/dev/null || true
|
||||
fi
|
||||
|
||||
exit "$statusCode"
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
die() {
|
||||
echo "Error: $*" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
help() {
|
||||
echo "Usage: $0 <image-file>"
|
||||
echo "Mounts a Stormux image, chroots into it, and cleans up on exit."
|
||||
exit 0
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1"
|
||||
}
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
help
|
||||
fi
|
||||
|
||||
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
|
||||
help
|
||||
fi
|
||||
|
||||
imagePath="$(readlink -f "$1" 2>/dev/null || true)"
|
||||
if [[ -z "${imagePath}" ]]; then
|
||||
die "Unable to resolve image path: $1"
|
||||
fi
|
||||
if [[ ! -f "${imagePath}" ]]; then
|
||||
die "Image file not found: ${imagePath}"
|
||||
fi
|
||||
|
||||
if [[ "$(whoami)" != "root" ]]; then
|
||||
die "This script must be run as root."
|
||||
fi
|
||||
|
||||
if command -v pacman >/dev/null 2>&1; then
|
||||
for packageName in arch-install-scripts util-linux; do
|
||||
if ! pacman -Q "$packageName" &>/dev/null; then
|
||||
die "Please install ${packageName} before continuing."
|
||||
fi
|
||||
done
|
||||
else
|
||||
require_cmd arch-chroot
|
||||
require_cmd losetup
|
||||
require_cmd partx
|
||||
require_cmd lsblk
|
||||
require_cmd mount
|
||||
require_cmd umount
|
||||
require_cmd findmnt
|
||||
require_cmd mountpoint
|
||||
fi
|
||||
|
||||
if [[ "$(uname -m)" == "x86_64" ]]; then
|
||||
if command -v pacman >/dev/null 2>&1; then
|
||||
if ! pacman -Q qemu-user-static &>/dev/null; then
|
||||
die "Please install qemu-user-static and qemu-user-static-binfmt before continuing."
|
||||
fi
|
||||
if ! pacman -Q qemu-user-static-binfmt &>/dev/null; then
|
||||
die "Please install qemu-user-static and qemu-user-static-binfmt before continuing."
|
||||
fi
|
||||
else
|
||||
require_cmd qemu-aarch64-static
|
||||
fi
|
||||
fi
|
||||
|
||||
require_cmd arch-chroot
|
||||
require_cmd losetup
|
||||
require_cmd partx
|
||||
require_cmd lsblk
|
||||
require_cmd mount
|
||||
require_cmd umount
|
||||
require_cmd findmnt
|
||||
require_cmd mountpoint
|
||||
|
||||
baseMountDir="/mnt"
|
||||
if [[ ! -d "${baseMountDir}" || ! -w "${baseMountDir}" ]]; then
|
||||
die "/mnt is missing or not writable. Please create or fix permissions."
|
||||
fi
|
||||
|
||||
if mountpoint -q "${baseMountDir}"; then
|
||||
if [[ -t 0 ]]; then
|
||||
echo "/mnt is already mounted. Unmount it to continue? [y/N]"
|
||||
read -r answerText
|
||||
case "${answerText}" in
|
||||
y|Y|yes|YES)
|
||||
umount "${baseMountDir}" || die "Failed to unmount /mnt"
|
||||
;;
|
||||
*)
|
||||
die "Refusing to proceed while /mnt is mounted."
|
||||
;;
|
||||
esac
|
||||
else
|
||||
die "/mnt is already mounted. Refusing to proceed in non-interactive mode."
|
||||
fi
|
||||
fi
|
||||
|
||||
mountRoot="${baseMountDir}"
|
||||
|
||||
loopDev="$(losetup --find --show --partscan "${imagePath}")"
|
||||
partx -u "${loopDev}" >/dev/null 2>&1 || true
|
||||
|
||||
declare -a rootCandidates=()
|
||||
declare -a bootCandidates=()
|
||||
|
||||
while read -r deviceName fsType nodeType; do
|
||||
if [[ "${nodeType}" != "part" ]]; then
|
||||
continue
|
||||
fi
|
||||
case "${fsType}" in
|
||||
ext4|ext3|ext2)
|
||||
rootCandidates+=("${deviceName}")
|
||||
;;
|
||||
vfat|fat|fat32|fat16)
|
||||
bootCandidates+=("${deviceName}")
|
||||
;;
|
||||
esac
|
||||
done < <(lsblk -nrpo NAME,FSTYPE,TYPE "${loopDev}")
|
||||
|
||||
if [[ ${#rootCandidates[@]} -gt 0 ]]; then
|
||||
rootPart="${rootCandidates[0]}"
|
||||
elif [[ -b "${loopDev}p2" ]]; then
|
||||
rootPart="${loopDev}p2"
|
||||
else
|
||||
die "Unable to locate root partition inside ${imagePath}"
|
||||
fi
|
||||
|
||||
if [[ ${#bootCandidates[@]} -gt 0 ]]; then
|
||||
bootPart="${bootCandidates[0]}"
|
||||
elif [[ -b "${loopDev}p1" ]]; then
|
||||
bootPart="${loopDev}p1"
|
||||
fi
|
||||
|
||||
mount "${rootPart}" "${mountRoot}"
|
||||
mountedPoints+=("${mountRoot}")
|
||||
|
||||
if [[ -n "${bootPart}" ]]; then
|
||||
mkdir -p "${mountRoot}/boot"
|
||||
mount "${bootPart}" "${mountRoot}/boot"
|
||||
mountedPoints+=("${mountRoot}/boot")
|
||||
fi
|
||||
|
||||
echo "Mounted image at ${mountRoot}. Entering chroot..."
|
||||
PS1="(Chroot) [\\u@\\h \\W] \\$ " arch-chroot "${mountRoot}"
|
||||
1
pi4/files/boot/cmdline.txt
Normal file
1
pi4/files/boot/cmdline.txt
Normal file
@@ -0,0 +1 @@
|
||||
root=LABEL=STRMX_ROOT rw rootwait console=serial0,115200 console=tty1 fsck.repair=yes
|
||||
4
pi4/files/etc/RHVoice/dicts/English/namefix.txt
Normal file
4
pi4/files/etc/RHVoice/dicts/English/namefix.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
bifrost=buyfraust
|
||||
danestange=dainstanggey
|
||||
stange=stangey
|
||||
kde=kaydeee
|
||||
19
pi4/files/etc/RHVoice/dicts/English/wordfix.txt
Normal file
19
pi4/files/etc/RHVoice/dicts/English/wordfix.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
asus=aysus
|
||||
certificate=cirtifficate
|
||||
douche=doosh*
|
||||
espeak=easpeak*
|
||||
freenginx=freeenginex
|
||||
git=ghit*
|
||||
github=ghittehub
|
||||
gitea=ghittee
|
||||
jolla=yolla
|
||||
jenux=jennux
|
||||
lightnin=lighttnin
|
||||
nginx=enginex
|
||||
rhvoice=ahraychvoice
|
||||
shit=shitt
|
||||
sync=sink*
|
||||
timezone=timezoan
|
||||
vinux=vinnux
|
||||
wench=wentch*
|
||||
youngin=younggin*
|
||||
@@ -1,4 +0,0 @@
|
||||
Section "Device"
|
||||
Identifier "fbdev"
|
||||
Driver "fbdev"
|
||||
EndSection
|
||||
@@ -1,20 +0,0 @@
|
||||
Section "Monitor"
|
||||
Identifier "dummy_monitor"
|
||||
HorizSync 28.0-80.0
|
||||
VertRefresh 48.0-75.0
|
||||
Modeline "1920x1080" 172.80 1920 2040 2248 2576 1080 1081 1084 1118
|
||||
EndSection
|
||||
|
||||
Section "Device"
|
||||
Identifier "dummy_card"
|
||||
VideoRam 256000
|
||||
Driver "dummy"
|
||||
EndSection
|
||||
|
||||
Section "Screen"
|
||||
Identifier "dummy_screen"
|
||||
Device "dummy_card"
|
||||
Monitor "dummy_monitor"
|
||||
SubSection "Display"
|
||||
EndSubSection
|
||||
EndSection
|
||||
7
pi4/files/etc/fstab
Normal file
7
pi4/files/etc/fstab
Normal file
@@ -0,0 +1,7 @@
|
||||
# Static information about the filesystems.
|
||||
# See fstab(5) for details.
|
||||
|
||||
# <file system> <dir> <type> <options> <dump> <pass>
|
||||
LABEL=STRMX_BOOT /boot vfat defaults 0 1
|
||||
LABEL=STRMX_ROOT / ext4 defaults,noatime 0 1
|
||||
tmpfs /var/log tmpfs defaults,noatime,nosuid,nodev,noexec,mode=0755,size=128M 0 0
|
||||
@@ -1,37 +0,0 @@
|
||||
# Configuration file for Log2Ram (https://github.com/azlux/log2ram) under MIT license.
|
||||
# This configuration file is read by the log2ram service
|
||||
|
||||
# Size for the ram folder, it defines the size the log folder will reserve into the RAM.
|
||||
# If it's not enough, log2ram will not be able to use ram. Check you /var/log size folder.
|
||||
# The default is 40M and is basically enough for a lot of applications.
|
||||
# You will need to increase it if you have a server and a lot of log for example.
|
||||
SIZE=128M
|
||||
|
||||
# This variable can be set to true if you prefer "rsync" rather than "cp".
|
||||
# I use the command cp -u and rsync -X, so I don't copy the all folder every time for optimization.
|
||||
# You can choose which one you want. Be sure rsync is installed if you use it.
|
||||
USE_RSYNC=true
|
||||
|
||||
# If there are some errors with available RAM space, a system mail will be send
|
||||
# Change it to false and you will have only a log if there is no place on RAM anymore.
|
||||
MAIL=false
|
||||
|
||||
# Variable for folders to put in RAM. You need to specify the real folder `/path/folder` , the `/path/hdd.folder` will be automatically created. Multiple path can be separeted by `;`. Do not add the final `/` !
|
||||
# example : PATH_DISK="/var/log;/home/test/FolderInRam"
|
||||
PATH_DISK="/var/log"
|
||||
|
||||
# **************** Zram backing conf *************************************************
|
||||
|
||||
# ZL2R Zram Log 2 Ram enables a zram drive when ZL2R=true ZL2R=false is mem only tmpfs
|
||||
ZL2R=false
|
||||
# COMP_ALG this is any compression algorithm listed in /proc/crypto
|
||||
# lz4 is fastest with lightest load but deflate (zlib) and Zstandard (zstd) give far better compression ratios
|
||||
# lzo is very close to lz4 and may with some binaries have better optimisation
|
||||
# COMP_ALG=lz4 for speed or Zstd for compression, lzo or zlib if optimisation or availabilty is a problem
|
||||
COMP_ALG=lz4
|
||||
# LOG_DISK_SIZE is the uncompressed disk size. Note zram uses about 0.1% of the size of the disk when not in use
|
||||
# LOG_DISK_SIZE is expected compression ratio of alg chosen multiplied by log SIZE
|
||||
# lzo/lz4=2.1:1 compression ratio zlib=2.7:1 zstandard=2.9:1
|
||||
# Really a guestimate of a bit bigger than compression ratio whilst minimising 0.1% mem usage of disk size
|
||||
LOG_DISK_SIZE=100M
|
||||
|
||||
@@ -6,5 +6,5 @@ Welcome to Stormux, powered by Arch Linux ARM
|
||||
Stormux IRC: #stormux on irc.stormux.org
|
||||
Arch Linux ARM IRC: #archlinuxarm on irc.libera.chat
|
||||
|
||||
Thank you Stormux supporters! https://ko-fi.com/stormux/leaderboard
|
||||
Thank you Stormux supporters! https://patreon.com/stormux
|
||||
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
#%PAM-1.0
|
||||
|
||||
auth include system-local-login
|
||||
account include system-local-login
|
||||
password include system-local-login
|
||||
session include system-local-login
|
||||
@@ -12,6 +12,34 @@ if ! [[ -x /usr/local/bin/configure-stormux ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Volume calibration FIRST
|
||||
echo "Setting up audio volume..."
|
||||
volume=50
|
||||
wait=0
|
||||
|
||||
# Wait for pipewire to become available
|
||||
while [[ $wait -lt 30 ]]; do
|
||||
if pgrep pipewire &> /dev/null ; then
|
||||
break
|
||||
else
|
||||
sleep 1
|
||||
((wait++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Volume calibration - this should be the VERY FIRST interactive part
|
||||
while [[ $volume -le 130 ]]; do
|
||||
clear
|
||||
pactl set-sink-volume @DEFAULT_SINK@ "${volume}%" 2>/dev/null
|
||||
spd-say "If this is loud enough, press enter."
|
||||
if read -t4 ; then
|
||||
echo "Volume set to ${volume}%"
|
||||
break
|
||||
else
|
||||
((volume+=5))
|
||||
fi
|
||||
done
|
||||
|
||||
# For audible sudo prompts:
|
||||
unset sudoFlags
|
||||
if [[ -x /etc/audibleprompt.sh ]]; then
|
||||
@@ -19,6 +47,7 @@ if [[ -x /etc/audibleprompt.sh ]]; then
|
||||
export sudoFlags=("-A")
|
||||
fi
|
||||
|
||||
clear
|
||||
cat << "EOF"
|
||||
Hello, and welcome to Stormux!
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
# This file is part of systemd.
|
||||
#
|
||||
# systemd is free software; you can redistribute it and/or modify it under the
|
||||
# terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation; either version 2.1 of the License, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# Entries in this file show the compile time defaults. Local configuration
|
||||
# should be created by either modifying this file, or by creating "drop-ins" in
|
||||
# the journald.conf.d/ subdirectory. The latter is generally recommended.
|
||||
# Defaults can be restored by simply deleting this file and all drop-ins.
|
||||
#
|
||||
# Use 'systemd-analyze cat-config systemd/journald.conf' to display the full config.
|
||||
#
|
||||
# See journald.conf(5) for details.
|
||||
|
||||
[Journal]
|
||||
#Storage=auto
|
||||
#Compress=yes
|
||||
#Seal=yes
|
||||
#SplitMode=uid
|
||||
#SyncIntervalSec=5m
|
||||
#RateLimitIntervalSec=30s
|
||||
#RateLimitBurst=10000
|
||||
SystemMaxUse=20M
|
||||
#SystemKeepFree=
|
||||
#SystemMaxFileSize=
|
||||
#SystemMaxFiles=100
|
||||
#RuntimeMaxUse=
|
||||
#RuntimeKeepFree=
|
||||
#RuntimeMaxFileSize=
|
||||
#RuntimeMaxFiles=100
|
||||
#MaxRetentionSec=
|
||||
#MaxFileSec=1month
|
||||
#ForwardToSyslog=no
|
||||
#ForwardToKMsg=no
|
||||
#ForwardToConsole=no
|
||||
#ForwardToWall=yes
|
||||
#TTYPath=/dev/console
|
||||
#MaxLevelStore=debug
|
||||
#MaxLevelSyslog=debug
|
||||
#MaxLevelKMsg=notice
|
||||
#MaxLevelConsole=info
|
||||
#MaxLevelWall=emerg
|
||||
#LineMax=48K
|
||||
#ReadKMsg=yes
|
||||
#Audit=yes
|
||||
3
pi4/files/etc/systemd/journald.conf.d/99-ramlog.conf
Normal file
3
pi4/files/etc/systemd/journald.conf.d/99-ramlog.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
[Journal]
|
||||
Storage=volatile
|
||||
SystemMaxUse=20M
|
||||
16
pi4/files/etc/systemd/system/log-to-ram-setup.service
Normal file
16
pi4/files/etc/systemd/system/log-to-ram-setup.service
Normal file
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Setup RAM logging and restore logs from disk
|
||||
DefaultDependencies=false
|
||||
After=local-fs.target
|
||||
Before=sysinit.target
|
||||
RequiresMountsFor=/var
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStartPre=/bin/mkdir -p /var/log.hdd
|
||||
ExecStartPre=/bin/sh -c 'if [ -d /var/log.hdd ] && [ "$(ls -A /var/log.hdd 2>/dev/null)" ]; then cp -au /var/log.hdd/* /var/log/ 2>/dev/null || true; fi'
|
||||
ExecStart=/bin/true
|
||||
|
||||
[Install]
|
||||
WantedBy=sysinit.target
|
||||
14
pi4/files/etc/systemd/system/log-to-ram-shutdown.service
Normal file
14
pi4/files/etc/systemd/system/log-to-ram-shutdown.service
Normal file
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Sync logs to disk before shutdown
|
||||
DefaultDependencies=false
|
||||
Before=shutdown.target reboot.target halt.target
|
||||
Conflicts=shutdown.target reboot.target halt.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=true
|
||||
ExecStart=/bin/sh -c 'rsync -aXv --delete --exclude="*.hdd" /var/log/ /var/log.hdd/ 2>/dev/null || true'
|
||||
TimeoutStopSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=shutdown.target reboot.target halt.target
|
||||
8
pi4/files/etc/systemd/system/log-to-ram-sync.service
Normal file
8
pi4/files/etc/systemd/system/log-to-ram-sync.service
Normal file
@@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=Sync logs from RAM to disk
|
||||
After=local-fs.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStartPre=/bin/mkdir -p /var/log.hdd
|
||||
ExecStart=/bin/sh -c 'rsync -aXv --delete --exclude="*.hdd" /var/log/ /var/log.hdd/ 2>/dev/null || true'
|
||||
11
pi4/files/etc/systemd/system/log-to-ram-sync.timer
Normal file
11
pi4/files/etc/systemd/system/log-to-ram-sync.timer
Normal file
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Sync logs from RAM to disk every hour
|
||||
Requires=log-to-ram-sync.service
|
||||
|
||||
[Timer]
|
||||
OnBootSec=15min
|
||||
OnUnitActiveSec=1h
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
17
pi4/files/etc/systemd/system/ssh-login-monitor.service
Normal file
17
pi4/files/etc/systemd/system/ssh-login-monitor.service
Normal file
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Fenrir SSH Login Monitor
|
||||
After=sshd.service
|
||||
Wants=sshd.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/share/fenrirscreenreader/scripts/ssh-login-monitor.sh
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# Security settings
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=false
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
1
pi4/files/etc/udev/rules.d/99-brltty.rules
Normal file
1
pi4/files/etc/udev/rules.d/99-brltty.rules
Normal file
@@ -0,0 +1 @@
|
||||
SUBSYSTEM=="tty", KERNEL=="tty[0-9]*|hvc[0-9]*|sclp_line[0-9]*|ttysclp[0-9]*|3270/tty[0-9]*", GROUP="tty", MODE="0620"
|
||||
3
pi4/files/etc/vconsole.conf
Normal file
3
pi4/files/etc/vconsole.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
# This is the fallback vconsole configuration provided by systemd.
|
||||
|
||||
KEYMAP=us_alt
|
||||
103
pi4/files/root/rename-user.sh
Executable file
103
pi4/files/root/rename-user.sh
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Renames a user
|
||||
# Required arguments: old user name, new user name
|
||||
|
||||
set -e
|
||||
|
||||
question() {
|
||||
echo
|
||||
echo "$@"
|
||||
read -r answer
|
||||
answer="${answer:0:1}"
|
||||
answer="${answer^}"
|
||||
}
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Usage: $0 old-user new-user"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
oldUser="$1"
|
||||
newUser="$2"
|
||||
|
||||
# Make sure old user exists
|
||||
if ! id "$oldUser" >/dev/null 2>&1; then
|
||||
echo "The user $oldUser does not exist."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure old user is not logged in
|
||||
if pgrep -u "$oldUser" >/dev/null; then
|
||||
echo "The user $oldUser is currently logged in or has running processes. Cannot continue."
|
||||
question "Would you like to forcibly log out $oldUser? (Y/N)"
|
||||
if [[ "$answer" != "Y" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
systemctl stop display-manager
|
||||
loginctl terminate-user "$oldUser"
|
||||
sleep 2
|
||||
if pgrep -u "$oldUser" >/dev/null; then
|
||||
echo "The user $oldUser still has running processes after termination. Cannot continue."
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Make sure new user does not exist
|
||||
if id "$newUser" >/dev/null 2>&1; then
|
||||
echo "The user name $newUser is already taken."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Make sure the new name is acceptable
|
||||
if ! [[ "$newUser" =~ ^[a-z_][a-z0-9_-]{0,31}$ ]]; then
|
||||
echo "$newUser is not an acceptable user name."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Passed all safety checks, proceed with the rename
|
||||
echo "Renaming $oldUser to $newUser..."
|
||||
groups=$(id -nG "$oldUser")
|
||||
groups="${groups// /,}"
|
||||
usermod -G "$groups" -m -d "/home/$newUser" -l "$newUser" "$oldUser"
|
||||
|
||||
# Update nodm.conf if it exists
|
||||
if [[ -e /etc/nodm.conf ]]; then
|
||||
echo "Updating /etc/nodm.conf..."
|
||||
sed -i -e "s#^NODM_USER=.*#NODM_USER='$newUser'#" -e "s#^NODM_XSESSION=.*#NODM_XSESSION='/home/$newUser/.xinitrc'#" /etc/nodm.conf
|
||||
fi
|
||||
|
||||
# Copy over crontab if it exists
|
||||
if crontab -u "$oldUser" -l >/tmp/${oldUser}_crontab.bak 2>/dev/null; then
|
||||
echo "Copying over crontab..."
|
||||
if crontab -u "$newUser" "/tmp/${oldUser}_crontab.bak"; then
|
||||
rm "/tmp/${oldUser}_crontab.bak"
|
||||
else
|
||||
echo "Warning: failed to restore crontab for $newUser."
|
||||
rm "/tmp/${oldUser}_crontab.bak"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Update linger
|
||||
if [[ -e "/var/lib/systemd/linger/$oldUser" ]]; then
|
||||
echo "Enabling linger..."
|
||||
mv "/var/lib/systemd/linger/$oldUser" "/var/lib/systemd/linger/$newUser"
|
||||
fi
|
||||
|
||||
# Optionally update files in new home directory
|
||||
echo
|
||||
echo "Would you like to search for references to $oldUser and update them to $newUser in files located in /home/$newUser?"
|
||||
question "This can take a while. (Y/N)"
|
||||
if [[ "$answer" == "Y" ]]; then
|
||||
echo "Updating files..."
|
||||
find "/home/$newUser" -type f -exec grep -Iq . "{}" \; -and -exec sed -i "s|$oldUser|$newUser|g" "{}" \;
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "Rename complete. The user, $newUser, is now available."
|
||||
question "Would you like to reboot?"
|
||||
if [[ "${answer}" == "Y" ]]; then
|
||||
reboot
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -24,6 +24,8 @@ if [[ -x /opt/configure-stormux/configure-stormux.sh ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Volume calibration is now handled in stormux_first_boot.sh
|
||||
|
||||
export DIALOGOPTS='--insecure --no-lines --visit-items'
|
||||
|
||||
set_timezone() {
|
||||
@@ -52,8 +54,6 @@ set_timezone() {
|
||||
ln -sf /usr/share/zoneinfo/${region}/${city} /etc/localtime
|
||||
timedatectl set-ntp true
|
||||
}
|
||||
|
||||
|
||||
# Offer to switch fenrir layout.
|
||||
echo "Would you like to switch Fenrir to laptop layout?"
|
||||
echo "Press y for yes or n for no followed by enter."
|
||||
@@ -75,23 +75,25 @@ if [[ $diskSize -le 7 ]]; then
|
||||
read -r continue
|
||||
continue="${continue::1}"
|
||||
if [[ "${continue,}" == "y" ]];then
|
||||
sudo "${sudoFlags[@]}" growpartfs $diskSource
|
||||
# Extract base device name (handles mmcblk0p2, nvme0n1p2, sda2, etc.)
|
||||
if [[ "$diskSource" =~ (.*[0-9]+)p[0-9]+$ ]]; then
|
||||
# Handle mmcblk0p2, nvme0n1p2 style
|
||||
diskDevice="${BASH_REMATCH[1]}"
|
||||
else
|
||||
# Handle sda2, sdb3 style
|
||||
diskDevice="$(echo "$diskSource" | sed 's/[0-9]*$//')"
|
||||
fi
|
||||
echo "Yes" | sudo "${sudoFlags[@]}" parted ---pretend-input-tty "$diskDevice" resizepart 2 100%
|
||||
sudo "${sudoFlags[@]}" resize2fs -f "$diskSource"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! ping -c1 stormux.org &> /dev/null ; then
|
||||
echo "No internet connection detected. Press enter to open NetworkManager."
|
||||
echo "Note, it is best to put Fenrir into highlight mode while using NetworkManager."
|
||||
echo "In desktop layout this is done by pressing Fenrir+numpad asterisk."
|
||||
echo "That is the key just above numpad 9."
|
||||
echo "In laptop mode, press Fenrir+y."
|
||||
echo "In desktop mode the Fenrir key is numpad insert."
|
||||
echo "In laptop mode the Fenrir key is the Super key, sometimes called the Windows key."
|
||||
echo "After connecting to the internet, remember to go back to cursor mode."
|
||||
echo "It is the same key used to switch to highlight mode."
|
||||
echo "Press enter to continue."
|
||||
read -r continue
|
||||
echo "setting set focus#highlight=True" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
nmtui-connect
|
||||
echo "setting set focus#highlight=False" | socat - UNIX-CLIENT:/tmp/fenrirscreenreader-deamon.sock
|
||||
fi
|
||||
# Check for internet connectivity
|
||||
if ping -qc1 -W 1 stormux.org &> /dev/null; then
|
||||
|
||||
582
pi4/files/usr/local/bin/sas
Executable file
582
pi4/files/usr/local/bin/sas
Executable file
@@ -0,0 +1,582 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import os
|
||||
import re
|
||||
import secrets
|
||||
import signal
|
||||
import string
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
import time
|
||||
import pwd
|
||||
import threading
|
||||
|
||||
|
||||
stormuxAdmin = ("storm",)
|
||||
ircServer = "irc.stormux.org"
|
||||
ircPort = 6667
|
||||
ircChannel = "#stormux"
|
||||
remoteHost = "billysballoons.com"
|
||||
sasUser = "sas"
|
||||
pingIntervalSeconds = 180
|
||||
pingCount = 5
|
||||
maxWormholeFailures = 3
|
||||
|
||||
sudoKeepaliveThread = None
|
||||
sudoKeepaliveStop = threading.Event()
|
||||
|
||||
|
||||
def speak_message(message):
|
||||
try:
|
||||
subprocess.run(["spd-say", message], check=False)
|
||||
except FileNotFoundError:
|
||||
print(message, flush=True)
|
||||
|
||||
|
||||
def say_or_print(message, useSpeech):
|
||||
if useSpeech:
|
||||
speak_message(message)
|
||||
else:
|
||||
print(message, flush=True)
|
||||
|
||||
|
||||
def run_command(command, inputText=None, check=False, env=None):
|
||||
return subprocess.run(
|
||||
command,
|
||||
input=inputText,
|
||||
text=True,
|
||||
capture_output=True,
|
||||
check=check,
|
||||
env=env,
|
||||
)
|
||||
|
||||
|
||||
def ensure_sudo(useSpeech):
|
||||
if os.geteuid() == 0:
|
||||
return True
|
||||
if useSpeech:
|
||||
speak_message("Sudo password required. Please enter your password now.")
|
||||
result = run_command(["sudo", "-v"])
|
||||
if result.returncode == 0:
|
||||
start_sudo_keepalive()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def start_sudo_keepalive():
|
||||
global sudoKeepaliveThread
|
||||
if sudoKeepaliveThread and sudoKeepaliveThread.is_alive():
|
||||
return
|
||||
|
||||
def keepalive_loop():
|
||||
while not sudoKeepaliveStop.wait(240):
|
||||
run_command(["sudo", "-n", "-v"])
|
||||
|
||||
sudoKeepaliveThread = threading.Thread(target=keepalive_loop, daemon=True)
|
||||
sudoKeepaliveThread.start()
|
||||
|
||||
|
||||
def run_privileged(command, useSpeech, inputText=None, check=True):
|
||||
if os.geteuid() == 0:
|
||||
fullCommand = command
|
||||
else:
|
||||
if not ensure_sudo(useSpeech):
|
||||
raise RuntimeError("sudo authentication failed")
|
||||
fullCommand = ["sudo"] + command
|
||||
return run_command(fullCommand, inputText=inputText, check=check)
|
||||
|
||||
|
||||
def run_as_user(userName, command, useSpeech, check=True):
|
||||
if os.geteuid() == 0:
|
||||
fullCommand = ["sudo", "-u", userName, "-H"] + command
|
||||
else:
|
||||
if not ensure_sudo(useSpeech):
|
||||
raise RuntimeError("sudo authentication failed")
|
||||
fullCommand = ["sudo", "-u", userName, "-H"] + command
|
||||
return run_command(fullCommand, check=check)
|
||||
|
||||
|
||||
def user_exists(userName):
|
||||
result = run_command(["getent", "passwd", userName])
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
def ensure_wheel(userName, useSpeech):
|
||||
result = run_command(["id", "-nG", userName])
|
||||
groups = result.stdout.strip().split()
|
||||
if "wheel" not in groups:
|
||||
run_privileged(["usermod", "-a", "-G", "wheel", userName], useSpeech)
|
||||
|
||||
|
||||
def generate_password():
|
||||
allowedChars = string.ascii_letters + string.digits
|
||||
length = secrets.randbelow(5) + 6
|
||||
return "".join(secrets.choice(allowedChars) for _ in range(length))
|
||||
|
||||
|
||||
def get_user_home(userName):
|
||||
return pwd.getpwnam(userName).pw_dir
|
||||
|
||||
|
||||
def set_password(userName, password, useSpeech):
|
||||
run_privileged(["chpasswd"], useSpeech, inputText=f"{userName}:{password}\n")
|
||||
|
||||
|
||||
def generate_ssh_key(userName, useSpeech):
|
||||
userHome = get_user_home(userName)
|
||||
sshDir = os.path.join(userHome, ".ssh")
|
||||
privateKeyPath = os.path.join(sshDir, "id_ed25519")
|
||||
publicKeyPath = f"{privateKeyPath}.pub"
|
||||
|
||||
run_privileged(["mkdir", "-p", sshDir], useSpeech)
|
||||
run_privileged(["chown", f"{userName}:{userName}", sshDir], useSpeech)
|
||||
run_privileged(["chmod", "700", sshDir], useSpeech)
|
||||
for entry in list_subdirs(sshDir):
|
||||
if os.path.isfile(entry) or os.path.islink(entry):
|
||||
run_privileged(["rm", "-f", entry], useSpeech, check=False)
|
||||
|
||||
run_as_user(
|
||||
userName,
|
||||
["ssh-keygen", "-t", "ed25519", "-N", "", "-f", privateKeyPath],
|
||||
useSpeech,
|
||||
)
|
||||
|
||||
run_privileged(["chmod", "600", privateKeyPath], useSpeech)
|
||||
run_privileged(["chmod", "644", publicKeyPath], useSpeech)
|
||||
run_privileged(["chown", f"{userName}:{userName}", privateKeyPath, publicKeyPath], useSpeech)
|
||||
|
||||
return privateKeyPath, publicKeyPath
|
||||
|
||||
|
||||
def path_exists_for_user(path, userName, useSpeech):
|
||||
result = run_as_user(userName, ["stat", path], useSpeech, check=False)
|
||||
return result.returncode == 0
|
||||
|
||||
|
||||
def extract_message_text(line):
|
||||
if "> " in line:
|
||||
return line.split("> ", 1)[1].strip()
|
||||
if ": " in line:
|
||||
return line.split(": ", 1)[1].strip()
|
||||
return line.strip()
|
||||
|
||||
|
||||
def parse_sender(line):
|
||||
match = re.search(r"<([^>]+)>", line)
|
||||
if match:
|
||||
return match.group(1)
|
||||
return None
|
||||
|
||||
|
||||
def find_wormhole_code(message):
|
||||
lowered = message.strip().lower()
|
||||
if lowered in ("yes", "accept"):
|
||||
return None
|
||||
match = re.search(r"\b\d+-[A-Za-z0-9-]+\b", message)
|
||||
if match:
|
||||
return match.group(0)
|
||||
return None
|
||||
|
||||
|
||||
class IrcSession:
|
||||
def __init__(self, server, port, nick, channel, baseDir):
|
||||
self.server = server
|
||||
self.port = port
|
||||
self.nick = nick
|
||||
self.channel = channel
|
||||
self.baseDir = baseDir
|
||||
self.serverDir = None
|
||||
self.serverInPath = None
|
||||
self.channelInPath = None
|
||||
self.iiProcess = None
|
||||
self.pmOffsets = {}
|
||||
|
||||
def start(self):
|
||||
if not shutil_which("ii"):
|
||||
raise RuntimeError("ii is not installed")
|
||||
supportsI = ii_supports_i()
|
||||
processEnv = os.environ.copy()
|
||||
iiCommand = ["ii", "-s", self.server, "-p", str(self.port), "-n", self.nick]
|
||||
if supportsI:
|
||||
iiCommand += ["-i", self.baseDir]
|
||||
else:
|
||||
processEnv["HOME"] = self.baseDir
|
||||
self.iiProcess = subprocess.Popen(
|
||||
iiCommand,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
env=processEnv,
|
||||
)
|
||||
self.serverDir = self.wait_for_server_dir()
|
||||
self.serverInPath = os.path.join(self.serverDir, "in")
|
||||
|
||||
def stop(self):
|
||||
if self.channelInPath and os.path.exists(self.channelInPath):
|
||||
try:
|
||||
self.write_line(self.channelInPath, f"/part {self.channel}")
|
||||
except OSError:
|
||||
pass
|
||||
if self.serverInPath and os.path.exists(self.serverInPath):
|
||||
try:
|
||||
self.write_line(self.serverInPath, "/quit")
|
||||
except OSError:
|
||||
pass
|
||||
if self.iiProcess and self.iiProcess.poll() is None:
|
||||
self.iiProcess.terminate()
|
||||
try:
|
||||
self.iiProcess.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
self.iiProcess.kill()
|
||||
|
||||
def join_channel(self):
|
||||
joinMessage = f"/join {self.channel}"
|
||||
channelDir = os.path.join(self.serverDir, self.channel)
|
||||
channelAltDir = os.path.join(self.serverDir, self.channel.lstrip("#"))
|
||||
startTime = time.monotonic()
|
||||
nextJoinTime = startTime
|
||||
while time.monotonic() - startTime < 60:
|
||||
if time.monotonic() >= nextJoinTime:
|
||||
self.write_line(self.serverInPath, joinMessage)
|
||||
nextJoinTime = time.monotonic() + 5
|
||||
for candidate in (channelDir, channelAltDir):
|
||||
inPath = os.path.join(candidate, "in")
|
||||
if os.path.exists(inPath):
|
||||
self.channelInPath = inPath
|
||||
return
|
||||
time.sleep(0.5)
|
||||
self.channelInPath = None
|
||||
|
||||
def send_channel_message(self, message):
|
||||
if not self.channelInPath:
|
||||
self.refresh_channel_in_path()
|
||||
if self.channelInPath and os.path.exists(self.channelInPath):
|
||||
self.write_line(self.channelInPath, message)
|
||||
else:
|
||||
self.write_line(self.serverInPath, f"/msg {self.channel} {message}")
|
||||
|
||||
def send_private_message(self, nick, message):
|
||||
nickDir = os.path.join(self.serverDir, nick)
|
||||
inPath = os.path.join(nickDir, "in")
|
||||
if os.path.exists(inPath):
|
||||
self.write_line(inPath, message)
|
||||
else:
|
||||
self.write_line(self.serverInPath, f"/msg {nick} {message}")
|
||||
|
||||
def get_private_messages(self, allowedUsers):
|
||||
messages = []
|
||||
for nick in allowedUsers:
|
||||
nickDir = os.path.join(self.serverDir, nick)
|
||||
outPath = os.path.join(nickDir, "out")
|
||||
if not os.path.exists(outPath):
|
||||
continue
|
||||
lastPos = self.pmOffsets.get(outPath, 0)
|
||||
with open(outPath, "r", encoding="utf-8", errors="ignore") as fileHandle:
|
||||
fileHandle.seek(lastPos)
|
||||
for line in fileHandle:
|
||||
sender = parse_sender(line)
|
||||
if sender and sender == self.nick:
|
||||
continue
|
||||
if sender and sender != nick:
|
||||
continue
|
||||
messageText = extract_message_text(line)
|
||||
if messageText:
|
||||
messages.append((nick, messageText))
|
||||
self.pmOffsets[outPath] = fileHandle.tell()
|
||||
return messages
|
||||
|
||||
def refresh_channel_in_path(self):
|
||||
channelDir = os.path.join(self.serverDir, self.channel)
|
||||
channelAltDir = os.path.join(self.serverDir, self.channel.lstrip("#"))
|
||||
for candidate in (channelDir, channelAltDir):
|
||||
inPath = os.path.join(candidate, "in")
|
||||
if os.path.exists(inPath):
|
||||
self.channelInPath = inPath
|
||||
return
|
||||
|
||||
def wait_for_server_dir(self):
|
||||
for _ in range(120):
|
||||
for rootDir in [self.baseDir] + list_subdirs(self.baseDir):
|
||||
if not os.path.isdir(rootDir):
|
||||
continue
|
||||
for entry in os.listdir(rootDir):
|
||||
path = os.path.join(rootDir, entry)
|
||||
if os.path.isdir(path) and self.server in entry:
|
||||
inPath = os.path.join(path, "in")
|
||||
if os.path.exists(inPath):
|
||||
return path
|
||||
time.sleep(0.5)
|
||||
raise RuntimeError("ii server directory not found")
|
||||
|
||||
@staticmethod
|
||||
def write_line(path, message):
|
||||
with open(path, "w", encoding="utf-8", errors="ignore") as fileHandle:
|
||||
fileHandle.write(message + "\n")
|
||||
fileHandle.flush()
|
||||
|
||||
|
||||
def ii_supports_i():
|
||||
result = run_command(["ii", "-h"])
|
||||
output = (result.stdout or "") + (result.stderr or "")
|
||||
return "-i" in output
|
||||
|
||||
|
||||
def list_subdirs(path):
|
||||
try:
|
||||
return [os.path.join(path, entry) for entry in os.listdir(path)]
|
||||
except OSError:
|
||||
return []
|
||||
|
||||
|
||||
def shutil_which(command):
|
||||
for path in os.environ.get("PATH", "").split(os.pathsep):
|
||||
candidate = os.path.join(path, command)
|
||||
if os.path.isfile(candidate) and os.access(candidate, os.X_OK):
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def build_nick():
|
||||
baseUser = os.environ.get("SUDO_USER") or os.environ.get("USER") or "sas"
|
||||
return f"{baseUser}-{int(time.time())}"
|
||||
|
||||
|
||||
def main():
|
||||
say_or_print("Checking accessibility. Is your screen reader working? (y/n)", True)
|
||||
answer = input().strip().lower()
|
||||
useSpeech = answer in ("n", "no")
|
||||
|
||||
shouldRemoveUser = False
|
||||
cleanupDone = False
|
||||
tempDir = tempfile.mkdtemp(prefix="sas-ii-")
|
||||
ircSession = None
|
||||
sshProcess = None
|
||||
|
||||
def cleanup(exitMessage=None):
|
||||
nonlocal cleanupDone
|
||||
if cleanupDone:
|
||||
return
|
||||
cleanupDone = True
|
||||
nonlocal sshProcess
|
||||
if exitMessage:
|
||||
say_or_print(exitMessage, useSpeech)
|
||||
|
||||
if sshProcess and sshProcess.poll() is None:
|
||||
sshProcess.terminate()
|
||||
try:
|
||||
sshProcess.wait(timeout=5)
|
||||
except subprocess.TimeoutExpired:
|
||||
sshProcess.kill()
|
||||
|
||||
if ircSession:
|
||||
ircSession.stop()
|
||||
|
||||
if shouldRemoveUser:
|
||||
try:
|
||||
run_privileged(["pkill", "-u", sasUser], useSpeech, check=False)
|
||||
time.sleep(1)
|
||||
result = run_privileged(["userdel", "-r", sasUser], useSpeech, check=False)
|
||||
run_privileged(["rm", "-rf", f"/home/{sasUser}"], useSpeech, check=False)
|
||||
if result.returncode != 0 and user_exists(sasUser):
|
||||
say_or_print(
|
||||
"Cleanup warning: failed to remove sas user. Please remove it manually.",
|
||||
useSpeech,
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
sudoKeepaliveStop.set()
|
||||
if sudoKeepaliveThread:
|
||||
sudoKeepaliveThread.join(timeout=2)
|
||||
|
||||
try:
|
||||
remove_tree(tempDir)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def handle_signal(signum, frame):
|
||||
cleanup("Interrupted. Cleaning up.")
|
||||
sys.exit(1)
|
||||
|
||||
signal.signal(signal.SIGINT, handle_signal)
|
||||
signal.signal(signal.SIGTERM, handle_signal)
|
||||
|
||||
try:
|
||||
if not user_exists(sasUser):
|
||||
run_privileged(
|
||||
["useradd", "-m", "-d", f"/home/{sasUser}", "-s", "/bin/bash", "-G", "wheel", sasUser],
|
||||
useSpeech,
|
||||
)
|
||||
shouldRemoveUser = True
|
||||
else:
|
||||
say_or_print(
|
||||
"User 'sas' exists. Remove and recreate it? This will delete /home/sas. (y/n)",
|
||||
useSpeech,
|
||||
)
|
||||
response = input().strip().lower()
|
||||
if response not in ("y", "yes"):
|
||||
cleanup("The sas user is unavailable. Remove it manually and try again.")
|
||||
return 1
|
||||
run_privileged(["pkill", "-u", sasUser], useSpeech, check=False)
|
||||
run_privileged(["userdel", "-r", sasUser], useSpeech, check=False)
|
||||
run_privileged(["rm", "-rf", f"/home/{sasUser}"], useSpeech, check=False)
|
||||
run_privileged(
|
||||
["useradd", "-m", "-d", f"/home/{sasUser}", "-s", "/bin/bash", "-G", "wheel", sasUser],
|
||||
useSpeech,
|
||||
)
|
||||
shouldRemoveUser = True
|
||||
|
||||
ensure_wheel(sasUser, useSpeech)
|
||||
|
||||
password = generate_password()
|
||||
set_password(sasUser, password, useSpeech)
|
||||
|
||||
privateKeyPath, publicKeyPath = generate_ssh_key(sasUser, useSpeech)
|
||||
sasHome = get_user_home(sasUser)
|
||||
knownHostsPath = os.path.join(sasHome, ".ssh", "known_hosts_sas")
|
||||
run_privileged(["touch", knownHostsPath], useSpeech)
|
||||
run_privileged(["chmod", "600", knownHostsPath], useSpeech)
|
||||
run_privileged(["chown", f"{sasUser}:{sasUser}", knownHostsPath], useSpeech)
|
||||
|
||||
nick = build_nick()
|
||||
ircSession = IrcSession(ircServer, ircPort, nick, ircChannel, tempDir)
|
||||
ircSession.start()
|
||||
ircSession.join_channel()
|
||||
|
||||
say_or_print("Waiting for assistance on IRC.", useSpeech)
|
||||
startTime = time.monotonic()
|
||||
nextPingTime = startTime
|
||||
pingsSent = 0
|
||||
confirmedAdmin = None
|
||||
|
||||
while time.monotonic() - startTime < pingIntervalSeconds * pingCount:
|
||||
now = time.monotonic()
|
||||
if pingsSent < pingCount and now >= nextPingTime:
|
||||
ircSession.send_channel_message(f"{nick} is requesting assistance.")
|
||||
pingsSent += 1
|
||||
nextPingTime = startTime + (pingsSent * pingIntervalSeconds)
|
||||
|
||||
for adminNick, messageText in ircSession.get_private_messages(stormuxAdmin):
|
||||
if messageText.strip().lower() in ("yes", "accept"):
|
||||
confirmedAdmin = adminNick
|
||||
break
|
||||
if confirmedAdmin:
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
if not confirmedAdmin:
|
||||
cleanup("No one was available to help, please try again later.")
|
||||
return 1
|
||||
|
||||
ircSession.send_private_message(
|
||||
confirmedAdmin,
|
||||
f'password: "{password}" please send wormhole ssh invite code',
|
||||
)
|
||||
|
||||
failures = 0
|
||||
while failures < maxWormholeFailures:
|
||||
inviteCode = None
|
||||
while inviteCode is None:
|
||||
for adminNick, messageText in ircSession.get_private_messages(stormuxAdmin):
|
||||
inviteCode = find_wormhole_code(messageText)
|
||||
if inviteCode:
|
||||
break
|
||||
if inviteCode:
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
if not path_exists_for_user(publicKeyPath, sasUser, useSpeech):
|
||||
raise RuntimeError(f"Public key missing: {publicKeyPath}")
|
||||
|
||||
wormholeCommand = [
|
||||
"wormhole",
|
||||
"ssh",
|
||||
"accept",
|
||||
"--yes",
|
||||
inviteCode,
|
||||
]
|
||||
result = run_as_user(sasUser, wormholeCommand, useSpeech, check=False)
|
||||
if result.returncode == 0:
|
||||
say_or_print("Wormhole key transfer succeeded.", useSpeech)
|
||||
break
|
||||
|
||||
failures += 1
|
||||
errorTextFull = (result.stderr or result.stdout or "").strip()
|
||||
if errorTextFull and not useSpeech:
|
||||
print("Wormhole ssh accept error:", flush=True)
|
||||
print(errorTextFull, flush=True)
|
||||
errorText = errorTextFull
|
||||
if errorText:
|
||||
errorText = " ".join(errorText.split())
|
||||
if len(errorText) > 400:
|
||||
errorText = errorText[:400] + "..."
|
||||
ircSession.send_private_message(
|
||||
confirmedAdmin,
|
||||
f"Wormhole ssh accept failed: {errorText}",
|
||||
)
|
||||
ircSession.send_private_message(
|
||||
confirmedAdmin,
|
||||
"Wormhole ssh accept failed. Please send a new invite code.",
|
||||
)
|
||||
|
||||
if failures >= maxWormholeFailures:
|
||||
cleanup("Wormhole failed too many times. Exiting.")
|
||||
return 1
|
||||
|
||||
say_or_print("Starting reverse SSH tunnel. Press Ctrl+C to stop.", useSpeech)
|
||||
sshCommand = [
|
||||
"ssh",
|
||||
"-N",
|
||||
"-R",
|
||||
"localhost:2232:localhost:22",
|
||||
"-o",
|
||||
"ExitOnForwardFailure=yes",
|
||||
"-o",
|
||||
"BatchMode=yes",
|
||||
"-o",
|
||||
"ServerAliveInterval=30",
|
||||
"-o",
|
||||
"ServerAliveCountMax=3",
|
||||
"-o",
|
||||
"StrictHostKeyChecking=accept-new",
|
||||
"-o",
|
||||
f"UserKnownHostsFile={knownHostsPath}",
|
||||
"-i",
|
||||
privateKeyPath,
|
||||
f"{sasUser}@{remoteHost}",
|
||||
]
|
||||
sshCommand = ["sudo", "-u", sasUser, "-H"] + sshCommand
|
||||
sshProcess = subprocess.Popen(sshCommand)
|
||||
sshProcess.wait()
|
||||
|
||||
except Exception as exc:
|
||||
cleanup(f"Error: {exc}")
|
||||
return 1
|
||||
finally:
|
||||
cleanup()
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def remove_tree(path):
|
||||
if not os.path.exists(path):
|
||||
return
|
||||
for rootDir, dirNames, fileNames in os.walk(path, topdown=False):
|
||||
for fileName in fileNames:
|
||||
try:
|
||||
os.unlink(os.path.join(rootDir, fileName))
|
||||
except OSError:
|
||||
pass
|
||||
for dirName in dirNames:
|
||||
try:
|
||||
os.rmdir(os.path.join(rootDir, dirName))
|
||||
except OSError:
|
||||
pass
|
||||
try:
|
||||
os.rmdir(path)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
185
pi4/files/usr/share/fenrirscreenreader/scripts/ssh-login-monitor.sh
Executable file
185
pi4/files/usr/share/fenrirscreenreader/scripts/ssh-login-monitor.sh
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# SSH Login Monitor for Fenrir Screen Reader
|
||||
# Monitors SSH logins and announces them via Fenrir's speech system
|
||||
|
||||
# Configuration
|
||||
fenrirSocket="/tmp/fenrirscreenreader-deamon.sock"
|
||||
logFile="/var/log/auth.log"
|
||||
stateFile="/tmp/fenrir-ssh-monitor.state"
|
||||
checkInterval=2 # seconds between checks
|
||||
|
||||
# Voice settings
|
||||
announceUser=true
|
||||
announceIp=true
|
||||
announceHostname=true
|
||||
announceLogout=false # Announce SSH disconnections (disabled by default - may not work reliably on all systems)
|
||||
|
||||
# Function to send message to Fenrir
|
||||
fenrirSay() {
|
||||
local message="$1"
|
||||
# Only announce if Fenrir socket exists (silently skip if not)
|
||||
if [[ -S "$fenrirSocket" ]]; then
|
||||
echo "command say ${message}" | socat - UNIX-CLIENT:"${fenrirSocket}" 2>/dev/null
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to get last processed line number
|
||||
getLastLine() {
|
||||
if [[ -f "$stateFile" ]]; then
|
||||
cat "$stateFile"
|
||||
else
|
||||
echo "0"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to save last processed line number
|
||||
saveLastLine() {
|
||||
echo "$1" > "$stateFile"
|
||||
}
|
||||
|
||||
# Function to parse SSH login and announce
|
||||
processLogin() {
|
||||
local logLine="$1"
|
||||
local user=""
|
||||
local ip=""
|
||||
local hostname=""
|
||||
|
||||
# Parse different SSH login patterns
|
||||
# Pattern 1: "Accepted publickey for USER from IP"
|
||||
# Pattern 2: "Accepted password for USER from IP"
|
||||
if [[ "$logLine" =~ Accepted\ (publickey|password|keyboard-interactive/pam)\ for\ ([^[:space:]]+)\ from\ ([^[:space:]]+) ]]; then
|
||||
user="${BASH_REMATCH[2]}"
|
||||
ip="${BASH_REMATCH[3]}"
|
||||
|
||||
# Try to resolve hostname
|
||||
if command -v host &> /dev/null && [[ "$announceHostname" == "true" ]]; then
|
||||
hostname="$(host "$ip" 2>/dev/null | grep -oP 'domain name pointer \K[^.]+' | head -1)"
|
||||
fi
|
||||
|
||||
# Build announcement message (concise format)
|
||||
local message=""
|
||||
|
||||
if [[ "$announceUser" == "true" ]]; then
|
||||
message+="${user} "
|
||||
fi
|
||||
|
||||
message+="S S H login"
|
||||
|
||||
if [[ "$announceIp" == "true" ]]; then
|
||||
message+=" from ${ip}"
|
||||
fi
|
||||
|
||||
if [[ -n "$hostname" ]] && [[ "$announceHostname" == "true" ]]; then
|
||||
message+=" ${hostname}"
|
||||
fi
|
||||
|
||||
fenrirSay "$message"
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to parse SSH logout and announce
|
||||
processLogout() {
|
||||
local logLine="$1"
|
||||
local user=""
|
||||
|
||||
# Parse SSH disconnect patterns
|
||||
# Pattern: "pam_unix(sshd:session): session closed for user USER"
|
||||
if [[ "$logLine" =~ session\ closed\ for\ user\ ([^[:space:]]+) ]]; then
|
||||
user="${BASH_REMATCH[1]}"
|
||||
|
||||
if [[ "$announceLogout" == "true" ]]; then
|
||||
local message=""
|
||||
|
||||
if [[ "$announceUser" == "true" ]]; then
|
||||
message+="${user} "
|
||||
fi
|
||||
|
||||
message+="disconnected from S S H"
|
||||
|
||||
fenrirSay "$message"
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
# Function to monitor auth.log
|
||||
monitorAuthLog() {
|
||||
local lastLine
|
||||
lastLine=$(getLastLine)
|
||||
|
||||
# Get total lines in log
|
||||
local totalLines
|
||||
totalLines=$(wc -l < "$logFile" 2>/dev/null || echo "0")
|
||||
|
||||
# If log was rotated, reset
|
||||
if [[ $totalLines -lt $lastLine ]]; then
|
||||
lastLine=0
|
||||
fi
|
||||
|
||||
# Process new lines
|
||||
if [[ $totalLines -gt $lastLine ]]; then
|
||||
local newLines=$((totalLines - lastLine))
|
||||
|
||||
# Read only new lines
|
||||
tail -n "$newLines" "$logFile" 2>/dev/null | while IFS= read -r line; do
|
||||
if [[ "$line" =~ sshd.*Accepted ]]; then
|
||||
processLogin "$line"
|
||||
elif [[ "$line" =~ sshd.*session\ closed ]]; then
|
||||
processLogout "$line"
|
||||
fi
|
||||
done
|
||||
|
||||
saveLastLine "$totalLines"
|
||||
fi
|
||||
}
|
||||
|
||||
# Function to monitor journalctl (alternative for systemd systems)
|
||||
monitorJournalctl() {
|
||||
# Follow journalctl for SSH logins and logouts
|
||||
journalctl -u sshd -u ssh -f -n 0 --no-pager 2>/dev/null | while IFS= read -r line; do
|
||||
if [[ "$line" =~ Accepted ]]; then
|
||||
processLogin "$line"
|
||||
elif [[ "$line" =~ session\ closed ]]; then
|
||||
processLogout "$line"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# Check if running as root
|
||||
if [[ "$(id -u)" -ne 0 ]]; then
|
||||
echo "Error: This script must be run with sudo privileges to access system logs."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Note: We don't require Fenrir to be running at startup
|
||||
# The script will silently skip announcements when Fenrir socket doesn't exist
|
||||
|
||||
# Determine monitoring method
|
||||
if command -v journalctl &> /dev/null && systemctl is-active --quiet sshd 2>/dev/null; then
|
||||
echo "Starting SSH login monitor (using journalctl)..."
|
||||
fenrirSay "SSH login monitor started."
|
||||
|
||||
# Use journalctl for real-time monitoring
|
||||
trap 'fenrirSay "SSH login monitor stopped."; exit 0' INT TERM
|
||||
monitorJournalctl
|
||||
elif [[ -f "$logFile" ]]; then
|
||||
echo "Starting SSH login monitor (using auth.log)..."
|
||||
fenrirSay "SSH login monitor started."
|
||||
|
||||
# Use auth.log polling
|
||||
trap 'fenrirSay "SSH login monitor stopped."; rm -f "$stateFile"; exit 0' INT TERM
|
||||
|
||||
while true; do
|
||||
monitorAuthLog
|
||||
sleep "$checkInterval"
|
||||
done
|
||||
else
|
||||
echo "Error: Cannot find SSH logs. Neither journalctl nor ${logFile} is available."
|
||||
exit 1
|
||||
fi
|
||||
BIN
pi4/files/usr/share/kbd/keymaps/i386/qwerty/us_alt.map.gz
Normal file
BIN
pi4/files/usr/share/kbd/keymaps/i386/qwerty/us_alt.map.gz
Normal file
Binary file not shown.
15
x86_64/.gitignore
vendored
Normal file
15
x86_64/.gitignore
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
# x86_64 ISO build artifacts
|
||||
out/
|
||||
work/
|
||||
logs/
|
||||
|
||||
# Build outputs
|
||||
*.iso
|
||||
*.iso.sig
|
||||
*.sha256
|
||||
|
||||
# Documentation (not tracked)
|
||||
*.md
|
||||
|
||||
# User-specific
|
||||
.claude/
|
||||
24
x86_64/50-fenrir-bluez.conf
Normal file
24
x86_64/50-fenrir-bluez.conf
Normal file
@@ -0,0 +1,24 @@
|
||||
# Fenrir console audio support
|
||||
# Prevents bluetooth disconnection when switching TTY
|
||||
|
||||
monitor.bluez.properties = {
|
||||
# Disable logind integration to prevent bluetooth device suspension on TTY switch
|
||||
bluez5.enable-sbc-xq = true
|
||||
bluez5.enable-msbc = true
|
||||
bluez5.enable-hw-volume = true
|
||||
}
|
||||
|
||||
monitor.bluez.rules = [
|
||||
{
|
||||
matches = [
|
||||
{
|
||||
device.name = "~bluez_card.*"
|
||||
}
|
||||
]
|
||||
actions = {
|
||||
update-props = {
|
||||
session.suspend-timeout-seconds = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
24
x86_64/50-fenrir-console.conf
Normal file
24
x86_64/50-fenrir-console.conf
Normal file
@@ -0,0 +1,24 @@
|
||||
# Fenrir console audio support
|
||||
# Adds secondary socket for console applications like Fenrir
|
||||
|
||||
pulse.properties = {
|
||||
# the addresses this server listens on
|
||||
server.address = [
|
||||
"unix:native"
|
||||
"unix:/tmp/pulse.sock" # console access socket
|
||||
]
|
||||
}
|
||||
|
||||
# client/stream specific properties
|
||||
pulse.rules = [
|
||||
{
|
||||
# speech dispatcher asks for too small latency and then underruns.
|
||||
matches = [ { application.name = "~speech-dispatcher*" } ]
|
||||
actions = {
|
||||
update-props = {
|
||||
pulse.min.req = 1024/48000 # 21ms
|
||||
pulse.min.quantum = 1024/48000 # 21ms
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
35
x86_64/50-fenrir-no-suspend.conf
Normal file
35
x86_64/50-fenrir-no-suspend.conf
Normal file
@@ -0,0 +1,35 @@
|
||||
# Fenrir console audio support
|
||||
# Prevents audio device suspension when switching to TTY console
|
||||
|
||||
monitor.alsa.rules = [
|
||||
{
|
||||
matches = [
|
||||
{
|
||||
device.name = "~alsa_card.*"
|
||||
}
|
||||
]
|
||||
actions = {
|
||||
update-props = {
|
||||
api.alsa.use-acp = true
|
||||
api.acp.auto-profile = false
|
||||
api.acp.auto-port = false
|
||||
session.suspend-timeout-seconds = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
matches = [
|
||||
{
|
||||
node.name = "~alsa_input.*"
|
||||
}
|
||||
{
|
||||
node.name = "~alsa_output.*"
|
||||
}
|
||||
]
|
||||
actions = {
|
||||
update-props = {
|
||||
session.suspend-timeout-seconds = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
4
x86_64/airootfs/etc/RHVoice/dicts/English/namefix.txt
Normal file
4
x86_64/airootfs/etc/RHVoice/dicts/English/namefix.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
bifrost=buyfraust
|
||||
danestange=dainstanggey
|
||||
stange=stangey
|
||||
kde=kaydeee
|
||||
19
x86_64/airootfs/etc/RHVoice/dicts/English/wordfix.txt
Normal file
19
x86_64/airootfs/etc/RHVoice/dicts/English/wordfix.txt
Normal file
@@ -0,0 +1,19 @@
|
||||
asus=aysus
|
||||
certificate=cirtifficate
|
||||
douche=doosh*
|
||||
espeak=easpeak*
|
||||
freenginx=freeenginex
|
||||
git=ghit*
|
||||
github=ghittehub
|
||||
gitea=ghittee
|
||||
jolla=yolla
|
||||
jenux=jennux
|
||||
lightnin=lighttnin
|
||||
nginx=enginex
|
||||
rhvoice=ahraychvoice
|
||||
shit=shitt
|
||||
sync=sink*
|
||||
timezone=timezoan
|
||||
vinux=vinnux
|
||||
wench=wentch*
|
||||
youngin=younggin*
|
||||
7
x86_64/airootfs/etc/audibleprompt.sh
Executable file
7
x86_64/airootfs/etc/audibleprompt.sh
Executable file
@@ -0,0 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
play -qnV0 synth 3 pluck D3 pluck A3 pluck D4 pluck F4 pluck A4 delay 0 .1 .2 .3 .4 remix - chorus 0.9 0.9 38 0.75 0.3 0.5 -t &
|
||||
read -rsp "$*"$'\n' password
|
||||
echo "$password"
|
||||
|
||||
exit 0
|
||||
12
x86_64/airootfs/etc/environment
Normal file
12
x86_64/airootfs/etc/environment
Normal file
@@ -0,0 +1,12 @@
|
||||
#
|
||||
# This file is parsed by pam_env module
|
||||
#
|
||||
# Syntax: simple "KEY=VAL" pairs on separate lines
|
||||
#
|
||||
# Accessibility variables
|
||||
export ACCESSIBILITY_ENABLED=1
|
||||
export GTK_MODULES=gail:atk-bridge
|
||||
export GNOME_ACCESSIBILITY=1
|
||||
export QT_ACCESSIBILITY=1
|
||||
export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1
|
||||
export SAL_USE_VCLPLUGIN=gtk3
|
||||
6
x86_64/airootfs/etc/fstab
Normal file
6
x86_64/airootfs/etc/fstab
Normal file
@@ -0,0 +1,6 @@
|
||||
# Static information about the filesystems.
|
||||
# See fstab(5) for details.
|
||||
|
||||
# <file system> <dir> <type> <options> <dump> <pass>
|
||||
# Live ISO - root filesystem is handled by archiso, only tmpfs mounts needed
|
||||
tmpfs /var/log tmpfs defaults,noatime,nosuid,nodev,noexec,mode=0755,size=128M 0 0
|
||||
1
x86_64/airootfs/etc/hostname
Normal file
1
x86_64/airootfs/etc/hostname
Normal file
@@ -0,0 +1 @@
|
||||
stormux
|
||||
5
x86_64/airootfs/etc/hosts
Normal file
5
x86_64/airootfs/etc/hosts
Normal file
@@ -0,0 +1,5 @@
|
||||
# Static table lookup for hostnames.
|
||||
# See hosts(5) for details.
|
||||
127.0.0.1 localhost
|
||||
::1 localhost
|
||||
127.0.1.1 stormux.localdomain stormux
|
||||
3
x86_64/airootfs/etc/mkinitcpio.conf.d/archiso.conf
Normal file
3
x86_64/airootfs/etc/mkinitcpio.conf.d/archiso.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
HOOKS=(base udev microcode modconf kms memdisk archiso archiso_loop_mnt archiso_pxe_common archiso_pxe_nbd archiso_pxe_http archiso_pxe_nfs block filesystems keyboard)
|
||||
COMPRESSION="xz"
|
||||
COMPRESSION_OPTIONS=(-9e)
|
||||
8
x86_64/airootfs/etc/mkinitcpio.d/linux.preset
Normal file
8
x86_64/airootfs/etc/mkinitcpio.d/linux.preset
Normal file
@@ -0,0 +1,8 @@
|
||||
# mkinitcpio preset file for the 'linux' package on archiso
|
||||
|
||||
PRESETS=('archiso')
|
||||
|
||||
ALL_kver='/boot/vmlinuz-linux'
|
||||
archiso_config='/etc/mkinitcpio.conf.d/archiso.conf'
|
||||
|
||||
archiso_image="/boot/initramfs-linux.img"
|
||||
9
x86_64/airootfs/etc/motd
Normal file
9
x86_64/airootfs/etc/motd
Normal file
@@ -0,0 +1,9 @@
|
||||
Welcome to Stormux, powered by Arch Linux
|
||||
|
||||
Stormux Website: https://stormux.org
|
||||
Arch Linux: https://archlinux.org
|
||||
|
||||
Stormux IRC: #stormux on irc.stormux.org
|
||||
|
||||
Thank you Stormux supporters! https://patreon.com/stormux
|
||||
|
||||
105
x86_64/airootfs/etc/pacman.conf
Normal file
105
x86_64/airootfs/etc/pacman.conf
Normal file
@@ -0,0 +1,105 @@
|
||||
#
|
||||
# /etc/pacman.conf
|
||||
#
|
||||
# See the pacman.conf(5) manpage for option and repository directives
|
||||
|
||||
#
|
||||
# GENERAL OPTIONS
|
||||
#
|
||||
[options]
|
||||
# The following paths are commented out with their default values listed.
|
||||
# If you wish to use different paths, uncomment and update the paths.
|
||||
#RootDir = /
|
||||
#DBPath = /var/lib/pacman/
|
||||
#CacheDir = /var/cache/pacman/pkg/
|
||||
#LogFile = /var/log/pacman.log
|
||||
#GPGDir = /etc/pacman.d/gnupg/
|
||||
#HookDir = /etc/pacman.d/hooks/
|
||||
HoldPkg = pacman glibc
|
||||
#XferCommand = /usr/bin/curl -L -C - -f -o %o %u
|
||||
#XferCommand = /usr/bin/wget --passive-ftp -c -O %o %u
|
||||
#CleanMethod = KeepInstalled
|
||||
Architecture = auto
|
||||
|
||||
# Pacman won't upgrade packages listed in IgnorePkg and members of IgnoreGroup
|
||||
#IgnorePkg =
|
||||
#IgnoreGroup =
|
||||
|
||||
# Protect Stormux custom skel files from being overwritten by package updates
|
||||
NoUpgrade = etc/skel/.bashrc etc/skel/.inputrc etc/skel/.screenrc etc/skel/.vimrc etc/skel/.vim/*
|
||||
#NoExtract =
|
||||
|
||||
# Misc options
|
||||
#UseSyslog
|
||||
#Color
|
||||
#NoProgressBar
|
||||
# We cannot check disk space from within a chroot environment
|
||||
#CheckSpace
|
||||
#VerbosePkgLists
|
||||
ParallelDownloads = 5
|
||||
#DownloadUser = alpm
|
||||
#DisableSandbox
|
||||
|
||||
# By default, pacman accepts packages signed by keys that its local keyring
|
||||
# trusts (see pacman-key and its man page), as well as unsigned packages.
|
||||
SigLevel = Required DatabaseOptional
|
||||
LocalFileSigLevel = Optional
|
||||
#RemoteFileSigLevel = Required
|
||||
|
||||
# NOTE: You must run `pacman-key --init` before first using pacman; the local
|
||||
# keyring can then be populated with the keys of all official Arch Linux
|
||||
# packagers with `pacman-key --populate archlinux`.
|
||||
|
||||
#
|
||||
# REPOSITORIES
|
||||
# - can be defined here or included from another file
|
||||
# - pacman will search repositories in the order defined here
|
||||
# - local/custom mirrors can be added here or in separate files
|
||||
# - repositories listed first will take precedence when packages
|
||||
# have identical names, regardless of version number
|
||||
# - URLs will have $repo replaced by the name of the current repo
|
||||
# - URLs will have $arch replaced by the name of the architecture
|
||||
#
|
||||
# Repository entries are of the format:
|
||||
# [repo-name]
|
||||
# Server = ServerName
|
||||
# Include = IncludePath
|
||||
#
|
||||
# The header [repo-name] is crucial - it must be present and
|
||||
# uncommented to enable the repo.
|
||||
#
|
||||
|
||||
# The testing repositories are disabled by default. To enable, uncomment the
|
||||
# repo name header and Include lines. You can add preferred servers immediately
|
||||
# after the header, and they will be used before the default mirrors.
|
||||
|
||||
#[core-testing]
|
||||
#Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[stormux]
|
||||
SigLevel = Required DatabaseOptional
|
||||
Server = https://packages.stormux.org/$arch
|
||||
|
||||
[core]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
#[extra-testing]
|
||||
#Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
[extra]
|
||||
Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
# If you want to run 32 bit applications on your x86_64 system,
|
||||
# enable the multilib repositories as required here.
|
||||
|
||||
#[multilib-testing]
|
||||
#Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
#[multilib]
|
||||
#Include = /etc/pacman.d/mirrorlist
|
||||
|
||||
# An example of a custom package repository. See the pacman manpage for
|
||||
# tips on creating your own repositories.
|
||||
#[custom]
|
||||
#SigLevel = Optional TrustAll
|
||||
#Server = file:///home/custompkgs
|
||||
10
x86_64/airootfs/etc/pacman.d/hooks/00-stormux-repo-key.hook
Normal file
10
x86_64/airootfs/etc/pacman.d/hooks/00-stormux-repo-key.hook
Normal file
@@ -0,0 +1,10 @@
|
||||
[Trigger]
|
||||
Operation = Install
|
||||
Operation = Upgrade
|
||||
Type = Package
|
||||
Target = *
|
||||
|
||||
[Action]
|
||||
Description = Adding Stormux repository key...
|
||||
When = PreTransaction
|
||||
Exec = /bin/sh -c 'if [ ! -f /etc/pacman.d/.stormux-key-added ]; then pacman-key --add /usr/share/stormux/stormux_repo.pub && pacman-key --lsign-key 52ADA49000F1FF0456F8AEEFB4CDE1CD56EF8E82 && touch /etc/pacman.d/.stormux-key-added; fi'
|
||||
16
x86_64/airootfs/etc/pacman.d/hooks/stormux-setup.hook
Normal file
16
x86_64/airootfs/etc/pacman.d/hooks/stormux-setup.hook
Normal file
@@ -0,0 +1,16 @@
|
||||
# remove from airootfs!
|
||||
# Stormux system setup hook - creates user, configures services
|
||||
|
||||
[Trigger]
|
||||
Operation = Install
|
||||
Operation = Upgrade
|
||||
Type = Package
|
||||
Target = filesystem
|
||||
|
||||
[Action]
|
||||
Description = Setting up Stormux user and system configuration...
|
||||
When = PostTransaction
|
||||
Depends = shadow
|
||||
Depends = systemd
|
||||
Depends = sudo
|
||||
Exec = /usr/local/bin/stormux-setup.sh
|
||||
961
x86_64/airootfs/etc/pacman.d/mirrorlist
Normal file
961
x86_64/airootfs/etc/pacman.d/mirrorlist
Normal file
@@ -0,0 +1,961 @@
|
||||
##
|
||||
## Arch Linux repository mirrorlist
|
||||
## Generated on 2025-10-21
|
||||
##
|
||||
|
||||
## Worldwide
|
||||
Server = https://geo.mirror.pkgbuild.com/$repo/os/$arch
|
||||
Server = https://mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = https://fastly.mirror.pkgbuild.com/$repo/os/$arch
|
||||
#Server = https://ftpmirror.infania.net/mirror/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
|
||||
## Albania
|
||||
#Server = https://al.arch.niranjan.co/$repo/os/$arch
|
||||
|
||||
## Armenia
|
||||
#Server = http://mirrors.teamcloud.am/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.teamcloud.am/archlinux/$repo/os/$arch
|
||||
|
||||
## Australia
|
||||
#Server = https://mirror.aarnet.edu.au/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://au.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://au.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch
|
||||
#Server = https://archlinux.mirror.digitalpacific.com.au/$repo/os/$arch
|
||||
#Server = http://gsl-syd.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://gsl-syd.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://sydney.mirror.pkgbuild.com/$repo/os/$arch
|
||||
#Server = http://ftp.iinet.net.au/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.internode.on.net/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://au.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = http://syd.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = https://syd.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.swin.edu.au/archlinux/$repo/os/$arch
|
||||
|
||||
## Austria
|
||||
#Server = http://mirror.alwyzon.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.alwyzon.net/archlinux/$repo/os/$arch
|
||||
#Server = http://at.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://at.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.digitalnova.at/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.easyname.at/archlinux/$repo/os/$arch
|
||||
#Server = https://at.arch.mirror.kescher.at/$repo/os/$arch
|
||||
#Server = https://at.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = https://at-vie.soulharsh007.dev/archlinux/$repo/os/$arch
|
||||
|
||||
## Azerbaijan
|
||||
#Server = http://mirror.ourhost.az/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ourhost.az/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.yer.az/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.yer.az/archlinux/$repo/os/$arch
|
||||
|
||||
## Bangladesh
|
||||
#Server = http://mirror.limda.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.limda.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.xeonbd.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.xeonbd.com/archlinux/$repo/os/$arch
|
||||
|
||||
## Belarus
|
||||
#Server = http://ftp.byfly.by/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.datacenter.by/pub/archlinux/$repo/os/$arch
|
||||
|
||||
## Belgium
|
||||
#Server = http://mirror.1ago.be/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.1ago.be/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.jonas-prz.be/$repo/os/$arch
|
||||
#Server = https://mirror.jonas-prz.be/$repo/os/$arch
|
||||
#Server = https://archlinux.mirror-services.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.tiguinet.net/arch/$repo/os/$arch
|
||||
#Server = https://mirror.tiguinet.net/arch/$repo/os/$arch
|
||||
|
||||
## Brazil
|
||||
#Server = http://archlinux.c3sl.ufpr.br/$repo/os/$arch
|
||||
#Server = https://archlinux.c3sl.ufpr.br/$repo/os/$arch
|
||||
#Server = http://br.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://br.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.ufscar.br/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ufscar.br/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.ic.unicamp.br/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.ic.unicamp.br/archlinux/$repo/os/$arch
|
||||
|
||||
## Bulgaria
|
||||
#Server = http://mirror.host.ag/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.telepoint.bg/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.telepoint.bg/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.uni-plovdiv.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.uni-plovdiv.net/archlinux/$repo/os/$arch
|
||||
|
||||
|
||||
## Canada
|
||||
#Server = http://mirror.0xem.ma/arch/$repo/os/$arch
|
||||
#Server = https://mirror.0xem.ma/arch/$repo/os/$arch
|
||||
#Server = https://mirror.acadielinux.ca/mirror/arch/$repo/os/$arch
|
||||
#Server = https://arch.mirror.winslow.cloud/$repo/os/$arch
|
||||
#Server = http://ca.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://ca.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.cpsc.ucalgary.ca/mirror/archlinux.org/$repo/os/$arch
|
||||
#Server = https://mirror.cpsc.ucalgary.ca/mirror/archlinux.org/$repo/os/$arch
|
||||
#Server = http://mirror.csclub.uwaterloo.ca/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.csclub.uwaterloo.ca/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror2.evolution-host.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror2.evolution-host.com/archlinux/$repo/os/$arch
|
||||
#Server = https://stygian.failzero.net/mirror/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.franscorack.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.its.dal.ca/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.quantum5.ca/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.quantum5.ca/archlinux/$repo/os/$arch
|
||||
#Server = http://muug.ca/mirror/archlinux/$repo/os/$arch
|
||||
#Server = https://muug.ca/mirror/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.pablonara.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.pablonara.com/archlinux/$repo/os/$arch
|
||||
#Server = https://upstream-1.pablonara.com/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.mirror.rafal.ca/$repo/os/$arch
|
||||
#Server = http://mirror.scd31.com/arch/$repo/os/$arch
|
||||
#Server = https://mirror.scd31.com/arch/$repo/os/$arch
|
||||
#Server = http://mirror.xenyth.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.xenyth.net/archlinux/$repo/os/$arch
|
||||
|
||||
## Chile
|
||||
#Server = http://mirror.anquan.cl/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.anquan.cl/archlinux/$repo/os/$arch
|
||||
#Server = http://elmirror.cl/archlinux/$repo/os/$arch
|
||||
#Server = https://elmirror.cl/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.hnd.cl/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.hnd.cl/archlinux/$repo/os/$arch
|
||||
|
||||
## China
|
||||
#Server = http://mirrors.163.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.aliyun.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.aliyun.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.bfsu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.bfsu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.cqu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.cqu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.hit.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.hit.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.hust.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.hust.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.jlu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.jlu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.jxust.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.jxust.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.lzu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.neusoft.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.neusoft.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.nju.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.nju.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.nyist.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.nyist.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.sjtug.sjtu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.tuna.tsinghua.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.ustc.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.wsyu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.wsyu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.xjtu.edu.cn/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.zju.edu.cn/archlinux/$repo/os/$arch
|
||||
|
||||
## Colombia
|
||||
#Server = http://mirrors.atlas.net.co/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.atlas.net.co/archlinux/$repo/os/$arch
|
||||
#Server = http://edgeuno-bog2.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://edgeuno-bog2.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.udenar.edu.co/archlinux/$repo/os/$arch
|
||||
|
||||
## Croatia
|
||||
#Server = http://archlinux.iskon.hr/$repo/os/$arch
|
||||
|
||||
## Czechia
|
||||
#Server = http://mirror.dkm.cz/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.dkm.cz/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.fi.muni.cz/pub/linux/arch/$repo/os/$arch
|
||||
#Server = http://ftp.linux.cz/pub/linux/arch/$repo/os/$arch
|
||||
#Server = https://europe.mirror.pkgbuild.com/$repo/os/$arch
|
||||
#Server = http://gluttony.sin.cvut.cz/arch/$repo/os/$arch
|
||||
#Server = https://gluttony.sin.cvut.cz/arch/$repo/os/$arch
|
||||
#Server = https://archlinux.nic.cz/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.sh.cvut.cz/arch/$repo/os/$arch
|
||||
#Server = https://ftp.sh.cvut.cz/arch/$repo/os/$arch
|
||||
#Server = http://mirror.vpsfree.cz/archlinux/$repo/os/$arch
|
||||
|
||||
## Denmark
|
||||
#Server = http://mirrors.dotsrc.org/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.dotsrc.org/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.group.one/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.group.one/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.it-privat.dk/arch/$repo/os/$arch
|
||||
|
||||
## Ecuador
|
||||
#Server = http://mirror.cedia.org.ec/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.linux.ec/archlinux/$repo/os/$arch
|
||||
|
||||
## Estonia
|
||||
#Server = http://mirror.cspacehostings.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.cspacehostings.com/archlinux/$repo/os/$arch
|
||||
#Server = http://repo.br.ee/arch/$repo/os/$arch
|
||||
#Server = https://repo.br.ee/arch/$repo/os/$arch
|
||||
#Server = http://mirrors.xtom.ee/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.xtom.ee/archlinux/$repo/os/$arch
|
||||
|
||||
## Finland
|
||||
#Server = https://archlinux.doridian.net/$repo/os/$arch
|
||||
#Server = http://cdnmirror.com/archlinux/$repo/os/$arch
|
||||
#Server = https://cdnmirror.com/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.mirror.far.fi/$repo/os/$arch
|
||||
#Server = http://mirror.5i.fi/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.5i.fi/archlinux/$repo/os/$arch
|
||||
#Server = https://fi.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = https://mirror1.sl-chat.ru/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.srv.fail/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.wuki.li/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.wuki.li/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.yhtez.xyz/$repo/os/$arch
|
||||
#Server = https://arch.yhtez.xyz/$repo/os/$arch
|
||||
|
||||
## France
|
||||
#Server = http://mirror.archlinux.ikoula.com/archlinux/$repo/os/$arch
|
||||
#Server = https://elda.asgardius.company/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.bakertelekom.fr/Arch/$repo/os/$arch
|
||||
#Server = https://mirror.bakertelekom.fr/Arch/$repo/os/$arch
|
||||
#Server = http://fr.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://fr.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.cyberbits.eu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.cyberbits.eu/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.datagr.am/$repo/os/$arch
|
||||
#Server = https://mirrors.eric.ovh/arch/$repo/os/$arch
|
||||
#Server = http://mirrors.gandi.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.gandi.net/archlinux/$repo/os/$arch
|
||||
#Server = http://archmirror.hogwarts.fr/$repo/os/$arch
|
||||
#Server = https://archmirror.hogwarts.fr/$repo/os/$arch
|
||||
#Server = http://mirror.its-tps.fr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.its-tps.fr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.jtremesay.org/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.lastmikoi.net/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.mailtunnel.eu/$repo/os/$arch
|
||||
#Server = https://archlinux.mailtunnel.eu/$repo/os/$arch
|
||||
#Server = http://f.matthieul.dev/mirror/archlinux/$repo/os/$arch
|
||||
#Server = https://f.matthieul.dev/mirror/archlinux/$repo/os/$arch
|
||||
#Server = http://mir.archlinux.fr/$repo/os/$arch
|
||||
#Server = http://mirror.oldsql.cc/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.oldsql.cc/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.mirrors.ovh.net/archlinux/$repo/os/$arch
|
||||
#Server = https://archlinux.mirrors.ovh.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.peeres-telecom.fr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.peeres-telecom.fr/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.rznet.fr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.rznet.fr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.smayzy.ovh/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.syxpi.fr/arch/$repo/os/$arch
|
||||
#Server = https://arch.syxpi.fr/arch/$repo/os/$arch
|
||||
#Server = https://mirror.thekinrar.fr/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.theo546.fr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.theo546.fr/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.trap.moe/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.trap.moe/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.u-strasbg.fr/linux/distributions/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.wormhole.eu/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.yourlabs.org/$repo/os/$arch
|
||||
#Server = https://arch.yourlabs.org/$repo/os/$arch
|
||||
|
||||
## Georgia
|
||||
#Server = http://archlinux.grena.ge/$repo/os/$arch
|
||||
#Server = https://archlinux.grena.ge/$repo/os/$arch
|
||||
|
||||
## Germany
|
||||
#Server = http://mirror.23m.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.23m.com/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.agdsn.de/pub/mirrors/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.agdsn.de/pub/mirrors/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.aminvakil.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.aminvakil.com/archlinux/$repo/os/$arch
|
||||
#Server = http://artfiles.org/archlinux.org/$repo/os/$arch
|
||||
#Server = https://mirror.bethselamin.de/$repo/os/$arch
|
||||
#Server = https://de.repo.c48.uk/arch/$repo/os/$arch
|
||||
#Server = http://de.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://de.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.clientvps.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.clientvps.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.cmt.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.cmt.de/archlinux/$repo/os/$arch
|
||||
#Server = http://os.codefionn.eu/archlinux/$repo/os/$arch
|
||||
#Server = https://os.codefionn.eu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror-de-1.cutie.dating/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror-de-1.cutie.dating/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.dogado.de/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.fau.de/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.fau.de/archlinux/$repo/os/$arch
|
||||
#Server = https://pkg.fef.moe/archlinux/$repo/os/$arch
|
||||
#Server = https://dist-mirror.fem.tu-ilmenau.de/archlinux/$repo/os/$arch
|
||||
#Server = https://berlin.mirror.pkgbuild.com/$repo/os/$arch
|
||||
#Server = http://ftp.gwdg.de/pub/linux/archlinux/$repo/os/$arch
|
||||
#Server = https://files.hadiko.de/pub/dists/arch/$repo/os/$arch
|
||||
#Server = http://ftp.hosteurope.de/mirror/ftp.archlinux.org/$repo/os/$arch
|
||||
#Server = http://ftp-stud.hs-esslingen.de/pub/Mirrors/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.hugo-betrugo.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.hugo-betrugo.de/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.informatik.tu-freiberg.de/arch/$repo/os/$arch
|
||||
#Server = https://mirror.informatik.tu-freiberg.de/arch/$repo/os/$arch
|
||||
#Server = http://mirror.as20647.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.ipb.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.as20647.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ipb.de/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.mirror.iphh.net/$repo/os/$arch
|
||||
#Server = http://mirrors.janbruckner.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.janbruckner.de/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.jensgutermuth.de/$repo/os/$arch
|
||||
#Server = https://arch.jensgutermuth.de/$repo/os/$arch
|
||||
#Server = https://de.arch.mirror.kescher.at/$repo/os/$arch
|
||||
#Server = http://mirror.kumi.systems/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.kumi.systems/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.fra10.de.leaseweb.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.fra10.de.leaseweb.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.metalgamer.eu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.metalgamer.eu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.lcarilla.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.lcarilla.de/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.moson.org/arch/$repo/os/$arch
|
||||
#Server = https://mirror.moson.org/arch/$repo/os/$arch
|
||||
#Server = http://mirrors.n-ix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.n-ix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.netcologne.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.netcologne.de/archlinux/$repo/os/$arch
|
||||
#Server = https://de.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = http://mirrors.niyawe.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.niyawe.de/archlinux/$repo/os/$arch
|
||||
#Server = http://packages.oth-regensburg.de/archlinux/$repo/os/$arch
|
||||
#Server = https://packages.oth-regensburg.de/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.owochle.app/$repo/os/$arch
|
||||
#Server = https://arch.owochle.app/$repo/os/$arch
|
||||
#Server = http://mirror.pagenotfound.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.pagenotfound.de/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.phinau.de/$repo/os/$arch
|
||||
#Server = https://arch.phinau.de/$repo/os/$arch
|
||||
#Server = https://mirror.pseudoform.org/$repo/os/$arch
|
||||
#Server = http://mirrors.purring.online/arch/$repo/os/$arch
|
||||
#Server = https://mirrors.purring.online/arch/$repo/os/$arch
|
||||
#Server = https://archlinux.richard-neumann.de/$repo/os/$arch
|
||||
#Server = http://ftp.halifax.rwth-aachen.de/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.halifax.rwth-aachen.de/archlinux/$repo/os/$arch
|
||||
#Server = http://linux.rz.rub.de/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.selfnet.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.selfnet.de/archlinux/$repo/os/$arch
|
||||
#Server = https://de-nue.soulharsh007.dev/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.spline.inf.fu-berlin.de/mirrors/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.spline.inf.fu-berlin.de/mirrors/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.sunred.org/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.sunred.org/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.thaller.ws/$repo/os/$arch
|
||||
#Server = https://archlinux.thaller.ws/$repo/os/$arch
|
||||
#Server = https://mirror.thereisno.page/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.tu-chemnitz.de/pub/linux/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.ubrco.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ubrco.de/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.uni-bayreuth.de/linux/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.uni-hannover.de/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.uni-kl.de/pub/linux/archlinux/$repo/os/$arch
|
||||
#Server = https://arch.unixpeople.org/$repo/os/$arch
|
||||
#Server = http://mirrors.xtom.de/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.xtom.de/archlinux/$repo/os/$arch
|
||||
|
||||
## Greece
|
||||
#Server = http://ftp.cc.uoc.gr/mirrors/linux/archlinux/$repo/os/$arch
|
||||
#Server = https://repo.greeklug.gr/data/pub/linux/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.otenet.gr/linux/archlinux/$repo/os/$arch
|
||||
|
||||
## Hong Kong
|
||||
#Server = https://hk.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror-hk.koddos.net/archlinux/$repo/os/$arch
|
||||
#Server = http://hkg.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = https://hkg.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = https://arch-mirror.wtako.net/$repo/os/$arch
|
||||
#Server = http://mirror.xtom.com.hk/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.xtom.com.hk/archlinux/$repo/os/$arch
|
||||
|
||||
## Hungary
|
||||
#Server = https://ftp.ek-cer.hu/pub/mirrors/ftp.archlinux.org/$repo/os/$arch
|
||||
#Server = http://nova.quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://super.quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://nova.quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://super.quantum-mirror.hu/mirrors/pub/archlinux/$repo/os/$arch
|
||||
|
||||
## Iceland
|
||||
#Server = http://is.mirror.flokinet.net/archlinux/$repo/os/$arch
|
||||
#Server = https://is.mirror.flokinet.net/archlinux/$repo/os/$arch
|
||||
|
||||
## India
|
||||
#Server = https://mirrors.abhy.me/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.del2.albony.in/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.maa.albony.in/archlinux/$repo/os/$arch
|
||||
#Server = http://in.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://in.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://in-mirror.garudalinux.org/archlinux/$repo/os/$arch
|
||||
#Server = https://in-mirror.garudalinux.org/archlinux/$repo/os/$arch
|
||||
#Server = https://archlinux.kushwanthreddy.com/$repo/os/$arch
|
||||
#Server = https://in.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = http://mirrors.nxtgen.com/archlinux-mirror/$repo/os/$arch
|
||||
#Server = https://mirrors.nxtgen.com/archlinux-mirror/$repo/os/$arch
|
||||
#Server = http://mirror.sahil.world/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.sahil.world/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.saswata.cc/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.saswata.cc/archlinux/$repo/os/$arch
|
||||
|
||||
## Indonesia
|
||||
#Server = http://mirror.citrahost.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.citrahost.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.gi.co.id/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.gi.co.id/archlinux/$repo/os/$arch
|
||||
#Server = http://kebo.pens.ac.id/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.ditatompel.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ditatompel.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.papua.go.id/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.papua.go.id/archlinux/$repo/os/$arch
|
||||
#Server = https://kacabenggala.uny.ac.id/archlinux/$repo/os/$arch
|
||||
|
||||
## Iran
|
||||
#Server = http://mirror.arvancloud.ir/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.arvancloud.ir/archlinux/$repo/os/$arch
|
||||
#Server = http://repo.iut.ac.ir/repo/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.mobinhost.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.mobinhost.com/archlinux/$repo/os/$arch
|
||||
|
||||
## Israel
|
||||
#Server = http://archlinux.interhost.co.il/$repo/os/$arch
|
||||
#Server = https://archlinux.interhost.co.il/$repo/os/$arch
|
||||
#Server = http://mirror.isoc.org.il/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.isoc.org.il/pub/archlinux/$repo/os/$arch
|
||||
|
||||
## Italy
|
||||
#Server = http://it.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://it.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.mirror.garr.it/archlinux/$repo/os/$arch
|
||||
#Server = https://arch.mirror.hyperbit.it/$repo/os/$arch
|
||||
#Server = http://archlinux.mirror.server24.net/$repo/os/$arch
|
||||
#Server = https://archlinux.mirror.server24.net/$repo/os/$arch
|
||||
|
||||
## Japan
|
||||
#Server = http://mirrors.cat.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.cat.net/archlinux/$repo/os/$arch
|
||||
#Server = http://jp.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://jp.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.tsukuba.wide.ad.jp/Linux/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/$repo/os/$arch
|
||||
#Server = https://ftp.jaist.ac.jp/pub/Linux/ArchLinux/$repo/os/$arch
|
||||
#Server = http://mirror.rain.ne.jp/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.rain.ne.jp/archlinux/$repo/os/$arch
|
||||
|
||||
## Kazakhstan
|
||||
#Server = http://mirror.ps.kz/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ps.kz/archlinux/$repo/os/$arch
|
||||
|
||||
## Kenya
|
||||
#Server = http://archlinux.mirror.liquidtelecom.com/$repo/os/$arch
|
||||
#Server = https://archlinux.mirror.liquidtelecom.com/$repo/os/$arch
|
||||
|
||||
## Latvia
|
||||
#Server = http://ftp.linux.edu.lv/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.linux.edu.lv/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.koyanet.lv/archlinux/$repo/os/$arch
|
||||
#Server = https://archlinux.koyanet.lv/archlinux/$repo/os/$arch
|
||||
|
||||
## Lithuania
|
||||
#Server = http://mirrors.atviras.lt/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.atviras.lt/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.sinirlan.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.sinirlan.net/archlinux/$repo/os/$arch
|
||||
|
||||
## Luxembourg
|
||||
#Server = http://arch-lux.spirex.me/$repo/os/$arch
|
||||
#Server = https://arch-lux.spirex.me/$repo/os/$arch
|
||||
|
||||
## Mauritius
|
||||
#Server = http://archlinux-mirror.cloud.mu/$repo/os/$arch
|
||||
#Server = https://archlinux-mirror.cloud.mu/$repo/os/$arch
|
||||
|
||||
## Mexico
|
||||
#Server = http://lidsol.fi-b.unam.mx/archlinux/$repo/os/$arch
|
||||
#Server = https://lidsol.fi-b.unam.mx/archlinux/$repo/os/$arch
|
||||
#Server = https://arch.jsc.mx/$repo/os/$arch
|
||||
|
||||
## Moldova
|
||||
#Server = http://mirror.hosthink.net/arch/$repo/os/$arch
|
||||
#Server = https://mirror.hosthink.net/arch/$repo/os/$arch
|
||||
#Server = http://mirror.ihost.md/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ihost.md/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.mangohost.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.mangohost.net/archlinux/$repo/os/$arch
|
||||
|
||||
## Morocco
|
||||
#Server = http://mirror.abderraziq.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.abderraziq.com/archlinux/$repo/os/$arch
|
||||
|
||||
|
||||
## Netherlands
|
||||
#Server = http://ams.nl.mirrors.bjg.at/arch/$repo/os/$arch
|
||||
#Server = https://ams.nl.mirrors.bjg.at/arch/$repo/os/$arch
|
||||
#Server = http://mirror.bouwhuis.network/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.bouwhuis.network/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.nl.cdn-perfprod.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.nl.cdn-perfprod.com/archlinux/$repo/os/$arch
|
||||
#Server = http://nl.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://nl.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.cj2.nl/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.cj2.nl/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.evoluso.com/archlinux/$repo/os/$arch
|
||||
#Server = http://nl.mirror.flokinet.net/archlinux/$repo/os/$arch
|
||||
#Server = https://nl.mirror.flokinet.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.iusearchbtw.nl/$repo/os/$arch
|
||||
#Server = http://mirror.koddos.net/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.mirrors.lavatech.top/$repo/os/$arch
|
||||
#Server = https://arch.mirrors.lavatech.top/$repo/os/$arch
|
||||
#Server = http://mirror.ams1.nl.leaseweb.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ams1.nl.leaseweb.net/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.mirror.liteserver.nl/$repo/os/$arch
|
||||
#Server = https://archlinux.mirror.liteserver.nl/$repo/os/$arch
|
||||
#Server = http://mirror.lyrahosting.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.lyrahosting.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.mijn.host/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.mijn.host/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.nluug.nl/os/Linux/distr/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.snt.utwente.nl/pub/os/linux/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.mirror.wearetriple.com/$repo/os/$arch
|
||||
#Server = https://archlinux.mirror.wearetriple.com/$repo/os/$arch
|
||||
#Server = http://mirrors.xtom.nl/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.xtom.nl/archlinux/$repo/os/$arch
|
||||
|
||||
## New Caledonia
|
||||
#Server = http://mirror.lagoon.nc/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.nautile.nc/archlinux/$repo/os/$arch
|
||||
#Server = https://archlinux.nautile.nc/archlinux/$repo/os/$arch
|
||||
|
||||
## New Zealand
|
||||
#Server = http://mirror.2degrees.nz/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.2degrees.nz/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.fsmg.org.nz/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.fsmg.org.nz/archlinux/$repo/os/$arch
|
||||
#Server = https://nz.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = https://archlinux.ourhome.kiwi/$repo/os/$arch
|
||||
|
||||
## North Macedonia
|
||||
#Server = http://arch.softver.org.mk/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.onevip.mk/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.t-home.mk/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.t-home.mk/archlinux/$repo/os/$arch
|
||||
|
||||
## Norway
|
||||
#Server = http://mirror.archlinux.no/$repo/os/$arch
|
||||
#Server = https://mirror.archlinux.no/$repo/os/$arch
|
||||
#Server = http://archlinux.uib.no/$repo/os/$arch
|
||||
#Server = http://mirror.neuf.no/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.neuf.no/archlinux/$repo/os/$arch
|
||||
|
||||
|
||||
## Poland
|
||||
#Server = http://ftp.icm.edu.pl/pub/Linux/dist/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.icm.edu.pl/pub/Linux/dist/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.juniorjpdj.pl/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.juniorjpdj.pl/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.midov.pl/arch/$repo/os/$arch
|
||||
#Server = https://arch.midov.pl/arch/$repo/os/$arch
|
||||
#Server = https://mirror.przekichane.pl/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.psnc.pl/linux/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.psnc.pl/linux/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.sakamoto.pl/$repo/os/$arch
|
||||
#Server = https://arch.sakamoto.pl/$repo/os/$arch
|
||||
|
||||
## Portugal
|
||||
#Server = http://mirror.barata.pt/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.barata.pt/archlinux/$repo/os/$arch
|
||||
#Server = http://glua.ua.pt/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://glua.ua.pt/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.up.pt/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.up.pt/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.rnl.tecnico.ulisboa.pt/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.rnl.tecnico.ulisboa.pt/pub/archlinux/$repo/os/$arch
|
||||
|
||||
## Romania
|
||||
#Server = http://mirror.ro.cdn-perfprod.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ro.cdn-perfprod.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.chroot.ro/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.chroot.ro/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.efect.ro/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.efect.ro/archlinux/$repo/os/$arch
|
||||
#Server = http://ro.mirror.flokinet.net/archlinux/$repo/os/$arch
|
||||
#Server = https://ro.mirror.flokinet.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.hosterion.ro/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.hosterion.ro/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.hostico.ro/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.hostico.ro/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.mirrors.linux.ro/$repo/os/$arch
|
||||
#Server = http://mirrors.nav.ro/archlinux/$repo/os/$arch
|
||||
#Server = https://ro.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = http://mirrors.nxthost.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.nxthost.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.pidginhost.com/arch/$repo/os/$arch
|
||||
#Server = https://mirrors.pidginhost.com/arch/$repo/os/$arch
|
||||
|
||||
## Russia
|
||||
#Server = http://archlinux.gay/archlinux/$repo/os/$arch
|
||||
#Server = https://archlinux.gay/archlinux/$repo/os/$arch
|
||||
#Server = http://ru.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://ru.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.kpfu.ru/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.kpfu.ru/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.nw-sys.ru/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.nw-sys.ru/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.powernet.com.ru/archlinux/$repo/os/$arch
|
||||
#Server = http://repository.su/archlinux/$repo/os/$arch
|
||||
#Server = https://repository.su/archlinux/$repo/os/$arch
|
||||
#Server = http://web.sketserv.ru/archlinux/$repo/os/$arch
|
||||
#Server = https://web.sketserv.ru/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror2.sl-chat.ru/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror3.sl-chat.ru/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.truenetwork.ru/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.truenetwork.ru/archlinux/$repo/os/$arch
|
||||
#Server = http://vladivostokst.ru/archlinux/$repo/os/$arch
|
||||
#Server = https://vladivostokst.ru/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.yandex.ru/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.yandex.ru/archlinux/$repo/os/$arch
|
||||
|
||||
## Réunion
|
||||
#Server = http://arch.mithril.re/$repo/os/$arch
|
||||
|
||||
## Saudi Arabia
|
||||
#Server = http://sa.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://sa.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.maeen.sa/arch-mirror/$repo/os/$arch
|
||||
#Server = https://mirror.maeen.sa/arch-mirror/$repo/os/$arch
|
||||
|
||||
## Serbia
|
||||
#Server = http://mirror.pmf.kg.ac.rs/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror1.sox.rs/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror1.sox.rs/archlinux/$repo/os/$arch
|
||||
|
||||
## Singapore
|
||||
#Server = http://mirror.aktkn.sg/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.aktkn.sg/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.sg.cdn-perfprod.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.sg.cdn-perfprod.com/archlinux/$repo/os/$arch
|
||||
#Server = http://sg.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://sg.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://download.nus.edu.sg/mirror/archlinux/$repo/os/$arch
|
||||
#Server = https://singapore.mirror.pkgbuild.com/$repo/os/$arch
|
||||
#Server = http://mirror.guillaumea.fr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.guillaumea.fr/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.jingk.ai/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.jingk.ai/archlinux/$repo/os/$arch
|
||||
#Server = https://sg.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = http://ossmirror.mycloud.services/os/linux/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.sg.gs/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.sg.gs/archlinux/$repo/os/$arch
|
||||
|
||||
## Slovakia
|
||||
#Server = http://ftp.energotel.sk/pub/linux/arch/$repo/os/$arch
|
||||
#Server = https://ftp.energotel.sk/pub/linux/arch/$repo/os/$arch
|
||||
#Server = http://mirror.lnx.sk/pub/linux/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.lnx.sk/pub/linux/archlinux/$repo/os/$arch
|
||||
#Server = http://tux.rainside.sk/archlinux/$repo/os/$arch
|
||||
|
||||
## Slovenia
|
||||
#Server = https://mirror.archlinux.si/$repo/os/$arch
|
||||
#Server = https://www.sooftware.com/mirrors/Arch-Linux/$repo/os/$arch
|
||||
#Server = http://mirror.tux.si/arch/$repo/os/$arch
|
||||
#Server = https://mirror.tux.si/arch/$repo/os/$arch
|
||||
|
||||
## South Africa
|
||||
#Server = http://archlinux.za.mirror.allworldit.com/archlinux/$repo/os/$arch
|
||||
#Server = https://archlinux.za.mirror.allworldit.com/archlinux/$repo/os/$arch
|
||||
#Server = http://za.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://za.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://johannesburg.mirror.pkgbuild.com/$repo/os/$arch
|
||||
#Server = http://mirror.is.co.za/mirror/archlinux.org/$repo/os/$arch
|
||||
#Server = http://mirrors.urbanwave.co.za/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.urbanwave.co.za/archlinux/$repo/os/$arch
|
||||
|
||||
## South Korea
|
||||
#Server = http://kr.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://kr.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.techlabs.co.kr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.techlabs.co.kr/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.distly.kr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.distly.kr/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.kaist.ac.kr/ArchLinux/$repo/os/$arch
|
||||
#Server = http://ftp.hrts.kr/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.hrts.kr/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.keiminem.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror2.keiminem.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.keiminem.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror2.keiminem.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.krfoss.org/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.lanet.kr/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.lanet.kr/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.siwoo.org/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.siwoo.org/archlinux/$repo/os/$arch
|
||||
|
||||
## Spain
|
||||
#Server = http://mirror.es.cdn-perfprod.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.es.cdn-perfprod.com/archlinux/$repo/os/$arch
|
||||
#Server = http://es.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://es.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://nox.panibrez.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.raiolanetworks.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.raiolanetworks.com/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.rediris.es/mirror/archlinux/$repo/os/$arch
|
||||
|
||||
## Sweden
|
||||
#Server = http://mirror.accum.se/mirror/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.accum.se/mirror/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.braindrainlan.nu/archlinux/$repo/os/$arch
|
||||
#Server = http://ftpmirror.infania.net/mirror/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.ludd.ltu.se/mirrors/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.ludd.ltu.se/mirrors/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.lysator.liu.se/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.lysator.liu.se/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.bahnhof.net/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.bahnhof.net/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://ftp.myrveln.se/pub/linux/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.myrveln.se/pub/linux/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.osbeck.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.retropc.se/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.retropc.se/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.tedwall.se/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.tedwall.se/archlinux/$repo/os/$arch
|
||||
|
||||
## Switzerland
|
||||
#Server = http://pkg.adfinis-on-exoscale.ch/archlinux-pkgbuild/$repo/os/$arch
|
||||
#Server = http://pkg.adfinis-on-exoscale.ch/archlinux/$repo/os/$arch
|
||||
#Server = https://pkg.adfinis-on-exoscale.ch/archlinux-pkgbuild/$repo/os/$arch
|
||||
#Server = https://pkg.adfinis-on-exoscale.ch/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.arch-linux.ch/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.arch-linux.ch/archlinux/$repo/os/$arch
|
||||
#Server = https://archlinux.lan.brgn.ch/archlinux/$repo/os/$arch
|
||||
#Server = http://ch.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://ch.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.hb9hil.org/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.hb9hil.org/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.init7.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.init7.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.metanet.ch/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.metanet.ch/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.puzzle.ch/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.puzzle.ch/archlinux/$repo/os/$arch
|
||||
#Server = https://theswissbay.ch/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.ungleich.ch/mirror/packages/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.worldhotspot.org/archlinux/$repo/os/$arch
|
||||
|
||||
## Taiwan
|
||||
#Server = http://mirror.archlinux.tw/ArchLinux/$repo/os/$arch
|
||||
#Server = https://mirror.archlinux.tw/ArchLinux/$repo/os/$arch
|
||||
#Server = http://archlinux.ccns.ncku.edu.tw/archlinux/$repo/os/$arch
|
||||
#Server = https://archlinux.ccns.ncku.edu.tw/archlinux/$repo/os/$arch
|
||||
#Server = http://tw.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://tw.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://free.nchc.org.tw/arch/$repo/os/$arch
|
||||
#Server = https://taipei.mirror.pkgbuild.com/$repo/os/$arch
|
||||
#Server = http://archlinux.cs.nycu.edu.tw/$repo/os/$arch
|
||||
#Server = https://archlinux.cs.nycu.edu.tw/$repo/os/$arch
|
||||
#Server = http://mirror.twds.com.tw/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.twds.com.tw/archlinux/$repo/os/$arch
|
||||
|
||||
## Thailand
|
||||
#Server = https://mirror.cyberbits.asia/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.kku.ac.th/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.kku.ac.th/archlinux/$repo/os/$arch
|
||||
|
||||
## Türkiye
|
||||
#Server = http://ftp.linux.org.tr/archlinux/$repo/os/$arch
|
||||
#Server = https://tr.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = http://mirror.nucc.tr/arch/$repo/os/$arch
|
||||
#Server = https://mirror.nucc.tr/arch/$repo/os/$arch
|
||||
#Server = http://mirror.timtal.com.tr/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.timtal.com.tr/archlinux/$repo/os/$arch
|
||||
|
||||
## Ukraine
|
||||
#Server = http://distrohub.kyiv.ua/archlinux/$repo/os/$arch
|
||||
#Server = https://distrohub.kyiv.ua/archlinux/$repo/os/$arch
|
||||
#Server = http://repo.hyron.dev/archlinux/$repo/os/$arch
|
||||
#Server = https://repo.hyron.dev/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.hntr.pp.ua/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.hntr.pp.ua/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.hostiko.network/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.hostiko.network/archlinux/$repo/os/$arch
|
||||
#Server = http://archlinux.ip-connect.vn.ua/$repo/os/$arch
|
||||
#Server = https://archlinux.ip-connect.vn.ua/$repo/os/$arch
|
||||
#Server = http://mirror.mirohost.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.mirohost.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.reitarovskyi.com.ua/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.reitarovskyi.com.ua/archlinux/$repo/os/$arch
|
||||
|
||||
## United Arab Emirates
|
||||
#Server = https://mirror.hafeezh.com/archlinux/$repo/os/$arch
|
||||
|
||||
## United Kingdom
|
||||
#Server = http://archlinux.uk.mirror.allworldit.com/archlinux/$repo/os/$arch
|
||||
#Server = https://archlinux.uk.mirror.allworldit.com/archlinux/$repo/os/$arch
|
||||
#Server = https://repo.c48.uk/arch/$repo/os/$arch
|
||||
#Server = https://uk.repo.c48.uk/arch/$repo/os/$arch
|
||||
#Server = http://gb.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://gb.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://london.mirror.pkgbuild.com/$repo/os/$arch
|
||||
#Server = http://mirror.marcusn.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.marcusn.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.melbourne.co.uk/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.melbourne.co.uk/archlinux/$repo/os/$arch
|
||||
#Server = http://www.mirrorservice.org/sites/ftp.archlinux.org/$repo/os/$arch
|
||||
#Server = https://www.mirrorservice.org/sites/ftp.archlinux.org/$repo/os/$arch
|
||||
#Server = http://mirror.netweaver.uk/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.netweaver.uk/archlinux/$repo/os/$arch
|
||||
#Server = http://lon.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = https://lon.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.server.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.server.net/archlinux/$repo/os/$arch
|
||||
#Server = https://repo.slithery.uk/$repo/os/$arch
|
||||
#Server = https://mirror.st2projects.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.ukfast.co.uk/sites/archlinux.org/$repo/os/$arch
|
||||
#Server = https://mirrors.ukfast.co.uk/sites/archlinux.org/$repo/os/$arch
|
||||
#Server = http://mirror.cov.ukservers.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.cov.ukservers.com/archlinux/$repo/os/$arch
|
||||
|
||||
## United States
|
||||
#Server = http://mirrors.acm.wpi.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.adectra.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.adectra.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.akane.network/archmirror/$repo/os/$arch
|
||||
#Server = http://arlm.tyzoid.com/$repo/os/$arch
|
||||
#Server = https://arlm.tyzoid.com/$repo/os/$arch
|
||||
#Server = http://ny.us.mirrors.bjg.at/arch/$repo/os/$arch
|
||||
#Server = https://ny.us.mirrors.bjg.at/arch/$repo/os/$arch
|
||||
#Server = http://mirrors.bloomu.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.bloomu.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://arch-mirror.brightlight.today/$repo/os/$arch
|
||||
#Server = http://mirrors.cat.pdx.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://us.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = https://us.mirrors.cicku.me/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.clarkson.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.clarkson.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.colonelhosting.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.colonelhosting.com/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.mirror.constant.com/$repo/os/$arch
|
||||
#Server = https://arch.mirror.constant.com/$repo/os/$arch
|
||||
#Server = http://mirror.cs.odu.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.cs.odu.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.cs.vt.edu/pub/ArchLinux/$repo/os/$arch
|
||||
#Server = http://repo.customcomputercare.com/archlinux/$repo/os/$arch
|
||||
#Server = https://repo.customcomputercare.com/archlinux/$repo/os/$arch
|
||||
#Server = http://distro.ibiblio.org/archlinux/$repo/os/$arch
|
||||
#Server = http://codingflyboy.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://coresite.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://forksystems.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://irltoolkit.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mnvoip.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://nnenix.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://nocix.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://ohioix.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://opencolo.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://southfront.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://volico.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = http://ziply.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://codingflyboy.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://coresite.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://forksystems.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://irltoolkit.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mnvoip.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://nnenix.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://nocix.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://ohioix.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://opencolo.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://southfront.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://volico.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://ziply.mm.fcix.net/archlinux/$repo/os/$arch
|
||||
#Server = https://losangeles.mirror.pkgbuild.com/$repo/os/$arch
|
||||
#Server = http://mirrors.gigenet.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.givebytes.net/archlinux/$repo/os/$arch
|
||||
#Server = https://arch.goober.cloud/$repo/os/$arch
|
||||
#Server = http://arch.hu.fo/archlinux/$repo/os/$arch
|
||||
#Server = https://arch.hu.fo/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.hugeblank.dev/$repo/os/$arch
|
||||
#Server = https://arch.hugeblank.dev/$repo/os/$arch
|
||||
#Server = http://repo.ialab.dsu.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://repo.ialab.dsu.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.iu13.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.iu13.net/archlinux/$repo/os/$arch
|
||||
#Server = https://arch.mirror.k0.ae/$repo/os/$arch
|
||||
#Server = http://mirrors.kernel.org/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.kernel.org/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.lahansons.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.sfo12.us.leaseweb.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.wdc1.us.leaseweb.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.sfo12.us.leaseweb.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.wdc1.us.leaseweb.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.liquidweb.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.lug.mtu.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.lug.mtu.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://m.lqy.me/arch/$repo/os/$arch
|
||||
#Server = https://arch.mirror.marcusspencer.us:4443/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.math.princeton.edu/pub/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.metrocast.net/archlinux/$repo/os/$arch
|
||||
#Server = http://arch.miningtcup.me/$repo/os/$arch
|
||||
#Server = https://arch.miningtcup.me/$repo/os/$arch
|
||||
#Server = https://mirrors.shr.cx/arch/$repo/os/$arch
|
||||
#Server = http://iad.mirrors.misaka.one/archlinux/$repo/os/$arch
|
||||
#Server = https://iad.mirrors.misaka.one/archlinux/$repo/os/$arch
|
||||
#Server = http://repo.miserver.it.umich.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.mit.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.mit.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.mra.sh/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.mra.sh/archlinux/$repo/os/$arch
|
||||
#Server = https://us.arch.niranjan.co/$repo/os/$arch
|
||||
#Server = http://mirrors.ocf.berkeley.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.ocf.berkeley.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://archmirror1.octyl.net/$repo/os/$arch
|
||||
#Server = https://archmirror1.octyl.net/$repo/os/$arch
|
||||
#Server = http://ftp.osuosl.org/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://ftp.osuosl.org/pub/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.pilotfiber.com/archlinux/$repo/os/$arch
|
||||
#Server = http://dfw.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = http://iad.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = http://ord.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = https://dfw.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = https://iad.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = https://ord.mirror.rackspace.com/archlinux/$repo/os/$arch
|
||||
#Server = http://plug-mirror.rcac.purdue.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://plug-mirror.rcac.purdue.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.rit.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.rit.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.siena.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.smeal.xyz/arch-linux/$repo/os/$arch
|
||||
#Server = https://mirrors.smeal.xyz/arch-linux/$repo/os/$arch
|
||||
#Server = http://mirrors.sonic.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.sonic.net/archlinux/$repo/os/$arch
|
||||
#Server = https://us-mnz.soulharsh007.dev/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.pit.teraswitch.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.pit.teraswitch.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.theash.xyz/arch/$repo/os/$arch
|
||||
#Server = http://mirror.umd.edu/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.umd.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.vectair.net/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.vectair.net/archlinux/$repo/os/$arch
|
||||
#Server = http://mirror.vtti.vt.edu/archlinux/$repo/os/$arch
|
||||
#Server = http://wcbmedia.io:8000/$repo/os/$arch
|
||||
#Server = http://mirrors.xmission.com/archlinux/$repo/os/$arch
|
||||
#Server = http://mirrors.xtom.com/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.xtom.com/archlinux/$repo/os/$arch
|
||||
#Server = https://yonderly.org/mirrors/archlinux/$repo/os/$arch
|
||||
#Server = https://mirror.zackmyers.io/archlinux/$repo/os/$arch
|
||||
#Server = https://zxcvfdsa.com/arch/$repo/os/$arch
|
||||
|
||||
## Uzbekistan
|
||||
#Server = http://mirror.dc.uz/arch/$repo/os/$arch
|
||||
#Server = https://mirror.dc.uz/arch/$repo/os/$arch
|
||||
|
||||
## Vietnam
|
||||
#Server = http://mirror.bizflycloud.vn/archlinux/$repo/os/$arch
|
||||
#Server = https://mirrors.huongnguyen.dev/arch/$repo/os/$arch
|
||||
#Server = https://mirror.meowsmp.net/arch/$repo/os/$arch
|
||||
#Server = https://mirrors.nguyenhoang.cloud/archlinux/$repo/os/$arch
|
||||
|
||||
13
x86_64/airootfs/etc/profile.d/stormux-accessibility.sh
Executable file
13
x86_64/airootfs/etc/profile.d/stormux-accessibility.sh
Executable file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
# Stormux accessibility environment variables
|
||||
# Available to all users and sessions
|
||||
|
||||
# Accessibility support
|
||||
export ACCESSIBILITY_ENABLED=1
|
||||
export GTK_MODULES=gail:atk-bridge:canberra-gtk-module
|
||||
export GNOME_ACCESSIBILITY=1
|
||||
export QT_ACCESSIBILITY=1
|
||||
export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1
|
||||
|
||||
# Dialog accessibility options
|
||||
export DIALOGOPTS='--no-lines --visit-items'
|
||||
59
x86_64/airootfs/etc/profile.d/stormux_first_boot.sh
Executable file
59
x86_64/airootfs/etc/profile.d/stormux_first_boot.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [[ "$(tty)" != "/dev/tty1" ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if [[ -x /opt/configure-stormux/configure-stormux.sh ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
if ! [[ -x /usr/local/bin/configure-stormux ]]; then
|
||||
return
|
||||
fi
|
||||
|
||||
# Volume calibration FIRST
|
||||
echo "Setting up audio volume..."
|
||||
volume=50
|
||||
wait=0
|
||||
|
||||
# Wait for pipewire to become available
|
||||
while [[ $wait -lt 30 ]]; do
|
||||
if pgrep pipewire &> /dev/null ; then
|
||||
break
|
||||
else
|
||||
sleep 1
|
||||
((wait++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Volume calibration - this should be the VERY FIRST interactive part
|
||||
while [[ $volume -le 130 ]]; do
|
||||
clear
|
||||
pactl set-sink-volume @DEFAULT_SINK@ "${volume}%" 2>/dev/null
|
||||
spd-say "If this is loud enough, press enter."
|
||||
if read -t4 ; then
|
||||
echo "Volume set to ${volume}%"
|
||||
break
|
||||
else
|
||||
((volume+=5))
|
||||
fi
|
||||
done
|
||||
|
||||
# For audible sudo prompts:
|
||||
unset sudoFlags
|
||||
if [[ -x /etc/audibleprompt.sh ]]; then
|
||||
export SUDO_ASKPASS=/etc/audibleprompt.sh
|
||||
export sudoFlags=("-A")
|
||||
fi
|
||||
|
||||
clear
|
||||
cat << "EOF"
|
||||
Hello, and welcome to Stormux!
|
||||
|
||||
Let's get you set up.
|
||||
|
||||
Please press enter to continue.
|
||||
EOF
|
||||
read -r
|
||||
sudo "${sudoFlags[@]}" configure-stormux
|
||||
4
x86_64/airootfs/etc/skel.custom/.bash_aliases
Normal file
4
x86_64/airootfs/etc/skel.custom/.bash_aliases
Normal file
@@ -0,0 +1,4 @@
|
||||
# Raspberry Pi Information
|
||||
alias pi-temp='/usr/bin/vcgencmd measure_temp'
|
||||
alias pi-version='cat /sys/firmware/devicetree/base/model;echo'
|
||||
alias pi-ip='ip a | grep -v "127.0.0.1" | grep -E -o "([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}"'
|
||||
21
x86_64/airootfs/etc/skel.custom/.bash_functions
Normal file
21
x86_64/airootfs/etc/skel.custom/.bash_functions
Normal file
@@ -0,0 +1,21 @@
|
||||
memuse() {
|
||||
ps axo rss,comm,pid \
|
||||
| awk '{ proc_list[$2] += $1; } END \
|
||||
{ for (proc in proc_list) { printf("%d\t%s\n", proc_list[proc],proc); }}' \
|
||||
| sort -n | tail -n 10 | sort -rn \
|
||||
| awk '{$1/=1024;printf "%.0fMB\t",$1}{print $2}'
|
||||
}
|
||||
|
||||
|
||||
pdf()
|
||||
{
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo 'Usage: pdf <file>' >&2
|
||||
else
|
||||
local dir=$(mktemp -d -p /tmp pdf_conversion.XXXXXX)
|
||||
local outFile="${1##*/}"
|
||||
local outFile="${outFile%.*}"
|
||||
pdftohtml -noframes -i -s "$1" "${dir}/${outFile}.html"
|
||||
w3m -s "${dir}/${outFile}.html"
|
||||
fi
|
||||
}
|
||||
24
x86_64/airootfs/etc/skel.custom/.bashrc
Normal file
24
x86_64/airootfs/etc/skel.custom/.bashrc
Normal file
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# ~/.bashrc
|
||||
#
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
[[ $- != *i* ]] && return
|
||||
|
||||
#Change directories without using cd
|
||||
shopt -s autocd
|
||||
|
||||
# Keep bash history in screen
|
||||
export HISTFILE="${HISTFILE}${WINDOW:+.${WINDOW}}"
|
||||
|
||||
# load Aliases and functions
|
||||
[[ -f ".bash_aliases" ]] && source .bash_aliases
|
||||
[[ -f ".bash_functions" ]] && source .bash_functions
|
||||
#Invironment variables
|
||||
PS1='[\u@\h \W] \$ '
|
||||
export DIALOGOPTS='--no-lines --visit-items'
|
||||
GPG_TTY=$(tty)
|
||||
export GPG_TTY
|
||||
# Don't put commands prefixed with space, or duplicate commands in history
|
||||
export HISTCONTROL=ignoreboth
|
||||
|
||||
6
x86_64/airootfs/etc/skel.custom/.inputrc
Normal file
6
x86_64/airootfs/etc/skel.custom/.inputrc
Normal file
@@ -0,0 +1,6 @@
|
||||
# Reload changes with control+x followed by control+r
|
||||
set echo-control-characters off
|
||||
|
||||
# History searching with up and down arrows.
|
||||
"\e[A": history-search-backward
|
||||
"\e[B": history-search-forward
|
||||
18
x86_64/airootfs/etc/skel.custom/.screenrc
Normal file
18
x86_64/airootfs/etc/skel.custom/.screenrc
Normal file
@@ -0,0 +1,18 @@
|
||||
vbell off
|
||||
bell_msg ""
|
||||
hardstatus off
|
||||
startup_message off
|
||||
defscrollback 4096
|
||||
bind ! select 10
|
||||
bind @ select 11
|
||||
bind \# select 12
|
||||
bind $ select 13
|
||||
bind % select 14
|
||||
bind ^ select 15
|
||||
bind & select 16
|
||||
bind * select 17
|
||||
bind ( select 18
|
||||
bind ) select 19
|
||||
bind b eval "writebuf" 'exec !!! xclip -selection "clipboard" -i /tmp/screen-exchange'
|
||||
#termcapinfo xterm|xterms|xs|rxvt ti@:te@
|
||||
termcapinfo xterm* ti@:te@
|
||||
43
x86_64/airootfs/etc/skel.stormux/.bashrc
Normal file
43
x86_64/airootfs/etc/skel.stormux/.bashrc
Normal file
@@ -0,0 +1,43 @@
|
||||
#
|
||||
# ~/.bashrc
|
||||
#
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
[[ $- != *i* ]] && return
|
||||
|
||||
# Change directories without using cd
|
||||
shopt -s autocd
|
||||
|
||||
# Load aliases and functions if they exist
|
||||
[[ -f "$HOME/.bash_aliases" ]] && . "$HOME/.bash_aliases"
|
||||
[[ -f "$HOME/.bash_functions" ]] && . "$HOME/.bash_functions"
|
||||
|
||||
# Environment variables
|
||||
export QT_ACCESSIBILITY=1
|
||||
export QT_LINUX_ACCESSIBILITY_ALWAYS_ON=1
|
||||
|
||||
# Set prompt
|
||||
PS1='[\u@\h \W] \$ '
|
||||
|
||||
# Dialog accessibility options
|
||||
export DIALOGOPTS='--no-lines --visit-items'
|
||||
|
||||
# Browser selection based on environment
|
||||
if [[ -z "$DISPLAY" ]]; then
|
||||
export BROWSER=w3m
|
||||
fi
|
||||
|
||||
# GPG TTY
|
||||
GPG_TTY=$(tty)
|
||||
export GPG_TTY
|
||||
|
||||
# Don't put commands prefixed with space, or duplicate commands in history
|
||||
export HISTCONTROL=ignoreboth
|
||||
|
||||
# Increase history size
|
||||
export HISTSIZE=10000
|
||||
export HISTFILESIZE=20000
|
||||
|
||||
# Add user's local bin directories to PATH
|
||||
PATH="$HOME/.local/bin:$HOME/bin:$PATH"
|
||||
export PATH
|
||||
25
x86_64/airootfs/etc/skel.stormux/.inputrc
Normal file
25
x86_64/airootfs/etc/skel.stormux/.inputrc
Normal file
@@ -0,0 +1,25 @@
|
||||
# ~/.inputrc
|
||||
# Readline configuration for bash
|
||||
# Reload changes with control+x followed by control+r
|
||||
|
||||
# Don't echo control characters
|
||||
set echo-control-characters off
|
||||
|
||||
# History searching with up and down arrows
|
||||
"\e[A": history-search-backward
|
||||
"\e[B": history-search-forward
|
||||
|
||||
# Shift+Tab sequences for console (backward menu completion)
|
||||
"\e[Z": menu-complete-backward
|
||||
"\eZ": menu-complete-backward
|
||||
# Alt+comma as alternative
|
||||
"\e,": menu-complete-backward
|
||||
|
||||
# Music player keybindings (requires playerctl)
|
||||
"\eX": "\C-k \C-u playerctl play\C-M"
|
||||
"\eC": "\C-k \C-u playerctl play-pause\C-M"
|
||||
"\eV": "\C-k \C-u playerctl stop\C-M"
|
||||
"\eB": "\C-k \C-u playerctl next\C-M"
|
||||
"\eU": "\C-k \C-u playerctl metadata -f '{{artist}} - {{album}} - {{title}}'\C-M"
|
||||
"\e_": "\C-k \C-u playerctl volume 0.05-\C-M"
|
||||
"\e+": "\C-k \C-u playerctl volume 0.05+\C-M"
|
||||
33
x86_64/airootfs/etc/skel.stormux/.screenrc
Normal file
33
x86_64/airootfs/etc/skel.stormux/.screenrc
Normal file
@@ -0,0 +1,33 @@
|
||||
# ~/.screenrc
|
||||
# GNU Screen configuration
|
||||
|
||||
# Disable visual bell
|
||||
vbell off
|
||||
bell_msg ""
|
||||
|
||||
# Disable hardstatus
|
||||
hardstatus off
|
||||
|
||||
# Disable startup message
|
||||
startup_message off
|
||||
|
||||
# Set scrollback buffer size
|
||||
defscrollback 4096
|
||||
|
||||
# Extended window numbering (0-19 instead of 0-9)
|
||||
bind ! select 10
|
||||
bind @ select 11
|
||||
bind \# select 12
|
||||
bind $ select 13
|
||||
bind % select 14
|
||||
bind ^ select 15
|
||||
bind & select 16
|
||||
bind * select 17
|
||||
bind ( select 18
|
||||
bind ) select 19
|
||||
|
||||
# Copy buffer to system clipboard (requires xclip)
|
||||
bind b eval "writebuf" 'exec !!! xclip -selection "clipboard" -i /tmp/screen-exchange'
|
||||
|
||||
# Disable alternate screen switching (allows scrollback in terminal)
|
||||
termcapinfo xterm* ti@:te@
|
||||
29
x86_64/airootfs/etc/skel.stormux/.vim/dates.vim
Normal file
29
x86_64/airootfs/etc/skel.stormux/.vim/dates.vim
Normal file
@@ -0,0 +1,29 @@
|
||||
" Date and time insertion functions
|
||||
|
||||
" Insert current date in format: Wednesday, January 15, 2025
|
||||
function! InsertDate()
|
||||
let date_string = strftime("%A, %B %d, %Y")
|
||||
execute "normal! a" . date_string
|
||||
endfunction
|
||||
|
||||
" Insert current time in format: 09:15PM
|
||||
function! InsertTime()
|
||||
let time_string = strftime("%I:%M%p")
|
||||
execute "normal! a" . time_string
|
||||
endfunction
|
||||
|
||||
" Insert current date and time in format: Wednesday, January 15, 2025, 09:15PM
|
||||
function! InsertDateTime()
|
||||
let datetime_string = strftime("%A, %B %d, %Y, %I:%M%p")
|
||||
execute "normal! a" . datetime_string
|
||||
endfunction
|
||||
|
||||
" Key mappings
|
||||
nnoremap <leader>date :call InsertDate()<CR>
|
||||
inoremap <leader>date <C-o>:call InsertDate()<CR>
|
||||
|
||||
nnoremap <leader>time :call InsertTime()<CR>
|
||||
inoremap <leader>time <C-o>:call InsertTime()<CR>
|
||||
|
||||
nnoremap <leader>datetime :call InsertDateTime()<CR>
|
||||
inoremap <leader>datetime <C-o>:call InsertDateTime()<CR>
|
||||
39
x86_64/airootfs/etc/skel.stormux/.vim/emoji.vim
Normal file
39
x86_64/airootfs/etc/skel.stormux/.vim/emoji.vim
Normal file
@@ -0,0 +1,39 @@
|
||||
" Emoji insertion mappings
|
||||
|
||||
" Basic expressions
|
||||
inoremap ,:) 😊
|
||||
inoremap ,:( 😢
|
||||
inoremap ,:D 😃
|
||||
inoremap ,;) 😉
|
||||
inoremap ,:P 😛
|
||||
inoremap ,:o 😮
|
||||
inoremap ,:\| 😐
|
||||
|
||||
" Hearts and love
|
||||
inoremap ,<3 ❤️
|
||||
inoremap ,heart ❤️
|
||||
inoremap ,love 💕
|
||||
inoremap ,kiss 😘
|
||||
|
||||
" Special expressions
|
||||
inoremap ,>:) 😈
|
||||
inoremap ,devil 😈
|
||||
inoremap ,:* 😘
|
||||
inoremap ,cool 😎
|
||||
inoremap ,nerd 🤓
|
||||
inoremap ,angry 😠
|
||||
|
||||
" Hands and gestures
|
||||
inoremap ,thumbs 👍
|
||||
inoremap ,clap 👏
|
||||
inoremap ,wave 👋
|
||||
inoremap ,peace ✌️
|
||||
inoremap ,pray 🙏
|
||||
|
||||
" Common symbols
|
||||
inoremap ,check ✅
|
||||
inoremap ,x ❌
|
||||
inoremap ,star ⭐
|
||||
inoremap ,fire 🔥
|
||||
inoremap ,rocket 🚀
|
||||
inoremap ,tada 🎉
|
||||
0
x86_64/airootfs/etc/skel.stormux/.vim/swap/.gitkeep
Normal file
0
x86_64/airootfs/etc/skel.stormux/.vim/swap/.gitkeep
Normal file
77
x86_64/airootfs/etc/skel.stormux/.vimrc
Normal file
77
x86_64/airootfs/etc/skel.stormux/.vimrc
Normal file
@@ -0,0 +1,77 @@
|
||||
" ~/.vimrc
|
||||
" Vim configuration for Stormux
|
||||
|
||||
" Ensure vim directory structure exists
|
||||
" mkdir -p ~/.vim/{backup,swap,views}
|
||||
|
||||
set nocompatible " Use Vim settings (not Vi compatible)
|
||||
filetype off " Required for some plugins
|
||||
|
||||
" Terminal and encoding
|
||||
set term=linux " Make arrow and other keys work
|
||||
scriptencoding utf-8
|
||||
|
||||
" History and undo
|
||||
set history=1000 " Store more history (default is 20)
|
||||
set undoreload=10000 " Maximum lines to save for undo on buffer reload
|
||||
|
||||
" Backup and swap file configuration
|
||||
set backup " Enable backups
|
||||
set backupdir=$HOME/.vim/backup//
|
||||
set directory=$HOME/.vim/swap//
|
||||
set viewdir=$HOME/.vim/views//
|
||||
|
||||
" Search settings
|
||||
set ignorecase " Case insensitive search
|
||||
set smartcase " Case sensitive when uppercase present
|
||||
set gdefault " /g flag on :s substitutions by default
|
||||
|
||||
" Spell checking
|
||||
set spell " Enable spell checking
|
||||
|
||||
" Display settings
|
||||
set wrap " Wrap long lines
|
||||
set linebreak " Break lines at word boundaries
|
||||
set noruler " Disable ruler (for accessibility)
|
||||
set laststatus=0 " Never show status line
|
||||
set noshowcmd " Don't show commands in status
|
||||
|
||||
" Indentation settings
|
||||
set shiftwidth=4 " Use indents of 4 spaces
|
||||
set expandtab " Tabs are spaces, not tabs
|
||||
set tabstop=4 " An indentation every four columns
|
||||
set softtabstop=4 " Let backspace delete indent
|
||||
|
||||
" Leader key
|
||||
let mapleader = ','
|
||||
|
||||
" Remap semicolon to colon for easier commands
|
||||
nnoremap ; :
|
||||
|
||||
" Yank from cursor to end of line (consistent with C and D)
|
||||
nnoremap Y y$
|
||||
|
||||
" Em-dash insertion
|
||||
inoremap ,- —
|
||||
|
||||
" Working directory shortcuts
|
||||
cmap cwd lcd %:p:h
|
||||
cmap cd. lcd %:p:h
|
||||
|
||||
" Write with sudo if you forgot to open with sudo
|
||||
cmap w!! w !sudo tee % >/dev/null
|
||||
|
||||
" Disable automatic comment continuation
|
||||
autocmd FileType * setlocal formatoptions-=c formatoptions-=r formatoptions-=o
|
||||
|
||||
" Load vim helper functions if they exist
|
||||
if filereadable(expand("~/.vim/dates.vim"))
|
||||
source ~/.vim/dates.vim
|
||||
endif
|
||||
|
||||
if filereadable(expand("~/.vim/emoji.vim"))
|
||||
source ~/.vim/emoji.vim
|
||||
endif
|
||||
|
||||
" Enable filetype detection and indenting
|
||||
filetype plugin indent on
|
||||
@@ -0,0 +1,7 @@
|
||||
# SSH configuration for Stormux Live ISO
|
||||
# This configuration allows root login for the live environment
|
||||
# Users should change the root password and disable this after installation
|
||||
|
||||
PermitRootLogin yes
|
||||
PasswordAuthentication yes
|
||||
ChallengeResponseAuthentication no
|
||||
15
x86_64/airootfs/etc/stormux-assist/client.conf
Normal file
15
x86_64/airootfs/etc/stormux-assist/client.conf
Normal file
@@ -0,0 +1,15 @@
|
||||
# Stormux Assistance System - Client Configuration
|
||||
|
||||
[server]
|
||||
host = assistance.stormux.org
|
||||
ssh_port = 22
|
||||
ssh_user = stormux-assist
|
||||
tunnel_port = 2222
|
||||
|
||||
[session]
|
||||
# Session timeout in seconds (14400 = 4 hours)
|
||||
timeout = 14400
|
||||
|
||||
[client]
|
||||
log_file = /var/log/sas.log
|
||||
log_dir = ~/stormux-assist-logs/
|
||||
1
x86_64/airootfs/etc/sudoers.d/wheel
Normal file
1
x86_64/airootfs/etc/sudoers.d/wheel
Normal file
@@ -0,0 +1 @@
|
||||
%wheel ALL=(ALL:ALL) ALL
|
||||
1
x86_64/airootfs/etc/sysctl.d/20-quiet-printk.conf
Normal file
1
x86_64/airootfs/etc/sysctl.d/20-quiet-printk.conf
Normal file
@@ -0,0 +1 @@
|
||||
kernel.printk = 3 3 3 3
|
||||
@@ -0,0 +1,3 @@
|
||||
[Journal]
|
||||
Storage=volatile
|
||||
SystemMaxUse=20M
|
||||
2
x86_64/airootfs/etc/systemd/resolved.conf.d/dnssec.conf
Normal file
2
x86_64/airootfs/etc/systemd/resolved.conf.d/dnssec.conf
Normal file
@@ -0,0 +1,2 @@
|
||||
[Resolve]
|
||||
DNSSEC=no
|
||||
@@ -0,0 +1,5 @@
|
||||
[Unit]
|
||||
# Ensure audio and speech-dispatcher are available before starting Fenrir
|
||||
# Wait for user audio initialization to complete
|
||||
After=sound.target stormux-audio-setup.service speech-dispatcherd.service user@1000.service
|
||||
Wants=stormux-audio-setup.service speech-dispatcherd.service user@1000.service
|
||||
@@ -0,0 +1 @@
|
||||
/usr/lib/systemd/system/fenrirscreenreader.service
|
||||
@@ -0,0 +1,3 @@
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=-/sbin/agetty -o '-p -f -- \\u' --noclear --autologin root - $TERM
|
||||
@@ -0,0 +1,3 @@
|
||||
[Service]
|
||||
ExecStart=
|
||||
ExecStart=-/sbin/agetty -o '-p -f -- \\u' --noclear --autologin stormux - $TERM
|
||||
16
x86_64/airootfs/etc/systemd/system/log-to-ram-setup.service
Normal file
16
x86_64/airootfs/etc/systemd/system/log-to-ram-setup.service
Normal file
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Setup RAM logging and restore logs from disk
|
||||
DefaultDependencies=false
|
||||
After=local-fs.target
|
||||
Before=sysinit.target
|
||||
RequiresMountsFor=/var
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStartPre=/bin/mkdir -p /var/log.hdd
|
||||
ExecStartPre=/bin/sh -c 'if [ -d /var/log.hdd ] && [ "$(ls -A /var/log.hdd 2>/dev/null)" ]; then cp -au /var/log.hdd/* /var/log/ 2>/dev/null || true; fi'
|
||||
ExecStart=/bin/true
|
||||
|
||||
[Install]
|
||||
WantedBy=sysinit.target
|
||||
@@ -0,0 +1,14 @@
|
||||
[Unit]
|
||||
Description=Sync logs to disk before shutdown
|
||||
DefaultDependencies=false
|
||||
Before=shutdown.target reboot.target halt.target
|
||||
Conflicts=shutdown.target reboot.target halt.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=true
|
||||
ExecStart=/bin/sh -c 'rsync -aXv --delete --exclude="*.hdd" /var/log/ /var/log.hdd/ 2>/dev/null || true'
|
||||
TimeoutStopSec=30
|
||||
|
||||
[Install]
|
||||
WantedBy=shutdown.target reboot.target halt.target
|
||||
@@ -0,0 +1,8 @@
|
||||
[Unit]
|
||||
Description=Sync logs from RAM to disk
|
||||
After=local-fs.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStartPre=/bin/mkdir -p /var/log.hdd
|
||||
ExecStart=/bin/sh -c 'rsync -aXv --delete --exclude="*.hdd" /var/log/ /var/log.hdd/ 2>/dev/null || true'
|
||||
11
x86_64/airootfs/etc/systemd/system/log-to-ram-sync.timer
Normal file
11
x86_64/airootfs/etc/systemd/system/log-to-ram-sync.timer
Normal file
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Sync logs from RAM to disk every hour
|
||||
Requires=log-to-ram-sync.service
|
||||
|
||||
[Timer]
|
||||
OnBootSec=15min
|
||||
OnUnitActiveSec=1h
|
||||
Persistent=true
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1 @@
|
||||
/usr/lib/systemd/system/NetworkManager.service
|
||||
@@ -0,0 +1 @@
|
||||
/usr/lib/systemd/system/brltty.path
|
||||
@@ -0,0 +1 @@
|
||||
../ssh-login-monitor.service
|
||||
@@ -0,0 +1 @@
|
||||
../stormux-repo-init.service
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Setup Pipewire for Live Environment
|
||||
After=sound.target
|
||||
Before=fenrirscreenreader.service speech-dispatcherd.service
|
||||
DefaultDependencies=no
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/local/bin/setup-pipewire-live.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1 @@
|
||||
/usr/lib/systemd/system/sshd.socket
|
||||
@@ -0,0 +1 @@
|
||||
../stormux-audio-setup.service
|
||||
17
x86_64/airootfs/etc/systemd/system/ssh-login-monitor.service
Normal file
17
x86_64/airootfs/etc/systemd/system/ssh-login-monitor.service
Normal file
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Fenrir SSH Login Monitor
|
||||
After=sshd.service
|
||||
Wants=sshd.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/share/fenrirscreenreader/scripts/ssh-login-monitor.sh
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# Security settings
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=false
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,17 @@
|
||||
[Unit]
|
||||
Description=Setup audio for Stormux live environment
|
||||
# Wait for audio hardware to be ready
|
||||
Wants=systemd-udev-settle.service
|
||||
After=systemd-udev-settle.service sound.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
# Enable linger so pipewire can run without login
|
||||
ExecStartPre=/bin/mkdir -p /var/lib/systemd/linger
|
||||
ExecStartPre=/bin/touch /var/lib/systemd/linger/stormux
|
||||
# Unmute and set volume
|
||||
ExecStart=/usr/local/bin/livecd-sound
|
||||
|
||||
[Install]
|
||||
WantedBy=sound.target
|
||||
13
x86_64/airootfs/etc/systemd/system/stormux-repo-init.service
Normal file
13
x86_64/airootfs/etc/systemd/system/stormux-repo-init.service
Normal file
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Initialize Stormux repository key
|
||||
After=pacman-init.service
|
||||
Requires=pacman-init.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/bin/pacman-key --add /usr/share/stormux/stormux_repo.pub
|
||||
ExecStart=/usr/bin/pacman-key --lsign-key 52ADA49000F1FF0456F8AEEFB4CDE1CD56EF8E82
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
16
x86_64/airootfs/etc/systemd/system/stormux-speech.service
Normal file
16
x86_64/airootfs/etc/systemd/system/stormux-speech.service
Normal file
@@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Stormux screen reader and speech service
|
||||
After=stormux-audio-setup.service sound.target
|
||||
Wants=stormux-audio-setup.service
|
||||
Before=getty@tty1.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
# Give pipewire a moment to initialize
|
||||
ExecStartPre=/bin/sleep 2
|
||||
# Start Fenrir screen reader
|
||||
ExecStart=/bin/systemctl start fenrirscreenreader.service
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
1
x86_64/airootfs/etc/systemd/system/systemd-firstboot.service
Symbolic link
1
x86_64/airootfs/etc/systemd/system/systemd-firstboot.service
Symbolic link
@@ -0,0 +1 @@
|
||||
/dev/null
|
||||
11
x86_64/airootfs/etc/systemd/system/time_sync_at_boot.service
Normal file
11
x86_64/airootfs/etc/systemd/system/time_sync_at_boot.service
Normal file
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Update system time from worldtimeapi.org
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/usr/local/bin/sync_time.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
1
x86_64/airootfs/etc/udev/rules.d/99-brltty.rules
Normal file
1
x86_64/airootfs/etc/udev/rules.d/99-brltty.rules
Normal file
@@ -0,0 +1 @@
|
||||
SUBSYSTEM=="tty", KERNEL=="tty[0-9]*|hvc[0-9]*|sclp_line[0-9]*|ttysclp[0-9]*|3270/tty[0-9]*", GROUP="tty", MODE="0620"
|
||||
3
x86_64/airootfs/etc/vconsole.conf
Normal file
3
x86_64/airootfs/etc/vconsole.conf
Normal file
@@ -0,0 +1,3 @@
|
||||
# This is the fallback vconsole configuration provided by systemd.
|
||||
|
||||
KEYMAP=us_alt
|
||||
@@ -0,0 +1,31 @@
|
||||
-- Prioritize analog and USB audio devices over HDMI
|
||||
-- This ensures real sound cards are selected by default
|
||||
|
||||
rule = {
|
||||
matches = {
|
||||
{
|
||||
{ "device.form-factor", "equals", "internal" },
|
||||
},
|
||||
{
|
||||
{ "device.form-factor", "equals", "speaker" },
|
||||
},
|
||||
{
|
||||
{ "device.form-factor", "equals", "headphone" },
|
||||
},
|
||||
{
|
||||
{ "device.bus", "equals", "usb" },
|
||||
},
|
||||
{
|
||||
{ "node.name", "matches", "alsa_output.pci-*analog*" },
|
||||
},
|
||||
{
|
||||
{ "node.name", "matches", "alsa_output.usb-*" },
|
||||
},
|
||||
},
|
||||
apply_properties = {
|
||||
["priority.driver"] = 1000,
|
||||
["priority.session"] = 1000,
|
||||
},
|
||||
}
|
||||
|
||||
table.insert(alsa_monitor.rules, rule)
|
||||
@@ -0,0 +1,22 @@
|
||||
-- Deprioritize HDMI audio devices
|
||||
-- This ensures analog/USB audio devices are preferred over HDMI
|
||||
|
||||
rule = {
|
||||
matches = {
|
||||
{
|
||||
{ "device.name", "matches", "hdmi*" },
|
||||
},
|
||||
{
|
||||
{ "device.name", "matches", "HDMI*" },
|
||||
},
|
||||
{
|
||||
{ "node.name", "matches", "alsa_output.pci-*hdmi*" },
|
||||
},
|
||||
},
|
||||
apply_properties = {
|
||||
["priority.driver"] = 100,
|
||||
["priority.session"] = 100,
|
||||
},
|
||||
}
|
||||
|
||||
table.insert(alsa_monitor.rules, rule)
|
||||
4
x86_64/airootfs/home/stormux/.bash_aliases
Normal file
4
x86_64/airootfs/home/stormux/.bash_aliases
Normal file
@@ -0,0 +1,4 @@
|
||||
# Raspberry Pi Information
|
||||
alias pi-temp='/usr/bin/vcgencmd measure_temp'
|
||||
alias pi-version='cat /sys/firmware/devicetree/base/model;echo'
|
||||
alias pi-ip='ip a | grep -v "127.0.0.1" | grep -E -o "([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}"'
|
||||
21
x86_64/airootfs/home/stormux/.bash_functions
Normal file
21
x86_64/airootfs/home/stormux/.bash_functions
Normal file
@@ -0,0 +1,21 @@
|
||||
memuse() {
|
||||
ps axo rss,comm,pid \
|
||||
| awk '{ proc_list[$2] += $1; } END \
|
||||
{ for (proc in proc_list) { printf("%d\t%s\n", proc_list[proc],proc); }}' \
|
||||
| sort -n | tail -n 10 | sort -rn \
|
||||
| awk '{$1/=1024;printf "%.0fMB\t",$1}{print $2}'
|
||||
}
|
||||
|
||||
|
||||
pdf()
|
||||
{
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo 'Usage: pdf <file>' >&2
|
||||
else
|
||||
local dir=$(mktemp -d -p /tmp pdf_conversion.XXXXXX)
|
||||
local outFile="${1##*/}"
|
||||
local outFile="${outFile%.*}"
|
||||
pdftohtml -noframes -i -s "$1" "${dir}/${outFile}.html"
|
||||
w3m -s "${dir}/${outFile}.html"
|
||||
fi
|
||||
}
|
||||
24
x86_64/airootfs/home/stormux/.bashrc
Normal file
24
x86_64/airootfs/home/stormux/.bashrc
Normal file
@@ -0,0 +1,24 @@
|
||||
#
|
||||
# ~/.bashrc
|
||||
#
|
||||
|
||||
# If not running interactively, don't do anything
|
||||
[[ $- != *i* ]] && return
|
||||
|
||||
#Change directories without using cd
|
||||
shopt -s autocd
|
||||
|
||||
# Keep bash history in screen
|
||||
export HISTFILE="${HISTFILE}${WINDOW:+.${WINDOW}}"
|
||||
|
||||
# load Aliases and functions
|
||||
[[ -f ".bash_aliases" ]] && source .bash_aliases
|
||||
[[ -f ".bash_functions" ]] && source .bash_functions
|
||||
#Invironment variables
|
||||
PS1='[\u@\h \W] \$ '
|
||||
export DIALOGOPTS='--no-lines --visit-items'
|
||||
GPG_TTY=$(tty)
|
||||
export GPG_TTY
|
||||
# Don't put commands prefixed with space, or duplicate commands in history
|
||||
export HISTCONTROL=ignoreboth
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# Fenrir console audio support
|
||||
# Adds secondary socket for console applications like Fenrir
|
||||
|
||||
pulse.properties = {
|
||||
# the addresses this server listens on
|
||||
server.address = [
|
||||
"unix:native"
|
||||
"unix:/tmp/pulse.sock" # console access socket
|
||||
]
|
||||
}
|
||||
|
||||
# client/stream specific properties
|
||||
pulse.rules = [
|
||||
{
|
||||
# speech dispatcher asks for too small latency and then underruns.
|
||||
matches = [ { application.name = "~speech-dispatcher*" } ]
|
||||
actions = {
|
||||
update-props = {
|
||||
pulse.min.req = 1024/48000 # 21ms
|
||||
pulse.min.quantum = 1024/48000 # 21ms
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
../pipewire-init-sound.service
|
||||
@@ -0,0 +1,12 @@
|
||||
[Unit]
|
||||
Description=Initialize Pipewire Audio with Sound Test
|
||||
After=pipewire.service pipewire-pulse.service wireplumber.service
|
||||
Wants=pipewire.service pipewire-pulse.service wireplumber.service
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/local/bin/init-pipewire-sound.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,24 @@
|
||||
# Fenrir console audio support
|
||||
# Prevents bluetooth disconnection when switching TTY
|
||||
|
||||
monitor.bluez.properties = {
|
||||
# Disable logind integration to prevent bluetooth device suspension on TTY switch
|
||||
bluez5.enable-sbc-xq = true
|
||||
bluez5.enable-msbc = true
|
||||
bluez5.enable-hw-volume = true
|
||||
}
|
||||
|
||||
monitor.bluez.rules = [
|
||||
{
|
||||
matches = [
|
||||
{
|
||||
device.name = "~bluez_card.*"
|
||||
}
|
||||
]
|
||||
actions = {
|
||||
update-props = {
|
||||
session.suspend-timeout-seconds = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user