diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d0966d9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,81 @@ +name: CI Build Test + +on: + pull_request: + branches: [master] + workflow_dispatch: # manual trigger from GitHub Actions UI + +permissions: + contents: read + +jobs: + build-deb: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - arch: amd64 + docker_platform: linux/amd64 + - arch: arm64 + docker_platform: linux/arm64 + - arch: armhf + docker_platform: linux/arm/v7 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Build .deb package + run: | + docker run --rm --platform ${{ matrix.docker_platform }} \ + -v "$PWD":/build -w /build \ + debian:bookworm bash -c ' + set -e + apt-get update + apt-get install -y --no-install-recommends \ + build-essential debhelper libudev-dev + dpkg-buildpackage -us -uc -b + echo "=== .deb build successful ===" + for deb in ../*.deb; do dpkg-deb --info "$deb"; done + ' + + build-rpm: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - arch: x86_64 + docker_platform: linux/amd64 + - arch: aarch64 + docker_platform: linux/arm64 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Build .rpm package + run: | + docker run --rm --platform ${{ matrix.docker_platform }} \ + -v "$PWD":/build -w /build \ + rockylinux:9 bash -c ' + set -e + dnf install -y gcc-c++ make systemd-devel rpm-build systemd-rpm-macros + mkdir -p /root/rpmbuild/{SOURCES,SPECS} + tar czf /root/rpmbuild/SOURCES/mediasmartserver-0.6.0.tar.gz \ + --transform "s,^\.,mediasmartserver-0.6.0," \ + --exclude=.git . + cp rpm/mediasmartserver.spec /root/rpmbuild/SPECS/ + rpmbuild -bb --define "_version 0.6.0" /root/rpmbuild/SPECS/mediasmartserver.spec + echo "=== .rpm build successful ===" + rpm -qip /root/rpmbuild/RPMS/*/*.rpm + ' diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..a78a1ae --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,302 @@ +name: Build & Release + +on: + push: + tags: + - 'v*' + +permissions: + contents: write + pages: write + id-token: write + +jobs: + build: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - arch: amd64 + docker_platform: linux/amd64 + - arch: arm64 + docker_platform: linux/arm64 + - arch: armhf + docker_platform: linux/arm/v7 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Extract version from tag + id: version + run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + + - name: Build .deb package + run: | + docker run --rm --platform ${{ matrix.docker_platform }} \ + -v "$PWD":/build -w /build \ + debian:bookworm bash -c ' + set -e + apt-get update + apt-get install -y --no-install-recommends \ + build-essential debhelper libudev-dev + # Update changelog version from tag + sed -i "1s/([^)]*)/('"${{ steps.version.outputs.version }}"'-1)/" debian/changelog + dpkg-buildpackage -us -uc -b + mkdir -p output + mv ../*.deb output/ + ' + + - name: Upload .deb artifact + uses: actions/upload-artifact@v4 + with: + name: deb-${{ matrix.arch }} + path: output/*.deb + + build-rpm: + runs-on: ubuntu-latest + strategy: + matrix: + include: + - arch: x86_64 + docker_platform: linux/amd64 + - arch: aarch64 + docker_platform: linux/arm64 + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Extract version from tag + id: version + run: echo "version=${GITHUB_REF_NAME#v}" >> "$GITHUB_OUTPUT" + + - name: Build .rpm package + run: | + docker run --rm --platform ${{ matrix.docker_platform }} \ + -v "$PWD":/build -w /build \ + rockylinux:9 bash -c ' + set -e + dnf install -y gcc-c++ make systemd-devel rpm-build systemd-rpm-macros + VERSION='"${{ steps.version.outputs.version }}"' + # Create source tarball + mkdir -p /root/rpmbuild/{SOURCES,SPECS} + tar czf /root/rpmbuild/SOURCES/mediasmartserver-${VERSION}.tar.gz \ + --transform "s,^\.,mediasmartserver-${VERSION}," \ + --exclude=.git . + cp rpm/mediasmartserver.spec /root/rpmbuild/SPECS/ + rpmbuild -bb --define "_version ${VERSION}" /root/rpmbuild/SPECS/mediasmartserver.spec + mkdir -p /build/output + cp /root/rpmbuild/RPMS/*/*.rpm /build/output/ + ' + + - name: Upload .rpm artifact + uses: actions/upload-artifact@v4 + with: + name: rpm-${{ matrix.arch }} + path: output/*.rpm + + release: + needs: [build, build-rpm] + runs-on: ubuntu-latest + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: packages + merge-multiple: true + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + files: | + packages/*.deb + packages/*.rpm + generate_release_notes: true + + publish-repos: + needs: [build, build-rpm] + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + ref: gh-pages + fetch-depth: 0 + continue-on-error: true + + - name: Initialize gh-pages if needed + run: | + if [ ! -f index.html ]; then + git init + git checkout -b gh-pages + fi + + - name: Download deb artifacts + uses: actions/download-artifact@v4 + with: + pattern: deb-* + path: incoming-deb + merge-multiple: true + + - name: Download rpm artifacts + uses: actions/download-artifact@v4 + with: + pattern: rpm-* + path: incoming-rpm + merge-multiple: true + + - name: Install repo tools + run: sudo apt-get update && sudo apt-get install -y reprepro createrepo-c + + - name: Import or generate GPG key + run: | + if [ -n "${{ secrets.GPG_PRIVATE_KEY }}" ]; then + echo "${{ secrets.GPG_PRIVATE_KEY }}" | gpg --batch --import + GPG_KEY_ID=$(gpg --list-secret-keys --keyid-format long | grep sec | head -1 | awk '{print $2}' | cut -d'/' -f2) + else + # Generate a temporary key for signing (user should replace with proper key) + cat > /tmp/gpg-batch <> "$GITHUB_ENV" + gpg --armor --export "$GPG_KEY_ID" > gpg.key + + - name: Configure reprepro + run: | + mkdir -p conf + cat > conf/distributions </dev/null || true + createrepo_c rpm/ + gpg --batch --pinentry-mode loopback --detach-sign --armor rpm/repodata/repomd.xml + + - name: Create index page + run: | + cat > index.html <<'HTMLEOF' + + + mediasmartserverd Package Repository + +

mediasmartserverd Package Repository

+ +

Debian / Ubuntu / Mint (apt)

+

Quick Install

+
+          curl -fsSL https://amd989.github.io/mediasmartserverd/setup.sh | sudo bash
+          sudo apt install mediasmartserver
+          
+

Manual Setup

+
+          curl -fsSL https://amd989.github.io/mediasmartserverd/gpg.key | sudo gpg --dearmor -o /usr/share/keyrings/mediasmartserverd.gpg
+          echo "deb [signed-by=/usr/share/keyrings/mediasmartserverd.gpg] https://amd989.github.io/mediasmartserverd stable main" | sudo tee /etc/apt/sources.list.d/mediasmartserverd.list
+          sudo apt update
+          sudo apt install mediasmartserver
+          
+ +

Rocky Linux / RHEL / Fedora (dnf)

+

Quick Install

+
+          curl -fsSL https://amd989.github.io/mediasmartserverd/setup-rpm.sh | sudo bash
+          sudo dnf install mediasmartserver
+          
+

Manual Setup

+
+          sudo rpm --import https://amd989.github.io/mediasmartserverd/gpg.key
+          sudo tee /etc/yum.repos.d/mediasmartserverd.repo <<EOF
+          [mediasmartserverd]
+          name=mediasmartserverd
+          baseurl=https://amd989.github.io/mediasmartserverd/rpm/
+          enabled=1
+          gpgcheck=1
+          gpgkey=https://amd989.github.io/mediasmartserverd/gpg.key
+          EOF
+          sudo dnf install mediasmartserver
+          
+ + + HTMLEOF + + - name: Create APT setup script + run: | + cat > setup.sh <<'SETUPEOF' + #!/bin/bash + set -e + echo "Adding mediasmartserverd APT repository..." + curl -fsSL https://amd989.github.io/mediasmartserverd/gpg.key | gpg --dearmor -o /usr/share/keyrings/mediasmartserverd.gpg + echo "deb [signed-by=/usr/share/keyrings/mediasmartserverd.gpg] https://amd989.github.io/mediasmartserverd stable main" > /etc/apt/sources.list.d/mediasmartserverd.list + apt-get update + echo "Done! You can now run: sudo apt install mediasmartserver" + SETUPEOF + chmod +x setup.sh + + - name: Create DNF setup script + run: | + cat > setup-rpm.sh <<'SETUPEOF' + #!/bin/bash + set -e + echo "Adding mediasmartserverd YUM/DNF repository..." + rpm --import https://amd989.github.io/mediasmartserverd/gpg.key + cat > /etc/yum.repos.d/mediasmartserverd.repo < Mon, 17 Mar 2026 00:00:00 +0000 + mediasmartserver (0.5.6-1ubuntu1~raring) raring; urgency=low * ATA index may be different from the host one diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7f8f011..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -7 diff --git a/debian/control b/debian/control index 64bf34e..09857a3 100644 --- a/debian/control +++ b/debian/control @@ -1,31 +1,20 @@ Source: mediasmartserver Section: utils -Priority: extra -Maintainer: Marlen Antonyan -Build-Depends: debhelper, libudev-dev, g++ (>= 4:4.3.1) -Standards-Version: 3.9.3 -Homepage: https://github.com/merelin/mediasmartserverd.git -#Vcs-Git: git://git.debian.org/collab-maint/mediasmartserver.git -#Vcs-Browser: http://git.debian.org/?p=collab-maint/mediasmartserver.git;a=summary +Priority: optional +Maintainer: amd989 +Build-Depends: debhelper-compat (= 13), libudev-dev, g++ +Standards-Version: 4.6.2 +Homepage: https://github.com/amd989/mediasmartserverd +Vcs-Git: https://github.com/amd989/mediasmartserverd.git +Vcs-Browser: https://github.com/amd989/mediasmartserverd Package: mediasmartserver Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libudev0, upstart-job, update-notifier-common -Description: This is a Linux daemon that controls the status LEDs - of the HP MediaSmart Server ex48X and Acer Aspire easyStore H340. - The driver has been published at the following forum topic: +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: LED status daemon for HP MediaSmart Server and compatible hardware + Linux daemon that controls drive bay status LEDs on HP MediaSmart Server + EX48X, Acer H340/H341/H342, Acer Altos easyStore M2, and Lenovo IdeaCentre + D400. Also supports Arduino-based USB serial LED control for custom builds. . - http://www.mediasmartserver.net/forums/viewtopic.php?f=23&t=7720 - . - The packaged version contains the original code from the repository: - . - https://bitbucket.org/adaptation/mediasmartserverd/wiki/Home - . - with activity-v2.patch.txt applied - and my fixes for: - - incorrect bay index detection - - incorrect hot-swap drives detection upon addition and removal. - . - I would like to thank all the guys from the topic for their work. - . - Built from the https://github.com/merelin/mediasmartserverd.git repository. + Monitors disk presence and activity via udev/sysfs, provides system update + notifications via LED colors, and supports light show animations. diff --git a/debian/mediasmartserver.install b/debian/mediasmartserver.install index 99956ae..66e7f0c 100644 --- a/debian/mediasmartserver.install +++ b/debian/mediasmartserver.install @@ -1,3 +1,2 @@ mediasmartserverd /usr/sbin lib/systemd/system/mediasmartserver.service /lib/systemd/system -etc/init/mediasmartserver.conf /etc/init diff --git a/debian/postinst b/debian/postinst index 58e0993..229156a 100644 --- a/debian/postinst +++ b/debian/postinst @@ -1,37 +1,11 @@ #!/bin/sh -# postinst script for mediasmartserver -# -# see: dh_installdeb(1) - set -e -# summary of how this script can be called: -# * `configure' -# * `abort-upgrade' -# * `abort-remove' `in-favour' -# -# * `abort-remove' -# * `abort-deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - case "$1" in configure) - INIT=$(ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'upstart') - case "$INIT" in - systemd) - systemctl daemon-reload - systemctl enable mediasmartserver - systemctl start mediasmartserver - ;; - - *) - start mediasmartserver - ;; - esac + systemctl daemon-reload + systemctl enable mediasmartserver + systemctl start mediasmartserver ;; abort-upgrade|abort-remove|abort-deconfigure) @@ -43,9 +17,6 @@ case "$1" in ;; esac -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - #DEBHELPER# exit 0 diff --git a/debian/preinst b/debian/preinst index 1eba64e..38162da 100644 --- a/debian/preinst +++ b/debian/preinst @@ -1,45 +1,10 @@ #!/bin/sh -# preinst script for mediasmartserver -# -# see: dh_installdeb(1) - set -e -# summary of how this script can be called: -# * `install' -# * `install' -# * `upgrade' -# * `abort-upgrade' -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - case "$1" in install|upgrade) - if [ -x "/etc/init.d/mediasmartserver" ] - then - if [ -x "`which invoke-rc.d 2>/dev/null`" ] - then - invoke-rc.d mediasmartserver stop > /dev/null - else - /etc/init.d/mediasmartserver stop > /dev/null - fi - - rm /etc/init.d/mediasmartserver > /dev/null - update-rc.d mediasmartserver remove > /dev/null - else - INIT=$(ps --pid 1 | grep -q systemd && echo 'systemd' || echo 'upstart') - case "$INIT" in - systemd) - systemctl stop mediasmartserver - systemctl disable mediasmartserver - systemctl daemon-reload - ;; - - *) - stop mediasmartserver - ;; - esac + if systemctl is-active --quiet mediasmartserver 2>/dev/null; then + systemctl stop mediasmartserver fi ;; @@ -52,9 +17,6 @@ case "$1" in ;; esac -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - #DEBHELPER# exit 0 diff --git a/debian/prerm b/debian/prerm index 9d4ec0e..e495c7d 100644 --- a/debian/prerm +++ b/debian/prerm @@ -1,25 +1,9 @@ #!/bin/sh -# prerm script for mediasmartserver -# -# see: dh_installdeb(1) - set -e -# summary of how this script can be called: -# * `remove' -# * `upgrade' -# * `failed-upgrade' -# * `remove' `in-favour' -# * `deconfigure' `in-favour' -# `removing' -# -# for details, see http://www.debian.org/doc/debian-policy/ or -# the debian-policy package - - case "$1" in remove|upgrade|deconfigure) - stop mediasmartserver + systemctl stop mediasmartserver 2>/dev/null || true ;; failed-upgrade) @@ -31,9 +15,6 @@ case "$1" in ;; esac -# dh_installdeb will replace this with shell code automatically -# generated by other debhelper scripts. - #DEBHELPER# exit 0 diff --git a/rpm/mediasmartserver.spec b/rpm/mediasmartserver.spec new file mode 100644 index 0000000..35e0b36 --- /dev/null +++ b/rpm/mediasmartserver.spec @@ -0,0 +1,51 @@ +Name: mediasmartserver +Version: %{_version} +Release: 1%{?dist} +Summary: LED status daemon for HP MediaSmart Server and compatible hardware +License: Zlib +URL: https://github.com/amd989/mediasmartserverd +Source0: %{name}-%{version}.tar.gz + +%define debug_package %{nil} + +BuildRequires: gcc-c++ +BuildRequires: make +BuildRequires: systemd-rpm-macros +BuildRequires: systemd-devel + +Requires: systemd + +%description +Linux daemon that controls drive bay status LEDs on HP MediaSmart Server +EX48X, Acer H340/H341/H342, Acer Altos easyStore M2, and Lenovo IdeaCentre +D400. Also supports Arduino-based USB serial LED control for custom builds. + +Monitors disk presence and activity via udev/sysfs, provides system update +notifications via LED colors, and supports light show animations. + +%prep +%setup -q + +%build +make mediasmartserverd + +%install +install -D -m 0755 mediasmartserverd %{buildroot}%{_sbindir}/mediasmartserverd +install -D -m 0644 lib/systemd/system/mediasmartserver.service %{buildroot}%{_unitdir}/mediasmartserver.service + +%files +%license LICENSE +%doc README.md +%{_sbindir}/mediasmartserverd +%{_unitdir}/mediasmartserver.service + +%post +%systemd_post mediasmartserver.service + +%preun +%systemd_preun mediasmartserver.service + +%postun +%systemd_postun_with_restart mediasmartserver.service + +%changelog diff --git a/src/led_control_sch5127_base.h b/src/led_control_sch5127_base.h index 0fa1468..47a3fda 100644 --- a/src/led_control_sch5127_base.h +++ b/src/led_control_sch5127_base.h @@ -36,7 +36,18 @@ #include #include #include +#if defined(__i386__) || defined(__x86_64__) #include +#else +// Stubs for non-x86 platforms (SCH5127 hardware doesn't exist on ARM etc.) +static inline int ioperm(unsigned long from, unsigned long num, int turn_on) { (void)from; (void)num; (void)turn_on; return -1; } +static inline unsigned char inb(unsigned short port) { (void)port; return 0; } +static inline unsigned short inw(unsigned short port) { (void)port; return 0; } +static inline unsigned int inl(unsigned short port) { (void)port; return 0; } +static inline void outb(unsigned char value, unsigned short port) { (void)value; (void)port; } +static inline void outw(unsigned short value, unsigned short port) { (void)value; (void)port; } +static inline void outl(unsigned int value, unsigned short port) { (void)value; (void)port; } +#endif ///////////////////////////////////////////////////////////////////////////// /// base class for LED control over systems using the SCH5127 chipset