diff --git a/.github/workflows/auto-remove-waiting-label.yml b/.github/workflows/auto-remove-waiting-label.yml index d8cda709..0e170107 100644 --- a/.github/workflows/auto-remove-waiting-label.yml +++ b/.github/workflows/auto-remove-waiting-label.yml @@ -1,7 +1,7 @@ name: Auto-remove "waiting new revision" label on PR update on: - pull_request: + pull_request_target: types: [synchronize] permissions: @@ -14,4 +14,5 @@ jobs: - name: Remove label on PR update uses: actions-ecosystem/action-remove-labels@v1 with: - labels: 'waiting new revision' + labels: waiting new revision + fail_on_error: true diff --git a/.github/workflows/checkpatch_ignore.txt b/.github/workflows/checkpatch_ignore.txt index ff7b3dbe..071fa5e9 100644 --- a/.github/workflows/checkpatch_ignore.txt +++ b/.github/workflows/checkpatch_ignore.txt @@ -1,7 +1,7 @@ # .github/workflows/checkpatch_ignore.txt -# Ignore a CONSTANT_COMPARISON that only appears in ras-page-isolation.h -^ras-page-isolation\.h:.*CONSTANT_COMPARISON +# Ignore a CONSTANT_COMPARISON that only appears in modules/ras-page-isolation.h +^modules/ras-page-isolation\.h:.*CONSTANT_COMPARISON -# Ignore a MACRO_ARG_PRECEDENCE that only appears in types.h -^types\.h:.*MACRO_ARG_PRECEDENCE +# Ignore a MACRO_ARG_PRECEDENCE that only appears in core/types.h +^core/types\.h:.*MACRO_ARG_PRECEDENCE diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38d8876b..221f27fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,42 +14,44 @@ jobs: strategy: matrix: arch: [x64_64, aarch64, ppc64le] - config: [--disable-all, --enable-all] + config: [disable-all=false, disable-all=true] steps: - - uses: actions/checkout@v2 - - name: prepare - run: | - sudo apt-get update - sudo apt-get install -y build-essential libsqlite3-dev sqlite3 libtraceevent-dev libtraceevent1 libpci-dev - - name: build - run: | - autoreconf -vfi - ./configure ${{ matrix.config }} - make - sudo make install + - uses: actions/checkout@v7 + + - name: prepare + run: | + sudo apt-get update + sudo apt-get install -y build-essential meson ninja-build pkg-config \ + git cmake libsqlite3-dev sqlite3 \ + libtraceevent-dev libtraceevent1 libpci-dev + - name: build + run: | + meson setup build --reconfigure -D${{ matrix.config }} + make + sudo make install Fedora: name: Fedora runs-on: ubuntu-latest - strategy: - matrix: - arch: [x64_64] container: image: fedora:rawhide options: --privileged steps: - - uses: actions/checkout@v2 - - name: prepare - run: | - dnf install -y mock rpm-build rpmdevtools \ - autoconf automake make gcc libtraceevent-devel - ln -sf fedora-rawhide-x86_64.cfg /etc/mock/default.cfg - rpmdev-setuptree - - name: build - run: | - autoreconf -vfi - ./configure - make mock + - name: prepare + run: | + dnf install -y git mock rpmdevtools meson gcc make \ + libtraceevent-devel + + ln -sf fedora-rawhide-x86_64.cfg /etc/mock/default.cfg + rpmdev-setuptree + + - uses: actions/checkout@v7 + + - name: build + run: | + meson setup build -Ddisable-all=true + git config --global safe.directory "*" + make mock openEuler: name: OpenEuler LTS @@ -61,30 +63,32 @@ jobs: image: openeuler/openeuler:24.03-lts-sp3 options: --privileged steps: - - uses: actions/checkout@v2 - - name: prepare - run: | - dnf install -y sudo autoconf automake libtool gettext-devel hwdata \ - make gcc libtraceevent-devel sqlite-devel sqlite \ - pciutils pciutils-devel - - name: build - run: | - autoreconf -vfi - ./configure --enable-all - make - make install + - name: prepare + run: | + dnf install -y sudo meson ninja-build gettext-devel hwdata \ + make gcc libtraceevent-devel sqlite-devel sqlite \ + pciutils pciutils-devel findutils + + - uses: actions/checkout@v7 + + - name: build + run: | + meson setup build --reconfigure -Ddisable-all=false + make + make install Check: name: Source code check runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - name: checkpatch - run: | - ignore_regex=$(grep -Ev '^\s*#' .github/workflows/checkpatch_ignore.txt | tr '\n' '|') - ignore_regex=${ignore_regex%|} + - uses: actions/checkout@v7 + + - name: checkpatch + run: | + ignore_regex=$(grep -Ev '^\s*#' .github/workflows/checkpatch_ignore.txt | tr '\n' '|') + ignore_regex=${ignore_regex%|} - output=$(./scripts/checkpatch.pl --terse --show-types --no-summary \ - -f $(git ls-files | grep -E '\.[ch]$') | \ - grep -Ev "$ignore_regex" || true); echo $output; \ - if [ -z "$output" ]; then exit 0; fi; exit 1 + output=$(./scripts/checkpatch.pl --terse --show-types --no-summary \ + -f $(git ls-files | grep -E '\.[ch]$') | \ + grep -Ev "$ignore_regex" || true); echo $output; \ + if [ -z "$output" ]; then exit 0; fi; exit 1 diff --git a/.github/workflows/on_tag.yml b/.github/workflows/on_tag.yml index 2b5d4234..73878402 100644 --- a/.github/workflows/on_tag.yml +++ b/.github/workflows/on_tag.yml @@ -7,7 +7,7 @@ on: push: # Sequence of patterns matched against refs/tags tags: - - 'v[0-9]+*' + - v[0-9]+* jobs: release: @@ -16,37 +16,36 @@ jobs: outputs: upload_url: ${{ steps.create_release.outputs.upload_url }} steps: - - uses: actions/checkout@v2 - - name: Release changelog - run: | - .github/workflows/gen_release.pl body_file.tmp > version - echo "version=$(cat version)" >> $GITHUB_ENV - - name: Create Release - id: create_release - uses: actions/create-release@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ github.ref }} - release_name: Release ${{ github.ref }} - body_path: body_file.tmp - draft: false - prerelease: true - - name: prepare - run: | - sudo apt-get update - sudo apt-get install -y build-essential sqlite3 libtraceevent-dev libtraceevent1 - - name: Create Source Package for version ${{ env.version }} - run: | - autoreconf -vfi - ./configure --enable-all - make dist-bzip2 - - name: upload - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: mchehab/upload-release-asset@v1.0.3 - with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: rasdaemon-${{ env.version }}.tar.bz2 - asset_name: rasdaemon-${{ env.version }}.tar.bz2 - asset_content_type: application/bzip2 + - uses: actions/checkout@v2 + - name: Release changelog + run: | + .github/workflows/gen_release.pl body_file.tmp > version + echo "version=$(cat version)" >> $GITHUB_ENV + - name: Create Release + id: create_release + uses: actions/create-release@latest + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ github.ref }} + release_name: Release ${{ github.ref }} + body_path: body_file.tmp + draft: false + prerelease: true + - name: prepare + run: | + sudo apt-get update + sudo apt-get install -y build-essential meson ninja-build sqlite3 libtraceevent-dev libtraceevent1 + - name: Create Source Package for version ${{ env.version }} + run: | + meson setup build --reconfigure -Ddisable-all=false + make dist-bzip2 + - name: upload + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: mchehab/upload-release-asset@v1.0.3 + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: rasdaemon-${{ env.version }}.tar.bz2 + asset_name: rasdaemon-${{ env.version }}.tar.bz2 + asset_content_type: application/bzip2 diff --git a/.github/workflows/unittest.yml b/.github/workflows/unittest.yml new file mode 100644 index 00000000..f125dad6 --- /dev/null +++ b/.github/workflows/unittest.yml @@ -0,0 +1,157 @@ +# SPDX-License-Identifier: GPL-2.0 + +name: Tests + +on: + workflow_dispatch: + push: + pull_request: + +jobs: + Unittest: + name: Default Unit Tests + runs-on: ubuntu-latest + steps: + - name: Start MySQL + run: | + sudo systemctl start mysql.service + mysqladmin ping --host=127.0.0.1 --user=root --password=root + + - name: Install PostgreSQL + run: | + sudo apt-get update + sudo apt-get install -y postgresql postgresql-client + + sudo systemctl start postgresql + + for attempt in {1..30}; do + if pg_isready --host=127.0.0.1 --port=5432; then + exit 0 + fi + sleep 1 + done + + sudo systemctl status postgresql --no-pager + + - name: Setup PostgreSQL trust + run: | + HBA_FILE="$(sudo -u postgres psql --tuples-only --no-align \ + --command='SHOW hba_file')" + sudo sed -i '1i local all rasdaemon trust' "$HBA_FILE" + + echo "Postgres config file $HBA_FILE:" + sudo cat "$HBA_FILE" + sudo systemctl restart postgresql + + for attempt in {1..30}; do + if pg_isready --host=127.0.0.1 --port=5432; then + exit 0 + fi + sleep 1 + done + + sudo systemctl status postgresql --no-pager + exit 1 + + - name: Create MySQL database + env: + MYSQL_PWD: root + run: | + mysql --host=127.0.0.1 --user=root << EOF + CREATE USER 'rasdaemon'@'%' IDENTIFIED BY 'mypass'; + CREATE DATABASE rasdaemon_test; + GRANT ALL PRIVILEGES ON rasdaemon_test.* TO 'rasdaemon'@'%'; + FLUSH PRIVILEGES; + EOF + - name: Create PostgreSQL database + run: | + sudo -u postgres psql --set ON_ERROR_STOP=1 << EOF + CREATE USER rasdaemon WITH PASSWORD 'mypass'; + CREATE DATABASE rasdaemon_test OWNER rasdaemon; + EOF + + PGPASSWORD='mypass' \ + psql -h /var/run/postgresql -U rasdaemon \ + -d rasdaemon_test --set ON_ERROR_STOP=1 << EOF2 + CREATE SCHEMA rasdaemon AUTHORIZATION rasdaemon; + EOF2 + - name: Install packages needed by Rasdaemon + run: | + sudo apt-get update + sudo apt-get install -y build-essential meson ninja-build pkg-config \ + git cmake libsqlite3-dev sqlite3 \ + python3-sqlalchemy python3-mysqldb \ + python3-psycopg2 \ + libcmocka-dev libmysqlclient-dev libpq-dev \ + libtraceevent-dev libtraceevent1 libpci-dev + - uses: actions/checkout@v7 + - name: Build rasdaemon + run: | + meson setup build + make + - name: Run unittest + env: + RAS_MYSQL_HOST: '' + RAS_MYSQL_PORT: '3306' + RAS_MYSQL_USER: rasdaemon + RAS_MYSQL_PASSWORD: mypass + RAS_MYSQL_DATABASE: rasdaemon_test + RAS_PG_HOST: '' + RAS_PG_PORT: 5432 + RAS_PG_USER: rasdaemon + RAS_PG_PASSWORD: mypass + RAS_PG_SCHEMA: rasdaemon + RAS_PG_DATABASE: rasdaemon_test + run: | + build/unittest -o tap + - name: Run Python unittests + run: | + python3 tests/run.py + + MariaDBUnittest: + name: MariaDB Unit Test + runs-on: ubuntu-latest + steps: + - name: Start MariaDB + run: | + sudo apt-get remove -y mysql-server mysql-client + sudo apt-get install -y mariadb-server mariadb-client + sudo systemctl start mariadb.service + + sudo mysqladmin ping + + - name: Create MariaDB database + env: + MYSQL_PWD: root + run: | + sudo mysql << EOF + CREATE USER 'rasdaemon'@'%' IDENTIFIED BY 'mypass'; + CREATE DATABASE rasdaemon_test; + GRANT ALL PRIVILEGES ON rasdaemon_test.* TO 'rasdaemon'@'%'; + FLUSH PRIVILEGES; + EOF + - name: Install packages needed by Rasdaemon + run: | + sudo apt-get update + sudo apt-get install -y build-essential meson ninja-build pkg-config \ + git cmake libsqlite3-dev sqlite3 \ + python3-sqlalchemy python3-mysqldb \ + libcmocka-dev libmariadb-dev-compat \ + libtraceevent-dev libtraceevent1 libpci-dev + - uses: actions/checkout@v7 + - name: Build rasdaemon + run: | + meson setup build + make + - name: Run unittest + env: + RAS_MYSQL_HOST: '' + RAS_MYSQL_PORT: '3306' + RAS_MYSQL_USER: rasdaemon + RAS_MYSQL_PASSWORD: mypass + RAS_MYSQL_DATABASE: rasdaemon_test + run: |- + build/unittest -o tap -g mysql + - name: Run Python unittests + run: |- + python3 -m unittest -v tests.test_ras_db.MysqlRasDatabaseTest diff --git a/.gitignore b/.gitignore index 4b368aad..79887c1a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,15 @@ -.deps/ -autom4te.cache/ -SRPMS/ +build/ misc/rasdaemon.spec misc/ras-mc-ctl.service misc/rasdaemon.service misc/rasdaemon.syslog-ng misc/rasdaemon.rsyslog misc/rasdaemon.logrotate -Makefile -Makefile.in -compile config.h -config.h.in -config.h.in~ -stamp-h1 -aclocal.m4 -config.guess -config.log -config.status -config.sub -configure -depcomp -install-sh -libtool -ltmain.sh -missing +librasdaemon.a rasdaemon +unittest *.o -*.c~ -*.h~ +*~ rasdaemon-*.tar.bz2 rasdaemon-*.src.rpm diff --git a/ChangeLog b/ChangeLog index 38666ede..1826b22b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,48 @@ +2026-08-21 Mauro Carvalho Chehab + - Version 0.9.90 (development) + + * Build: Replace Autotools with Meson while retaining a convenience + Makefile for common build, install, clean, and test operations + * Build: Auto-detect optional dependencies and non-standard CPER + decoders, and add an option to disable optional features + * Packaging: Fix Meson-generated RPM and install rules, install the + DIMM label database, and update Python runtime dependencies + * Database: Introduce a generic, modular database abstraction layer + * Database: Add MySQL/MariaDB and PostgreSQL recording backends + * Database: Load backend and connection settings from the rasdaemon + environment file, with an alternate file selectable at runtime + * Database: Record the hostname in remote databases + * SQLite3: Allow the full database path to be configured at build time + or with RAS_SQLITE3_DATABASE at runtime + * MySQL/MariaDB: Add MariaDB Connector/C support and constrain hostname + storage to the backend limit + * MySQL/PostgreSQL: Quote field names and improve binding and error + handling + * ras-mc-ctl: Replace the Perl implementation with a Python 3 tool + * ras-mc-ctl: Add DIMM status, labels, mainboard detection, and memory + layout commands compatible with the former tool + * ras-mc-ctl: Add SQLite3, MySQL/MariaDB, and PostgreSQL database query + support, including date and hostname filters and automatic indexes + * ras-mc-ctl: Allow selection of an alternate configuration file + * ras-mc-ctl: Update the manual page and Bash and Zsh completions for + the new subcommand interface + * contrib: Add example test configurations for all three database + backends and a fill-test-databases data generator + * Tests: Move the C unit tests to cmocka and expand database, module, + DIMM, layout, environment, and Python tool coverage + * CI: Build with Meson and test SQLite3, MySQL, MariaDB, and PostgreSQL + * rasdaemon: Add a module registration and lifecycle interface + * ras-report: Consolidate common reporting code and eliminate unsafe + stack allocations + * ras-cxl-handler: Gracefully handle missing optional DRAM fields + * ras-logger: Improve log identification and use colors on terminals + * ras-events: Restore compatibility with Ubuntu 22.04 + * non-standard: Fix duplicate Ampere fields, missing database guards, + and duplicate JaguarMicro table creation + * systemd: Order rasdaemon after debugfs + * Documentation: Describe Meson builds and SQLite3, MySQL/MariaDB, and + PostgreSQL configuration and dependencies + 2026-06-26 Mauro Carvalho Chehab - Version 0.8.5 diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..4872d3ca --- /dev/null +++ b/Makefile @@ -0,0 +1,36 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2026 Mauro Carvalho Chehab + +default: all + +PYTHON ?= python3 + +-include build/Makefile.inc + +build/build.ninja: + @if test -d build/; then \ + meson setup build --reconfigure; \ + else \ + meson setup build; \ + fi + +all: build/build.ninja + @ninja -C build + +clean: build/build.ninja + @ninja -C build clean + +reconfigure: build/build.ninja + @ninja -C build reconfigure + +install: build/build.ninja + @ninja -C build install + +uninstall: build/build.ninja + @ninja -C build uninstall + +python-test: + PYTHONDONTWRITEBYTECODE=1 $(PYTHON) tests/run.py + +.PHONY: python-test diff --git a/Makefile.am b/Makefile.am deleted file mode 100644 index 0c213d3b..00000000 --- a/Makefile.am +++ /dev/null @@ -1,283 +0,0 @@ -# Copyright (C) 2013- Mauro Carvalho Chehab -# SPDX-License-Identifier: GPL-2.0 - -# NOTE: For the file variables, please keep each group of dependencies sorted -# alphabetically. Hopefully, this would make easier to solve merge conflicts - -AM_DISTCHECK_CONFIGURE_FLAGS = --enable-all -ACLOCAL_AMFLAGS=-I m4 -SUBDIRS = util man - -SYSTEMD_SERVICES_IN = misc/rasdaemon.service.in -SYSTEMD_SERVICES_IN += misc/ras-mc-ctl.service.in - -SYSTEMD_SERVICES = $(SYSTEMD_SERVICES_IN:.service.in=.service) - -SYSLOG_SERVICES_IN = misc/rasdaemon.syslog-ng.in -SYSLOG_SERVICES = $(SYSLOG_SERVICES_IN:.syslog-ng.in=.syslog-ng) - -LOGROTATE_SERVICES_IN = misc/rasdaemon.logrotate.in -LOGROTATE_SERVICES = $(LOGROTATE_SERVICES_IN:.logrotate.in=.logrotate) - -RSYSLOG_SERVICES_IN = misc/rasdaemon.rsyslog.in -RSYSLOG_SERVICES = $(RSYSLOG_SERVICES_IN:.rsyslog.in=.rsyslog) - -EXTRA_DIST = $(LOGROTATE_SERVICES_IN) -EXTRA_DIST += $(RSYSLOG_SERVICES_IN) -EXTRA_DIST += $(SYSLOG_SERVICES_IN) -EXTRA_DIST += $(SYSTEMD_SERVICES_IN) - -EXTRA_DIST += completions/ras-mc-ctl.bash -EXTRA_DIST += completions/ras-mc-ctl.zsh -EXTRA_DIST += contrib/mem_fail_trigger -EXTRA_DIST += contrib/mc_event_trigger -EXTRA_DIST += labels -EXTRA_DIST += misc/rasdaemon.env - -CLEANFILES = misc/rasdaemon.logrotate -CLEANFILES += misc/rasdaemon.rsyslog -CLEANFILES += misc/rasdaemon.service -CLEANFILES += misc/rasdaemon.syslog-ng - -CLEANFILES += misc/ras-mc-ctl.service - -DISTCLEANFILES = misc/rasdaemon.spec - -# This rule is needed because \@sbindir\@ is expanded to \${exec_prefix\}/sbin -# during ./configure phase, therefore it is not possible to add .service.in -# files to AC_CONFIG_FILES in configure.ac - -SUFFIXES = .logrotate .logrotate.in -SUFFIXES += .rsyslog .rsyslog.in -SUFFIXES += .service .service.in -SUFFIXES += .syslog-ng .syslog-ng.in - -.service.in.service: - sed -e s,\@sbindir\@,$(sbindir),g -e s,\@SYSCONFDEFDIR\@,@SYSCONFDEFDIR@,g $< > $@ - -.logrotate.in.logrotate: - sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ - -.syslog-ng.in.syslog-ng: - sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ - -.rsyslog.in.rsyslog: - sed -e s,\@sbindir\@,$(sbindir),g -e s,\@localstatedir\@,${localstatedir},g $< > $@ - -# This rule is needed because the service files must be generated on target -# system after ./configure phase -all-local: $(SYSTEMD_SERVICES) $(SYSLOG_SERVICES) $(RSYSLOG_SERVICES) $(LOGROTATE_SERVICES) - -sbin_PROGRAMS = rasdaemon - -rasdaemon_SOURCES = rasdaemon.c - -rasdaemon_SOURCES += bitfield.c -rasdaemon_SOURCES += ras-events.c -rasdaemon_SOURCES += ras-mc-handler.c -rasdaemon_SOURCES += trigger.c -rasdaemon_SOURCES += types.c - -# Keep the IFs alphabetically sorted - -if WITH_ABRT_REPORT - rasdaemon_SOURCES += ras-report.c -endif - -if WITH_AER - rasdaemon_SOURCES += ras-aer-handler.c -endif - -if WITH_AMP_NS_DECODE - rasdaemon_SOURCES += non-standard-ampere.c -endif - -if WITH_ARM - rasdaemon_SOURCES += ras-arm-handler.c -endif - -if WITH_CPU_FAULT_ISOLATION - rasdaemon_SOURCES += ras-cpu-isolation.c - rasdaemon_SOURCES += queue.c -endif - -if WITH_CXL - rasdaemon_SOURCES += ras-cxl-handler.c -endif - -if WITH_DEVLINK - rasdaemon_SOURCES += ras-devlink-handler.c -endif - -if WITH_DISKERROR - rasdaemon_SOURCES += ras-diskerror-handler.c -endif - -if WITH_ERST - rasdaemon_SOURCES += ras-erst.c -endif - -if WITH_EXTLOG - rasdaemon_SOURCES += ras-extlog-handler.c -endif - -if WITH_HISI_NS_DECODE - rasdaemon_SOURCES += non-standard-hisi_hip08.c - rasdaemon_SOURCES += non-standard-hisilicon.c -endif - -if WITH_JAGUAR_NS_DECODE - rasdaemon_SOURCES += non-standard-jaguarmicro.c -endif - -if WITH_MCE - rasdaemon_SOURCES += mce-amd.c - rasdaemon_SOURCES += mce-amd-k8.c - rasdaemon_SOURCES += mce-amd-smca.c - rasdaemon_SOURCES += mce-intel.c - rasdaemon_SOURCES += mce-intel-broadwell-de.c - rasdaemon_SOURCES += mce-intel-broadwell-epex.c - rasdaemon_SOURCES += mce-intel-diamond.c - rasdaemon_SOURCES += mce-intel-dunnington.c - rasdaemon_SOURCES += mce-intel-haswell.c - rasdaemon_SOURCES += mce-intel-granite.c - rasdaemon_SOURCES += mce-intel-i10nm.c - rasdaemon_SOURCES += mce-intel-ivb.c - rasdaemon_SOURCES += mce-intel-knl.c - rasdaemon_SOURCES += mce-intel-nehalem.c - rasdaemon_SOURCES += mce-intel-p4-p6.c - rasdaemon_SOURCES += mce-intel-sb.c - rasdaemon_SOURCES += mce-intel-skylake-xeon.c - rasdaemon_SOURCES += mce-intel-tulsa.c - rasdaemon_SOURCES += mce-zhaoxin.c - rasdaemon_SOURCES += mce-zhaoxin-kh50000.c - rasdaemon_SOURCES += ras-mce-handler.c -endif - -if WITH_MEMORY_FAILURE - rasdaemon_SOURCES += ras-memory-failure-handler.c -endif - -if WITH_NVIDIA_NS_DECODE - rasdaemon_SOURCES += non-standard-nvidia.c -endif - -if WITH_NON_STANDARD - rasdaemon_SOURCES += ras-non-standard-handler.c -endif - -if WITH_OPENBMC_UNIFIED_SEL - rasdaemon_SOURCES += unified-sel.c -endif - -if WITH_PFA - rasdaemon_SOURCES += rbtree.c ras-page-isolation.c -endif - -if WITH_POISON_PAGE_STAT - rasdaemon_SOURCES += ras-poison-page-stat.c -endif - -if WITH_SIGNAL - rasdaemon_SOURCES += ras-signal-handler.c -endif - -if WITH_SQLITE3 - rasdaemon_SOURCES += ras-record.c -endif - -if WITH_YITIAN_NS_DECODE - rasdaemon_SOURCES += non-standard-yitian.c -endif - -if WITH_RERI - rasdaemon_SOURCES += ras-reri-handler.c -endif - -rasdaemon_LDADD = -lpthread $(SQLITE3_LIBS) $(LIBTRACEEVENT_LIBS) $(LIBPCI_LIBS) -rasdaemon_CFLAGS = $(SQLITE3_CFLAGS) $(LIBTRACEEVENT_CFLAGS) $(LIBPCI_CFLAGS) - -include_HEADERS = config.h - -include_HEADERS += bitfield.h -include_HEADERS += queue.h -include_HEADERS += rbtree.h -include_HEADERS += trigger.h -include_HEADERS += types.h -include_HEADERS += unified-sel.h - -include_HEADERS += non-standard-ampere.h -include_HEADERS += non-standard-hisilicon.h -include_HEADERS += non-standard-jaguarmicro.h -include_HEADERS += non-standard-nvidia.h -include_HEADERS += non-standard-yitian.h - -include_HEADERS += ras-aer-handler.h -include_HEADERS += ras-arm-handler.h -include_HEADERS += ras-cpu-isolation.h -include_HEADERS += ras-cxl-handler.h -include_HEADERS += ras-devlink-handler.h -include_HEADERS += ras-diskerror-handler.h -include_HEADERS += ras-erst.h -include_HEADERS += ras-events.h -include_HEADERS += ras-extlog-handler.h -include_HEADERS += ras-logger.h -include_HEADERS += ras-mc-handler.h -include_HEADERS += ras-mce-handler.h -include_HEADERS += ras-memory-failure-handler.h -include_HEADERS += ras-non-standard-handler.h -include_HEADERS += ras-page-isolation.h -include_HEADERS += ras-poison-page-stat.h -include_HEADERS += ras-record.h -include_HEADERS += ras-report.h -include_HEADERS += ras-signal-handler.h -include_HEADERS += ras-reri-handler.h - -# This rule can't be called with more than one Makefile job (like make -j8) -# I can't figure out a way to fix that -dist-rpm: dist-bzip2 - if [ ! -d "`rpm --eval %{_topdir}`/SOURCES/" ]; then mkdir "`rpm --eval %{_topdir}`/SOURCES/"; fi - cp @PACKAGE@-@PACKAGE_VERSION@.tar.bz2 `rpm --eval %{_topdir}`/SOURCES/ - rpmbuild -ba misc/@PACKAGE@.spec - cp `rpm --eval %{_topdir}`/SRPMS/@PACKAGE@-@PACKAGE_VERSION@*.src.rpm . - -srpm: dist-bzip2 - if [ ! -d "`rpm --eval %{_topdir}`/SOURCES/" ]; then mkdir "`rpm --eval %{_topdir}`/SOURCES/"; fi - cp @PACKAGE@-@PACKAGE_VERSION@.tar.bz2 `rpm --eval %{_topdir}`/SOURCES/ - rpmbuild -bs misc/@PACKAGE@.spec - -mock: srpm - mock --resultdir="./SRPMS" `rpm --eval %{_topdir}`/SRPMS/@PACKAGE@-@PACKAGE_VERSION@*.src.rpm - -rpmlint: - rpmlint misc/@PACKAGE@.spec `rpm --eval %{_topdir}`/SRPMS/@PACKAGE@-@PACKAGE_VERSION@*.src.rpm `rpm --eval %{_topdir}`/RPMS/*/@PACKAGE@-@PACKAGE_VERSION@*.rpm - -upload: - scp `rpm --eval %{_topdir}`/SRPMS/@PACKAGE@-@PACKAGE_VERSION@*.src.rpm @PACKAGE@-@PACKAGE_VERSION@.tar.bz2 misc/rasdaemon.spec www.infradead.org:public_html/rasdaemon - -# custom target -install-data-local: - $(install_sh) -d "$(DESTDIR)@sysconfdir@/ras/dimm_labels.d" - for f in @abs_srcdir@/labels/*; do \ - test -f "$$f" || continue; \ - $(install_sh) -m 0644 "$$f" "$(DESTDIR)@sysconfdir@/ras/dimm_labels.d/"; \ - done - $(install_sh) -d "$(DESTDIR)@sysconfdir@/ras/triggers" - install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.env "$(DESTDIR)@SYSCONFDEFDIR@/rasdaemon" - $(install_sh) @abs_srcdir@/contrib/mc_event_trigger "$(DESTDIR)@sysconfdir@/ras/triggers/mc_event_trigger" - $(install_sh) @abs_srcdir@/contrib/mem_fail_trigger "$(DESTDIR)@sysconfdir@/ras/triggers/mem_fail_trigger" - if [ -d "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d" ]; then \ - install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.syslog-ng "$(DESTDIR)@sysconfdir@/syslog-ng/conf.d/rasdaemon.conf"; \ - fi - if [ -d "$(DESTDIR)@sysconfdir@/rsyslog.d/" ]; then \ - install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.rsyslog "$(DESTDIR)@sysconfdir@/rsyslog.d/rasdaemon.conf"; \ - fi - if [ -d "$(DESTDIR)@sysconfdir@/logrotate.d" ]; then \ - install -D -p -m 0655 @abs_srcdir@/misc/rasdaemon.logrotate "$(DESTDIR)@sysconfdir@/logrotate.d/rasdaemon"; \ - fi - $(install_sh) -d "$(DESTDIR)${datarootdir}/zsh/site-functions" - install -D -p -m 0644 @abs_srcdir@/completions/ras-mc-ctl.zsh \ - $(DESTDIR)${datarootdir}/zsh/site-functions/_ras-mc-ctl - $(install_sh) -d "$(DESTDIR)${datarootdir}/bash-completion/completions" - install -D -p -m 0644 @abs_srcdir@/completions/ras-mc-ctl.bash \ - $(DESTDIR)${datarootdir}/bash-completion/completions/ras-mc-ctl diff --git a/Makefile.inc.in b/Makefile.inc.in new file mode 100644 index 00000000..4dcc3e55 --- /dev/null +++ b/Makefile.inc.in @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2026 Mauro Carvalho Chehab + +# Extra rasdaemon-specific targets + +RPM_TOPDIR ?= $(shell rpm --eval '%{_topdir}') +DIST_TARBALL = build/meson-dist/@PACKAGE@-@PACKAGE_VERSION@.tar.xz +SPEC_FILE = build/rasdaemon.spec + +test: all + build/unittest + +dist: + meson dist -C build + +dist-rpm: dist + if [ ! -d "$(RPM_TOPDIR)/SOURCES/" ]; then \ + mkdir -p "$(RPM_TOPDIR)/SOURCES/"; \ + fi + cp "${DIST_TARBALL}" "${RPM_TOPDIR}/SOURCES/" + rpmbuild -ba $(SPEC_FILE) + cp $(RPM_TOPDIR)/SRPMS/@PACKAGE@-@PACKAGE_VERSION@*.src.rpm . + cp $(RPM_TOPDIR)/RPMS/*/@PACKAGE@-@PACKAGE_VERSION@*.rpm . + +srpm: dist + if [ ! -d "$(RPM_TOPDIR)/SOURCES/" ]; then \ + mkdir -p "$(RPM_TOPDIR)/SOURCES/"; \ + fi + cp $(DIST_TARBALL) "$(RPM_TOPDIR)/SOURCES/" + rpmbuild -bs $(SPEC_FILE) + cp $(RPM_TOPDIR)/SRPMS/@PACKAGE@-@PACKAGE_VERSION@*.src.rpm . + +mock: srpm + mock --resultdir="./SRPMS" "$(RPM_TOPDIR)/SRPMS/"@PACKAGE@-@PACKAGE_VERSION@*.src.rpm + +rpmlint: dist-rpm + rpmlint $(RPM_TOPDIR)/SRPMS/@PACKAGE@-@PACKAGE_VERSION@*.src.rpm + rpmlint $(RPM_TOPDIR)/RPMS/*/@PACKAGE@-@PACKAGE_VERSION@*.rpm + +local-install: + ninja -C build install DESTDIR=$(DESTDIR) --prefix=$(PREFIX) + +local-uninstall: + ninja -C build uninstall DESTDIR=$(DESTDIR) --prefix=$(PREFIX) + +distclean: clean + rm -rf @PACKAGE@-@PACKAGE_VERSION@*.src.rpm \ + @PACKAGE@-@PACKAGE_VERSION@*.rpm \ + SRPMS/ @PACKAGE@-@PACKAGE_VERSION@*.tar.xz \ + build/ + +upload: srpm dist + scp $(RPM_TOPDIR)/SRPMS/@PACKAGE@-@PACKAGE_VERSION@*.src.rpm $(DIST_TARBALL) misc/rasdaemon.spec www.infradead.org:public_html/rasdaemon + diff --git a/README.md b/README.md index 3758457e..07095cd4 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ users. The project is not offered as a consumer-facing online service or managed platform. -GOALS +Goals ===== Its initial goal is to replace the edac-tools that got bitrotted after @@ -88,76 +88,84 @@ While this tool works since Kernel 3.5 (where HERM patches got added), in order to get the full benefit of this tool, Kernel 3.10 or upper is needed. -COMPILING AND INSTALLING +Compiling and Installing ======================== -sqlite3 and autoconf needs to be installed. On Fedora, this is done by -installing the following packages: +Meson, a C compiler, the trace-event library, and the Python dependencies +need to be installed. On Fedora, this is done by installing the following +packages: ``` - make gcc - autoconf - automake - libtool + meson + ninja-build libtraceevent-devel - tar - sqlite-devel (if sqlite3 will be used) - perl-DBD-SQLite (if sqlite3 will be used) + pciutils-devel + python3 + python3-sqlalchemy + sqlite-devel (if SQLite3 will be used) + mariadb-connector-c-devel (if MariaDB will be used) + mysql-community-devel (if Oracle MySQL will be used; from the MySQL repository) + libpq-devel (if PostgreSQL will be used) + python3-mysqlclient (to query either MariaDB or MySQL with ras-mc-ctl) + python3-psycopg2 (to query PostgreSQL with ras-mc-ctl) ``` To install them on Fedora, run: ``` - $ dnf install -y make gcc autoconf automake libtool tar perl-dbd-sqlite \ - libtraceevent-devel + $ dnf install -y gcc meson ninja-build libtraceevent-devel \ + pciutils-devel python3 python3-sqlalchemy sqlite-devel ``` -Or, if sqlite3 database will be used to store data: + +All features are enabled by default when their dependencies are available. +Features can be explicitly enabled or disabled with Meson options. For +example: ``` - $ dnf install -y make gcc autoconf automake libtool tar sqlite-devel \ - libtraceevent-devel + -Dsqlite3=enabled enable storage in an SQLite3 database + -Daer=enabled enable PCIe AER events + -Dmce=enabled enable MCE events ``` -There are currently 3 features that are enabled optionally, via -./configure parameters: - +In order to compile it, run: ``` - --enable-sqlite3 enable storing data at SQL lite database (currently - experimental) - --enable-aer enable PCIe AER events (currently experimental) - --enable-mce enable MCE events (currently experimental) + $ meson setup build [options] + $ meson compile -C build ``` -In order to compile it, run: +The top-level Makefile is a convenience wrapper around Meson and Ninja. For a +build using the default options, simply running the following also works: + ``` - $ autoreconf -vfi - $ ./configure [parameters] $ make ``` So, for example, to enable everything but sqlite3: ``` - $ autoreconf -vfi && ./configure --enable-aer --enable-mce && make + $ meson setup build -Dsqlite3=disabled + $ meson compile -C build ``` After compiling, run, as root: ``` - $ make install + $ meson install -C build ``` +When using the Makefile wrapper, `make install` performs the equivalent +installation. + RPM-based compilation ===================== If the distribution is rpm-based, an alternative method would be to do: ``` - $ autoreconf -vfi && ./configure + $ meson setup build ``` The above procedure will generate a file at misc/rasdaemon.spec. -You may edit it, in order to add/remove the --enable-\[option\] -parameters. +You may edit it to change the Meson feature options. To generate the rpm files, do: @@ -170,7 +178,7 @@ To install the rpm files, run, as root: # rpm -i $(ls SRPMS/rasdaemon-*.rpm|tail -1) ``` -RUNNING +Running ======= The daemon generally requires root permission, in order to read the @@ -216,31 +224,252 @@ You may also start it via systemd: The rasdaemon will then output the messages to journald. -TESTING -======= +How to Setup a Database +======================= -A script is provided under /contrib, in order to test the daemon EDAC -handler. While the daemon is running, just run: +RAS Daemon supports multiple types of databases. Each require their own +specific parameters. Only one database can be active. The database backend +connection parameters are specified via environment variables, usually in +the `/etc/sysconfig/rasdaemon` file. It contains these common fields: + +- `RASDAEMON_DB_BACKEND` - backend to be used. Can be: `postgresql`, + `mysql` or `sqlite3`. +- `RASDAEMON_HOSTNAME` - hostname to be stored inside remote databases + (MySQL/MariaDB or PostgreSQL). Not used for SQLite. + +The other parameters are database specific and are also located in that file. + +## SQLite3 (default) + +For SQLite3, `RAS_SQLITE3_DATABASE` specifies the full database path. It +defaults to `/var/lib/rasdaemon/ras-mc_event.db`, and rasdaemon creates the +parent directory when needed. The compiled default can be changed with: ``` -# contrib/edac-fake-inject + $ meson setup build -Dsqlite3-database=/path/to/ras-mc_event.db +``` + +On Ubuntu/Debian, the packages required to build rasdaemon with sqlite3 +support are: + +```bash +sudo apt-get update +sudo apt-get install -y build-essential meson ninja-build pkg-config \ + git cmake libsqlite3-dev sqlite3 \ + libtraceevent-dev libtraceevent1 libpci-dev +``` + +## PostgreSQL + +To use PostgreSQL, set the following environment variables +(all optional with sensible defaults): + +- `RAS_PG_HOST` - Hostname or IP (default: `""` = local Unix socket) +- `RAS_PG_PORT` - TCP port (default: `5432`) +- `RAS_PG_USER` - Username (default: `rasdaemon`) +- `RAS_PG_PASSWORD` - Password (default: empty) +- `RAS_PG_SCHEMA` - Schema (default: `rasdaemon`) +- `RAS_PG_DATABASE` - Database name (default: `rasdaemon_test`) + +Example: +```bash +RAS_PG_HOST="localhost" +RAS_PG_PORT="5432" +RAS_PG_USER="rasdaemon" +RAS_PG_PASSWORD="" +RAS_PG_DATABASE="rasdaemon" +RAS_PG_SCHEMA="rasdaemon" +``` + +**Prerequisites**: Install `libpq-devel` or `libpq-dev` package and +`postgresql` server. + +### Install and configure PostgreSQL + +On Debian/Ubuntu: + +```bash +sudo apt-get install -y postgresql postgresql-client libpq-dev + +sudo systemctl start postgresql +for attempt in {1..30}; do + if pg_isready --host=127.0.0.1 --port=5432; then + exit 0 + fi + sleep 1 +done + +sudo systemctl status postgresql --no-pager +``` + +### Setup PostgreSQL trust authentication + +If you plan to run PostgreSQL locally starting it from a different user, +you'll need to setup the the rasdaemon user as trusted. + +```bash +HBA_FILE="$(sudo -u postgres psql --tuples-only --no-align --command='SHOW hba_file')" + +sudo sed -i '1i local all rasdaemon trust' "$HBA_FILE" + +echo "Postgres config file $HBA_FILE:" +sudo cat "$HBA_FILE" + +sudo systemctl restart postgresql +for attempt in {1..30}; do + if pg_isready --host=127.0.0.1 --port=5432; then + exit 0 + fi + sleep 1 +done + +# Check if everything is OK +sudo systemctl status postgresql --no-pager ``` -The script requires a Kernel compiled with CONFIG_EDAC_DEBUG and a running -EDAC driver. +### Create PostgreSQL database and schema + +Before starting rasdaemon, if they don't exist, you need to: +- create the user; +- create the database; +- create the schema; +- grant permissions. -MCE error handling can use the MCE inject: - +For a simple setup, you could do: -For it to work, Kernel mce-inject module should be compiled and loaded. +```bash +sudo -u postgres psql --set ON_ERROR_STOP=1 << EOF + CREATE USER rasdaemon WITH PASSWORD 'some_password'; + CREATE DATABASE rasdaemon_test OWNER rasdaemon; +EOF + +PGPASSWORD='some_password' \ + psql -h /var/run/postgresql -U rasdaemon \ + -d rasdaemon_test --set ON_ERROR_STOP=1 << EOF2 + CREATE SCHEMA rasdaemon AUTHORIZATION rasdaemon; +EOF2 +``` -APEI error injection can use this tool: - +## MySQL / MariaDB -AER error injection can use this tool: - +To use MySQL or MariaDB, set the following environment variables +(all optional with sensible defaults): + +- `RAS_MYSQL_HOST` - Hostname or IP (default: `""` = local Unix socket) +- `RAS_MYSQL_PORT` - TCP port (default: `3306`) +- `RAS_MYSQL_USER` - Username (default: `rasdaemon`) +- `RAS_MYSQL_PASSWORD` - Password (default: empty) +- `RAS_MYSQL_DATABASE` - Database name (default: `rasdaemon_test`) + +Example: +```bash +RAS_MYSQL_HOST="" +RAS_MYSQL_PORT="3306" +RAS_MYSQL_USER="rasdaemon" +RAS_MYSQL_PASSWORD="" +RAS_MYSQL_DATABASE="rasdaemon_test" +``` + +The C client development package depends on the server implementation and +distribution: + +- Fedora/RHEL with MariaDB: `mariadb-connector-c-devel` +- Fedora/RHEL with Oracle MySQL packages: `mysql-community-devel` +- Debian/Ubuntu with MariaDB: `libmariadb-dev`; some releases also require + `libmariadb-dev-compat` for the MySQL-compatible development headers +- Debian/Ubuntu with MySQL: `default-libmysqlclient-dev` + +Only one C client development package is needed. Meson accepts the +`mysqlclient`, `mariadb`, or `libmariadb` pkg-config interface. The Python +database tool additionally requires the `mysqlclient` Python module, packaged +as `python3-mysqlclient` on Fedora/RHEL and `python3-mysqldb` on Debian/Ubuntu. + +### Start MySQL or MariaDB and create the database + +For MySQL and MariaDB, you'll need to: +- create the user; +- create the database; +- grant permissions. + +The service name is normally `mysqld.service` for Oracle MySQL packages and +`mariadb.service` for MariaDB. On Debian/Ubuntu, the MySQL service may instead +be named `mysql.service`. Start the service matching the installed server, for +example: + +```bash +sudo systemctl start mariadb.service +# Or: sudo systemctl start mysqld.service +# Or: sudo systemctl start mysql.service +``` + +For a simple local setup, the SQL is the same for both implementations: + +```bash +mysqladmin ping --host=127.0.0.1 --user=root --password=root + +sudo -u root mysql --host=127.0.0.1 << EOF + CREATE USER 'rasdaemon'@'%' IDENTIFIED BY 'mypass'; + CREATE DATABASE rasdaemon_test; + GRANT ALL PRIVILEGES ON rasdaemon_test.* TO 'rasdaemon'@'%'; + FLUSH PRIVILEGES; +EOF +``` + +Unit Tests +========== + +rasdaemon provides unit tests for each database backend. The tests follow +the pattern shown in `tests/db*` [6, 9, 4], which use `module_init()` to +initialize exactly one backend module. + +To enable unit tests, `libcmocka-devel` or `libcmocka-dev` package is +required. + +**SQLite3 tests** (`test-sqlite3.c` [6]): +```bash +$ make +$ ./build/unittest -g sqlite3 +``` + +**PostgreSQL tests** (`test-postgresql.c` [4, 5]): +```bash +$ make +$ ./build/unittest -g postgresql +``` + +**MySQL tests** (`test-mysql.c` [9]): +```bash +$ make +$ ./build/unittest -g mysql +``` + +Error Injection Testing +======================= + +Some scripts is provided under /contrib, in order to test the daemon EDAC +handler you can use: + +- `contrib/edac-fake-inject` - Inject EDAC errors. + Requires a kernel compiled with `CONFIG_EDAC_DEBUG` and a + running EDAC driver. + +For other error sources, external tools are recommended: + +- **MCE error injection**: +- **APEI error injection**: +- **AER error injection**: + + + +A script is provided under /contrib, in order to test the daemon EDAC +handler. While the daemon is running, just run: + +``` +# contrib/edac-fake-inject +``` -# SUBMITTING PATCHES +Submitting Patches +================== If you want to help improve this tool, be my guest! We try to follow the Kernel's CodingStyle and submission rules as a reference. diff --git a/completions/ras-mc-ctl.bash b/completions/ras-mc-ctl.bash index df60cee4..15d6cd17 100644 --- a/completions/ras-mc-ctl.bash +++ b/completions/ras-mc-ctl.bash @@ -1,77 +1,47 @@ #!/bin/bash -_ras_mc_ctl() { - local cur prev opts +_ras_mc_ctl() +{ + local cur prev command word + local global_opts="dimm mem database db -h --help -V --version -v --verbose -c --config" + local dimm_opts="-h --help -m --mainboard -D --dmidecode -V --vendor -M --model -s --status -p --print-labels -g --guess-labels -r --register-labels -d --delay -L --labeldb -l --layout" + local database_opts="-h --help --indexes-only --since --until --hostname" + COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" - opts="--quiet --mainboard --status --print-labels --guess-labels --register-labels - --delay --labeldb --layout --summary --errors --error-count --since - --vendor-errors-summary --vendor-errors --vendor-platforms --help" - - case "${prev}" in - --delay) - COMPREPLY=($(compgen -W "1 5 10 30 60" -- ${cur})) - return 0 - ;; - --labeldb) - COMPREPLY=($(compgen -f -- ${cur})) - return 0 + case "$prev" in + -c|--config|-L|--labeldb) + COMPREPLY=($(compgen -f -- "$cur")) + return ;; - --since) - local today=$(date +%Y-%m-%d) - local yesterday=$(date -d "1 day ago" +%Y-%m-%d 2>/dev/null || date -v-1d +%Y-%m-%d 2>/dev/null || echo "") - local week_ago=$(date -d "1 week ago" +%Y-%m-%d 2>/dev/null || date -v-1w +%Y-%m-%d 2>/dev/null || echo "") - local month_ago=$(date -d "1 month ago" +%Y-%m-%d 2>/dev/null || date -v-1m +%Y-%m-%d 2>/dev/null || echo "") - - local dates="$today" - [[ -n "$yesterday" ]] && dates="$dates $yesterday" - [[ -n "$week_ago" ]] && dates="$dates $week_ago" - [[ -n "$month_ago" ]] && dates="$dates $month_ago" - - COMPREPLY=($(compgen -W "$dates" -- ${cur})) - return 0 - ;; - --vendor-errors-summary|--vendor-errors) - COMPREPLY=() - return 0 + -d|--delay) + COMPREPLY=($(compgen -W "1 5 10 30 60" -- "$cur")) + return ;; esac - if [[ ${cur} == --*=* ]]; then - local option=${cur%%=*} - local value=${cur#*=} - - case "${option}" in - --delay) - local suggestions="1 5 10 30 60" - COMPREPLY=($(compgen -W "$suggestions" -P "${option}=" -- ${value})) - return 0 - ;; - --labeldb) - COMPREPLY=($(compgen -f -P "${option}=" -- ${value})) - return 0 - ;; - --since) - local today=$(date +%Y-%m-%d) - local yesterday=$(date -d "1 day ago" +%Y-%m-%d 2>/dev/null || date -v-1d +%Y-%m-%d 2>/dev/null || echo "") - local week_ago=$(date -d "1 week ago" +%Y-%m-%d 2>/dev/null || date -v-1w +%Y-%m-%d 2>/dev/null || echo "") - local month_ago=$(date -d "1 month ago" +%Y-%m-%d 2>/dev/null || date -v-1m +%Y-%m-%d 2>/dev/null || echo "") - - local dates="$today" - [[ -n "$yesterday" ]] && dates="$dates $yesterday" - [[ -n "$week_ago" ]] && dates="$dates $week_ago" - [[ -n "$month_ago" ]] && dates="$dates $month_ago" - - COMPREPLY=($(compgen -W "$dates" -P "${option}=" -- ${value})) - return 0 + for word in "${COMP_WORDS[@]:1:COMP_CWORD-1}"; do + case "$word" in + dimm|mem|database|db) + command="$word" + break ;; esac - fi + done - COMPREPLY=($(compgen -W "${opts}" -- ${cur})) - return 0 + case "$command" in + dimm|mem) + COMPREPLY=($(compgen -W "$dimm_opts" -- "$cur")) + ;; + database|db) + COMPREPLY=($(compgen -W "$database_opts" -- "$cur")) + ;; + *) + COMPREPLY=($(compgen -W "$global_opts" -- "$cur")) + ;; + esac } complete -F _ras_mc_ctl ras-mc-ctl diff --git a/completions/ras-mc-ctl.zsh b/completions/ras-mc-ctl.zsh index 1f4fdf15..fbfca5b9 100644 --- a/completions/ras-mc-ctl.zsh +++ b/completions/ras-mc-ctl.zsh @@ -1,47 +1,54 @@ #compdef ras-mc-ctl -_ras-mc-ctl() { +_ras-mc-ctl() +{ local context state line typeset -A opt_args _arguments -C \ - '--quiet[Quiet operation]' \ - '--mainboard[Print mainboard vendor and model for this hardware]' \ - '--status[Print status of EDAC drivers]' \ - '--print-labels[Print Motherboard DIMM labels to stdout]' \ - '--guess-labels[Print DMI labels, when bank locator is available]' \ - '--register-labels[Load Motherboard DIMM labels into EDAC driver]' \ - '--delay=[Delay N seconds before writing DIMM labels]:delay (seconds):' \ - '--labeldb=[Load label database from file DB]:database file:_files' \ - '--layout[Display the memory layout]' \ - '--summary[Presents a summary of the logged errors]' \ - '--errors[Shows the errors stored at the error database]' \ - '--error-count[Shows the corrected and uncorrected error counts using sysfs]' \ - '--since=[Only include events since the date YYYY-MM-DD]:date (YYYY-MM-DD):_dates' \ - '--vendor-errors-summary[Presents a summary of the vendor-specific logged errors]:platform-id:' \ - '--vendor-errors[Shows the vendor-specific errors stored in the error database]:platform-id:' \ - '--vendor-platforms[List the supported platforms with platform-ids for the vendor-specific errors]' \ - '--help[This help message]' \ - && return 0 + '(-h --help)'{-h,--help}'[show command help]' \ + '(-V --version)'{-V,--version}'[show program version]' \ + '(-v --verbose)'{-v,--verbose}'[enable verbose output]' \ + '(-c --config)'{-c,--config}'[use an alternate configuration file]:configuration file:_files' \ + '1:command:->command' \ + '*::command arguments:->arguments' - return 1 -} - -_dates() { - local -a dates - local today=$(date +%Y-%m-%d) - local yesterday=$(date -d "1 day ago" +%Y-%m-%d 2>/dev/null || date -v-1d +%Y-%m-%d 2>/dev/null) - local week_ago=$(date -d "1 week ago" +%Y-%m-%d 2>/dev/null || date -v-1w +%Y-%m-%d 2>/dev/null) - local month_ago=$(date -d "1 month ago" +%Y-%m-%d 2>/dev/null || date -v-1m +%Y-%m-%d 2>/dev/null) - - dates=( - "$today:today" - "$yesterday:yesterday" - "$week_ago:1 week ago" - "$month_ago:1 month ago" - ) - - _describe 'date' dates + case $state in + command) + _values 'command' \ + 'dimm[inspect DIMMs and EDAC]' \ + 'mem[alias for dimm]' \ + 'database[display recorded RAS events]' \ + 'db[alias for database]' + ;; + arguments) + case $words[1] in + dimm|mem) + _arguments \ + '(-h --help)'{-h,--help}'[show command help]' \ + '(-m --mainboard)'{-m,--mainboard}'[print mainboard vendor and model]' \ + '(-D --dmidecode)'{-D,--dmidecode}'[use dmidecode for DIMM information]' \ + '(-V --vendor)'{-V,--vendor}'[override mainboard vendor]:vendor:' \ + '(-M --model)'{-M,--model}'[override mainboard model]:model:' \ + '(-s --status)'{-s,--status}'[print EDAC driver status]' \ + '(-p --print-labels)'{-p,--print-labels}'[print DIMM labels]' \ + '(-g --guess-labels)'{-g,--guess-labels}'[guess DIMM labels from DMI]' \ + '(-r --register-labels)'{-r,--register-labels}'[register DIMM labels]' \ + '(-d --delay)'{-d,--delay}'[delay label registration]:seconds:(1 5 10 30 60)' \ + '(-L --labeldb)'{-L,--labeldb}'[use an alternate label database]:label database:_files' \ + '(-l --layout)'{-l,--layout}'[print the EDAC memory layout]' + ;; + database|db) + _arguments \ + '(-h --help)'{-h,--help}'[show command help]' \ + '--indexes-only[only create missing indexes]' \ + '--since=[include records on or after this date]:date (YYYY-MM-DD):' \ + '--until=[include records on or before this date]:date (YYYY-MM-DD):' \ + '--hostname=[only include records for this hostname]:hostname:' + ;; + esac + ;; + esac } _ras-mc-ctl "$@" diff --git a/config.h.in b/config.h.in new file mode 100644 index 00000000..95f49f44 --- /dev/null +++ b/config.h.in @@ -0,0 +1,35 @@ +#ifndef CONFIG_H +#define CONFIG_H + +/* Feature detection macros */ +#mesondefine HAVE_MYSQL +#mesondefine HAVE_POSTGRESQL +#mesondefine HAVE_SQLITE3 + +#mesondefine HAVE_AER +#mesondefine HAVE_NON_STANDARD +#mesondefine HAVE_ARM +#mesondefine HAVE_DB +#mesondefine HAVE_MCE +#mesondefine HAVE_EXTLOG +#mesondefine HAVE_DEVLINK +#mesondefine HAVE_DISKERROR +#mesondefine HAVE_MEMORY_FAILURE +#mesondefine HAVE_CXL +#mesondefine HAVE_ABRT_REPORT +#mesondefine HAVE_HISI_NS_DECODE +#mesondefine HAVE_MEMORY_CE_PFA +#mesondefine HAVE_MEMORY_ROW_CE_PFA +#mesondefine HAVE_AMP_NS_DECODE +#mesondefine HAVE_OPENBMC_UNIFIED_SEL +#mesondefine HAVE_JAGUAR_NS_DECODE +#mesondefine HAVE_CPU_FAULT_ISOLATION +#mesondefine HAVE_YITIAN_NS_DECODE +#mesondefine HAVE_NVIDIA_NS_DECODE +#mesondefine HAVE_SIGNAL +#mesondefine HAVE_ERST +#mesondefine HAVE_RERI + +#mesondefine RASDAEMON_ENV + +#endif diff --git a/configure.ac b/configure.ac deleted file mode 100644 index 9e6ff93b..00000000 --- a/configure.ac +++ /dev/null @@ -1,351 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -AC_INIT([RASdaemon],[0.8.5]) -AM_SILENT_RULES([yes]) -AC_CANONICAL_TARGET -AC_CONFIG_MACRO_DIR([m4]) -AC_CONFIG_HEADERS([config.h]) -AM_INIT_AUTOMAKE([foreign]) -AC_PROG_CC -AC_PROG_INSTALL -LT_INIT - -X_AC_META - -AC_CONFIG_FILES([ - Makefile - man/Makefile - man/ras-mc-ctl.8 - man/rasdaemon.1 - misc/rasdaemon.spec - util/Makefile - util/ras-mc-ctl -]) - -AC_ARG_ENABLE([all], - AS_HELP_STRING([--enable-all], [enable all features])) - -AC_ARG_ENABLE([sqlite3], - AS_HELP_STRING([--enable-sqlite3], [enable storing data at SQL lite database (currently experimental)])) - -AS_IF([test "x$enable_sqlite3" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_CHECK_LIB(sqlite3, sqlite3_open,[echo "found sqlite3"] , AC_MSG_ERROR([*** Unable to find sqlite3 library]), ) - SQLITE3_LIBS="-lsqlite3" - AC_DEFINE(HAVE_SQLITE3,1,"have sqlite3") - AC_SUBST([WITH_SQLITE3]) -]) - -AM_CONDITIONAL([WITH_SQLITE3], [test x$enable_sqlite3 = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_SQLITE3], [USE_SQLITE3="yes"], [USE_SQLITE3="no"]) - -AC_SUBST([SQLITE3_LIBS]) - -has_libtraceevent_ver=0 -dnl check for tracevent library -PKG_CHECK_MODULES([LIBTRACEEVENT], [libtraceevent], [has_libtraceevent_ver=1]) - -AS_IF([test "$has_libtraceevent_ver" -eq 0], [ - AC_MSG_ERROR([libtraceevent is required but were not found]) -]) - -AC_ARG_ENABLE([aer], - AS_HELP_STRING([--enable-aer], [enable PCIe AER events (currently experimental)])) - -AS_IF([test "x$enable_aer" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_AER,1,"have PCIe AER events collect") - AC_SUBST([WITH_AER]) - - has_libpci_ver=0 - dnl check for pciutils library - PKG_CHECK_MODULES([LIBPCI], [libpci], [has_libpci_ver=1]) - - AS_IF([test "$has_libpci_ver" -eq 0], [ - AC_MSG_ERROR([libpci is required but were not found]) -]) -]) -AM_CONDITIONAL([WITH_AER], [test x$enable_aer = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_AER], [USE_AER="yes"], [USE_AER="no"]) - - -AC_ARG_ENABLE([non_standard], - AS_HELP_STRING([--enable-non-standard], [enable NON_STANDARD events (currently experimental)])) - -AS_IF([test "x$enable_non_standard" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_NON_STANDARD,1,"have UNKNOWN_SEC events collect") - AC_SUBST([WITH_NON_STANDARD]) -]) -AM_CONDITIONAL([WITH_NON_STANDARD], [test x$enable_non_standard = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_NON_STANDARD], [USE_NON_STANDARD="yes"], [USE_NON_STANDARD="no"]) - -AC_ARG_ENABLE([arm], - AS_HELP_STRING([--enable-arm], [enable ARM events (currently experimental)])) - -AS_IF([test "x$enable_arm" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_ARM,1,"have ARM events collect") - AC_SUBST([WITH_ARM]) -]) -AM_CONDITIONAL([WITH_ARM], [test x$enable_arm = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_ARM], [USE_ARM="yes"], [USE_ARM="no"]) - -AC_ARG_ENABLE([mce], - AS_HELP_STRING([--enable-mce], [enable MCE events (currently experimental)])) - -AS_IF([test "x$enable_mce" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_MCE,1,"have PCIe MCE events collect") - AC_SUBST([WITH_MCE]) -]) -AM_CONDITIONAL([WITH_MCE], [test x$enable_mce = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_MCE], [USE_MCE="yes"], [USE_MCE="no"]) - -AC_ARG_ENABLE([extlog], - AS_HELP_STRING([--enable-extlog], [enable EXTLOG events (currently experimental)])) - -AS_IF([test "x$enable_extlog" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_EXTLOG,1,"have EXTLOG events collect") - AC_SUBST([WITH_EXTLOG]) -]) -AM_CONDITIONAL([WITH_EXTLOG], [test x$enable_extlog = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_EXTLOG], [USE_EXTLOG="yes"], [USE_EXTLOG="no"]) - -AC_ARG_ENABLE([devlink], - AS_HELP_STRING([--enable-devlink], [enable devlink health events (currently experimental)])) - -AS_IF([test "x$enable_devlink" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_DEVLINK,1,"have devlink health events collect") - AC_SUBST([WITH_DEVLINK]) -]) -AM_CONDITIONAL([WITH_DEVLINK], [test x$enable_devlink = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_DEVLINK], [USE_DEVLINK="yes"], [USE_DEVLINK="no"]) - -AC_ARG_ENABLE([diskerror], - AS_HELP_STRING([--enable-diskerror], [enable disk I/O error events (currently experimental)])) - -AS_IF([test "x$enable_diskerror" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_DISKERROR,1,"have disk I/O errors collect") - AC_SUBST([WITH_DISKERROR]) -]) -AM_CONDITIONAL([WITH_DISKERROR], [test x$enable_diskerror = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_DISKERROR], [USE_DISKERROR="yes"], [USE_DISKERROR="no"]) - -AC_COMPILE_IFELSE([AC_LANG_SOURCE([[ -#include -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) -#ifdef RHEL_RELEASE_CODE -#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(9, 1) -# error kernel too old -#endif -#else -# error kernel too old -#endif -#endif -]])], [AC_DEFINE(HAVE_BLK_RQ_ERROR,1,"have block_rq_error tracepoint")]) - -AC_ARG_ENABLE([memory_failure], - AS_HELP_STRING([--enable-memory-failure], [enable memory failure events (currently experimental)])) - -AS_IF([test "x$enable_memory_failure" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_MEMORY_FAILURE,1,"have memory failure events collect") - AC_SUBST([WITH_MEMORY_FAILURE]) -]) -AM_CONDITIONAL([WITH_MEMORY_FAILURE], [test x$enable_memory_failure = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_MEMORY_FAILURE], [USE_MEMORY_FAILURE="yes"], [USE_MEMORY_FAILURE="no"]) - -AC_ARG_ENABLE([cxl], - AS_HELP_STRING([--enable-cxl], [enable CXL events (currently experimental)])) - -AS_IF([test "x$enable_cxl" = "xyes" || test "x$enable_all" == "xyes"], [ - AC_DEFINE(HAVE_CXL,1,"have CXL events collect") - AC_SUBST([WITH_CXL]) -]) -AM_CONDITIONAL([WITH_CXL], [test x$enable_cxl = xyes || test x$enable_all == xyes]) -AM_COND_IF([WITH_CXL], [USE_CXL="yes"], [USE_CXL="no"]) - -AC_ARG_ENABLE([abrt_report], - AS_HELP_STRING([--enable-abrt-report], [enable report event to ABRT (currently experimental)])) - -AS_IF([test "x$enable_abrt_report" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_ABRT_REPORT,1,"have report event to ABRT") - AC_SUBST([WITH_ABRT_REPORT]) -]) -AM_CONDITIONAL([WITH_ABRT_REPORT], [test x$enable_abrt_report = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_ABRT_REPORT], [USE_ABRT_REPORT="yes"], [USE_ABRT_REPORT="no"]) - -AC_ARG_ENABLE([hisi_ns_decode], - AS_HELP_STRING([--enable-hisi-ns-decode], [enable HISI_NS_DECODE events (currently experimental)])) - -AS_IF([test "x$enable_hisi_ns_decode" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_HISI_NS_DECODE,1,"have HISI UNKNOWN_SEC events decode") - AC_SUBST([WITH_HISI_NS_DECODE]) -]) -AM_CONDITIONAL([WITH_HISI_NS_DECODE], [test x$enable_hisi_ns_decode = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_HISI_NS_DECODE], [USE_HISI_NS_DECODE="yes"], [USE_HISI_NS_DECODE="no"]) - -AC_ARG_ENABLE([memory_ce_pfa], - AS_HELP_STRING([--enable-memory-ce-pfa], [enable memory Corrected Error predictive failure analysis])) - -AS_IF([test "x$enable_memory_ce_pfa" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_MEMORY_CE_PFA,1,"have memory corrected error predictive failure analysis") - AC_SUBST([WITH_MEMORY_CE_PFA]) -]) -AM_CONDITIONAL([WITH_MEMORY_CE_PFA], [test x$enable_memory_ce_pfa = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_MEMORY_CE_PFA], [USE_MEMORY_CE_PFA="yes"], [USE_MEMORY_CE_PFA="no"]) - -AC_ARG_ENABLE([memory_row_ce_pfa], - AS_HELP_STRING([--enable-memory-row-ce-pfa], [enable memory row Corrected Error predictive failure analysis])) - -AS_IF([test "x$enable_memory_row_ce_pfa" = "xyes" || test "x$enable_all" == "xyes"], [ - AC_DEFINE(HAVE_MEMORY_ROW_CE_PFA,1,"have memory row corrected error predictive failure analysis") - AC_SUBST([WITH_MEMORY_ROW_CE_PFA]) -]) -AM_CONDITIONAL([WITH_MEMORY_ROW_CE_PFA], [test x$enable_memory_row_ce_pfa = xyes || test x$enable_all == xyes]) -AM_COND_IF([WITH_MEMORY_ROW_CE_PFA], [USE_MEMORY_ROW_CE_PFA="yes"], [USE_MEMORY_ROW_CE_PFA="no"]) - -AM_CONDITIONAL([WITH_PFA], [test x$USE_MEMORY_CE_PFA = xyes || test x$USE_MEMORY_ROW_CE_PFA = xyes]) - -AC_ARG_ENABLE([amp_ns_decode], - AS_HELP_STRING([--enable-amp-ns-decode], [enable AMP_NS_DECODE events (currently experimental)])) - -AS_IF([test "x$enable_amp_ns_decode" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_AMP_NS_DECODE,1,"have AMP UNKNOWN_SEC events decode") - AC_SUBST([WITH_AMP_NS_DECODE]) -]) -AM_CONDITIONAL([WITH_AMP_NS_DECODE], [test x$enable_amp_ns_decode = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_AMP_NS_DECODE], [USE_AMP_NS_DECODE="yes"], [USE_AMP_NS_DECODE="no"]) - -AC_ARG_ENABLE([openbmc_unified_sel], - AS_HELP_STRING([--enable-openbmc-unified-sel], [enable OPENBMC_UNIFIED_SEL events (currently experimental)])) - -AS_IF([test "x$enable_openbmc_unified_sel" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_OPENBMC_UNIFIED_SEL,1,"have OpenBMC unified SEL") - AC_SUBST([WITH_OPENBMC_UNIFIED_SEL]) -]) -AM_CONDITIONAL([WITH_OPENBMC_UNIFIED_SEL], [test x$enable_openbmc_unified_sel = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_OPENBMC_UNIFIED_SEL], [USE_OPENBMC_UNIFIED_SEL="yes"], [USE_OPENBMC_UNIFIED_SEL="no"]) - -AC_ARG_ENABLE([jaguar_ns_decode], - AS_HELP_STRING([--enable-jaguar-ns-decode], [enable JAGUAR_NS_DECODE events (currently experimental)])) - -AS_IF([test "x$enable_jaguar_ns_decode" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_JAGUAR_NS_DECODE,1,"have JaguarMicro UNKNOWN_SEC events decode") - AC_SUBST([WITH_JAGUAR_NS_DECODE]) -]) -AM_CONDITIONAL([WITH_JAGUAR_NS_DECODE], [test x$enable_jaguar_ns_decode = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_JAGUAR_NS_DECODE], [USE_JAGUAR_NS_DECODE="yes"], [USE_JAGUAR_NS_DECODE="no"]) - -AC_ARG_ENABLE([cpu_fault_isolation], - AS_HELP_STRING([--enable-cpu-fault-isolation], [enable cpu online fault isolation])) - -AS_IF([test "x$enable_cpu_fault_isolation" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_CPU_FAULT_ISOLATION,1,"have cpu online fault isolation") - AC_SUBST([WITH_CPU_FAULT_ISOLATION]) -]) -AM_CONDITIONAL([WITH_CPU_FAULT_ISOLATION], [test x$enable_cpu_fault_isolation = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_CPU_FAULT_ISOLATION], [USE_CPU_FAULT_ISOLATION="yes"], [USE_CPU_FAULT_ISOLATION="no"]) - -AC_ARG_ENABLE([yitian_ns_decode], - AS_HELP_STRING([--enable-yitian-ns-decode], [enable YITIAN_NS_DECODE events (currently experimental)])) - -AS_IF([test "x$enable_yitian_ns_decode" = "xyes" || test "x$enable_all" == "xyes"], [ - AC_DEFINE(HAVE_YITIAN_NS_DECODE,1,"have YITIAN UNKNOWN_SEC events decode") - AC_SUBST([WITH_YITIAN_NS_DECODE]) -]) -AM_CONDITIONAL([WITH_YITIAN_NS_DECODE], [test x$enable_yitian_ns_decode = xyes || test x$enable_all == xyes]) -AM_COND_IF([WITH_YITIAN_NS_DECODE], [USE_YITIAN_NS_DECODE="yes"], [USE_YITIAN_NS_DECODE="no"]) - -AC_ARG_ENABLE([nvidia-ns-decode], - AS_HELP_STRING([--enable-nvidia-ns-decode], [enable NVIDIA_NS_DECODE events])) - -AS_IF([test "x$enable_nvidia_ns_decode" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_NVIDIA_NS_DECODE,1,"have NVIDIA UNKNOWN_SEC events decode") - AC_SUBST([WITH_NVIDIA_NS_DECODE]) -]) -AM_CONDITIONAL([WITH_NVIDIA_NS_DECODE], [test x$enable_nvidia_ns_decode = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_NVIDIA_NS_DECODE], [USE_NVIDIA_NS_DECODE="yes"], [USE_NVIDIA_NS_DECODE="no"]) - -AC_ARG_ENABLE([signal], - AS_HELP_STRING([--enable-signal], [enable signal event(currently experimental)])) - -AS_IF([test "x$enable_signal" = "xyes" || test "x$enable_all" == "xyes"], [ - AC_DEFINE(HAVE_SIGNAL,1,"have signal event") - AC_SUBST([WITH_SIGNAL]) -]) -AM_CONDITIONAL([WITH_SIGNAL], [test x$enable_signal = xyes || test x$enable_all == xyes]) -AM_COND_IF([WITH_SIGNAL], [USE_SIGNAL="yes"], [USE_SIGNAL="no"]) - -AS_IF([test "x$enable_memory_ce_pfa" = "xyes" || test "x$enable_memory_row_ce_pfa" = "xyes" || test "x$enable_memory_failure" = "xyes" || test "x$enable_all" == "xyes"], [ - AC_DEFINE(HAVE_POISON_PAGE_STAT,1,"have poison page statistics") - AC_SUBST([WITH_POISON_PAGE_STAT]) -]) -AM_CONDITIONAL([WITH_POISON_PAGE_STAT], [test "x$enable_memory_ce_pfa" = "xyes" || test "x$enable_memory_row_ce_pfa" = "xyes" || test "x$enable_memory_failure" = "xyes" || test "x$enable_all" == "xyes" ]) - -AC_ARG_ENABLE([erst], - AS_HELP_STRING([--enable-erst], [enable erst (currently experimental)])) - -AS_IF([test "x$enable_erst" = "xyes" || test "x$enable_all" == "xyes"], [ - AC_DEFINE(HAVE_ERST,1,"have ERST") - AC_SUBST([WITH_ERST]) -]) -AM_CONDITIONAL([WITH_ERST], [test x$enable_erst = xyes || test x$enable_all == xyes]) -AM_COND_IF([WITH_ERST], [USE_ERST="yes"], [USE_ERST="no"]) - -AC_ARG_ENABLE([reri], - AS_HELP_STRING([--enable-reri], [enable RISC-V RERI events (RISC-V RAS Error Report Register Interface)])) - -AS_IF([test "x$enable_reri" = "xyes" || test "x$enable_all" = "xyes"], [ - AC_DEFINE(HAVE_RERI,1,"have RISC-V RERI events collect") - AC_SUBST([WITH_RERI]) -]) -AM_CONDITIONAL([WITH_RERI], [test x$enable_reri = xyes || test x$enable_all = xyes]) -AM_COND_IF([WITH_RERI], [USE_RERI="yes"], [USE_RERI="no"]) - -test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc - -CFLAGS="$CFLAGS -Wall -Wmissing-prototypes -Wstrict-prototypes" - -AC_SUBST([rasstatedir], [$localstatedir/lib/rasdaemon]) -AC_DEFINE_DIR([RASSTATEDIR], [rasstatedir], [rasdaemon db store state dir]) -AC_SUBST([RASSTATEDIR]) - -AC_ARG_WITH(sysconfdefdir, - AS_HELP_STRING([--with-sysconfdefdir=DIR],[rasdaemon environment file dir]), - [SYSCONFDEFDIR=$withval], - [SYSCONFDEFDIR=/etc/sysconfig]) -AC_SUBST([SYSCONFDEFDIR]) - -AC_DEFINE([RAS_DB_FNAME], ["ras-mc_event.db"], [ras events database]) -AC_SUBST([RAS_DB_FNAME], ["ras-mc_event.db"]) - -AC_OUTPUT - -dnl --------------------------------------------------------------------- -dnl compile time options summary - -cat < #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" unsigned int bitfield_msg(char *buf, size_t len, const char * const *bitarray, unsigned int array_len, diff --git a/bitfield.h b/core/bitfield.h similarity index 100% rename from bitfield.h rename to core/bitfield.h diff --git a/core/modules.c b/core/modules.c new file mode 100644 index 00000000..2c03ab68 --- /dev/null +++ b/core/modules.c @@ -0,0 +1,178 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* +* Copyright (C) 2026 Mauro Carvalho Chehab +*/ + +#include +#include + +#include "core/modules.h" +#include "core/ras-logger.h" + +/* Let's not declare it as static, as we want to access it on unit tests */ +struct module_list ras_modules = { 0 }; + +/* + * Public functions + */ + +int module_register(const struct ras_module_entry *entry) +{ + struct ras_module_entry_runtime **head = &ras_modules.head; + struct ras_module_entry_runtime *new, *cur, *prev = NULL; + + if (!entry) { + log(ALL, LOG_ERR, "module entry is missing!\n"); + return -EINVAL; + } + + new = calloc(1, sizeof(*new)); + if (!new) { + log(ALL, LOG_ERR, "no memory to register module %s\n", + entry->name); + return -ENOMEM; + } + + new->e = entry; + + /* Keep it alphabetically sorted */ + for (cur = ras_modules.head; cur; cur = cur->next) { + if (strcmp(entry->name, cur->e->name) < 0) + break; + + prev = cur; + } + + if (!prev) { + new->next =*head; + *head = new; + } else { + new->next = prev->next; + prev->next = new; + } + + return 0; +} + +bool modules_have_sql_backend(void) +{ + struct ras_module_entry_runtime *entry = ras_modules.head; + + while (entry) { + if (entry->e->level == DB_MODULE && entry->is_enabled) + return true; + + entry = entry->next; + } + + return false; +} + +int module_init(struct ras_events *ras, const char *name) +{ + struct ras_module_entry_runtime *entry; + + for (entry = ras_modules.head; entry; entry = entry->next) { + if (entry->e->postpone_init) + continue; + + if (!strcmp(name, entry->e->name) && entry->e->init) { + if (entry->e->init(name, ras, &entry->priv)) { + log(ALL, LOG_ERR, + "module %s init failed\n", + entry->e->name); + } else { + entry->is_enabled = true; + + return false; + } + } + } + + return true; +} + +int module_cleanup(const char *name) +{ + struct ras_module_entry_runtime *entry; + + for (entry = ras_modules.head; entry; entry = entry->next) { + if (!strcmp(name, entry->e->name) && entry->e->cleanup) { + entry->e->cleanup(entry->e, &entry->priv); + entry->is_enabled = false; + + return false; + } + } + + return true; +} + +void modules_init(struct ras_events *ras) +{ + struct ras_module_entry_runtime *entry; + + for (int level = 0; level < MAX_LEVELS; level++) { + for (entry = ras_modules.head; entry; entry = entry->next) { + if (level == entry->e->level && entry->e->init) { + if (entry->e->init(entry->e->name, + ras, &entry->priv)) { + log(ALL, LOG_ERR, + "module %s init failed\n", + entry->e->name); + } + } + } + } +} + +bool module_is_enabled(const char *name) +{ + struct ras_module_entry_runtime *entry = ras_modules.head; + + while (entry) { + if (!strcmp(entry->e->name, name)) + return true; + + entry = entry->next; + } + + return false; +} + +void modules_unregister(void) +{ + struct ras_module_entry_runtime *entry, *tmp; + + /* + * Cleanup each module + * + * NOTE: + * The logic here assumes that modules at the same level + * can be unregistered in any order. It means that modules + * that has HAVE_ dependencies to other modules at event_list + * needs to handle cleanup() even if called after other event + * list requrements. + */ + for (int level = MAX_LEVELS - 1; level >= 0; level--) { + entry = ras_modules.head; + + while (entry) { + tmp = entry->next; + if (entry->e->level == level && entry->e->cleanup && entry->is_enabled) + entry->e->cleanup(entry->e, entry->priv); + + entry = entry->next; + } + } + + /* Free them and remove head */ + entry = ras_modules.head; + while (entry) { + tmp = entry->next; + free(entry); + entry = tmp; + } + + ras_modules.head = NULL; +} diff --git a/core/modules.h b/core/modules.h new file mode 100644 index 00000000..5b3dcf76 --- /dev/null +++ b/core/modules.h @@ -0,0 +1,77 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +#ifndef RAS_MODULE_H +#define RAS_MODULE_H + +#include + +struct ras_events; + +enum init_level { + CORE_MODULE, + DB_MODULE, + BASE_EVENT_MODULE, + SUB_EVENT_MODULE, + + /* Should be the last one */ + MAX_LEVELS +}; + +/* Module entry: one per module, chained via ->next */ +struct ras_module_entry { + const char *name; + + const int (*init)(const char *name, struct ras_events *ras, void **priv); + const void (*cleanup)(const struct ras_module_entry *entry, void *priv); + + const enum init_level level; + bool postpone_init; +}; + + +struct ras_module_entry_runtime { + const struct ras_module_entry *e; + + bool is_enabled; + + void *priv; + + struct ras_module_entry_runtime *next; +}; + +/* + * Priority list - linked list of modules for a given priority level. + * head = NULL means the list is empty. + */ +struct module_list { + struct ras_module_entry_runtime *head; + struct module_list *next; +}; + +/* + * Register one module into the given priority list. + * Returns 0 on success, non-zero if registration failed. + */ +int module_register(const struct ras_module_entry *entry); + +int module_init(struct ras_events *ras, const char *name); +int module_cleanup(const char *name); + +void modules_init(struct ras_events *ras); +void modules_unregister(void); + +/* + * Check whether any SQL backend has been initialized at runtime. + */ +bool modules_have_sql_backend(void); + +/* + * Check whether a named event handler has been registered and enabled in the + * event-handler list. + */ +bool module_is_enabled(const char *name); + +#endif /* RAS_MODULE_H */ diff --git a/queue.c b/core/queue.c similarity index 97% rename from queue.c rename to core/queue.c index 8a8c5004..0c410565 100644 --- a/queue.c +++ b/core/queue.c @@ -7,8 +7,8 @@ #include #include -#include "queue.h" -#include "ras-logger.h" +#include "core/queue.h" +#include "core/ras-logger.h" int is_empty(struct link_queue *queue) { diff --git a/queue.h b/core/queue.h similarity index 100% rename from queue.h rename to core/queue.h diff --git a/core/ras-env.c b/core/ras-env.c new file mode 100644 index 00000000..e01ebdcb --- /dev/null +++ b/core/ras-env.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +#include +#include +#include +#include +#include +#include + +#include "ras-logger.h" + +/* Maximum number of environment variables to load */ + +/* Maximum line length */ +#define MAX_LINE_LEN 1024 + +/** + * Trim leading and trailing whitespace in-place. + */ +static void ras_trim(char *s, bool remove_commas) +{ + char *start = s; + char *end = s + strlen(s) - 1; + + while (end > s && (*end == ' ' || *end == '\t')) + *end-- = '\0'; + + while (*start == ' ' || *start == '\t') + start++; + + if (remove_commas) { + if (strlen(s) >= 2 && *start == '"' && s[strlen(s) - 1] == '"') { + s[strlen(s) - 1] = '\0'; + start++; /* skip leading quote */ + } + } + + if (start != s) + memmove(s, start, strlen(start) + 1); +} + +/** + * Parse a configuration file and set environment variables. + * + * Format: + * KEY=value + * + * Empty lines and lines starting with '#' or ';' are ignored. + * + * Spaces and tabs are allowed. + * + * @param fname Path to the configuration file. + * @return 0 on success, -1 on error. + */ +int ras_set_env(const char *fname) +{ + char line[MAX_LINE_LEN], *key, *value, *p; + FILE *fp = NULL; + int nenv = 0; + int ln = 1; + + fp = fopen(fname, "r"); + if (!fp) { + log(TERM, LOG_ERR, "Failed to open config file %s: %s\n", + fname, strerror(errno)); + return -1; + } + + while (fgets(line, sizeof(line), fp)) { + ras_trim(line, false); + + if (!*line || line[0] == '#' || line[0] == ';') { + ln++; + continue; + } + + key = strtok(line, "="); + if (!key) { + ln++; + continue; + } + + value = strtok(NULL, "\n"); + if (!value) { + ln++; + continue; + } + + ras_trim(key, false); + ras_trim(value, true); + + /* Validate key is not empty after trimming */ + if (!*key) { + log(TERM, LOG_ERR, + "line %d: Empty key in config line\n", ln); + fclose(fp); + return -1; + } + + if (setenv(key, value, 0) != 0) { + p = getenv(key); + if (p) { + log(TERM, LOG_INFO, "Skipping %s=%s (already set to %s)\n", + key, value, p); + } else { + log(TERM, LOG_ERR, + "line %d: failed to set env var %s to %s: %s\n", + ln, key, value, strerror(errno)); + } + } else { + nenv++; + } + ln++; + } + + fclose(fp); + + log(TERM, LOG_INFO, "Read %d config vars from %s.\n", nenv, fname); + + return 0; +} diff --git a/core/ras-env.h b/core/ras-env.h new file mode 100644 index 00000000..b8391c62 --- /dev/null +++ b/core/ras-env.h @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +int ras_set_env(const char *path); diff --git a/ras-events.c b/core/ras-events.c similarity index 94% rename from ras-events.c rename to core/ras-events.c index ab2dd518..0f14e5df 100644 --- a/ras-events.c +++ b/core/ras-events.c @@ -20,25 +20,48 @@ #include #include -#include "ras-aer-handler.h" -#include "ras-arm-handler.h" -#include "ras-cpu-isolation.h" -#include "ras-cxl-handler.h" -#include "ras-devlink-handler.h" -#include "ras-diskerror-handler.h" -#include "ras-events.h" -#include "ras-extlog-handler.h" -#include "ras-logger.h" -#include "ras-aer-handler.h" -#include "ras-mce-handler.h" -#include "ras-mc-handler.h" -#include "ras-memory-failure-handler.h" -#include "ras-non-standard-handler.h" -#include "ras-page-isolation.h" -#include "ras-signal-handler.h" -#include "ras-record.h" -#include "ras-reri-handler.h" -#include "trigger.h" +#include "modules/ras-aer-handler.h" +#include "events-arch-arm/ras-arm-handler.h" +#include "modules/ras-cpu-isolation.h" +#include "events/ras-cxl-handler.h" +#include "events/ras-devlink-handler.h" +#include "events/ras-diskerror-handler.h" +#include "core/ras-events.h" +#include "core/ras-extlog-handler.h" +#include "core/ras-logger.h" +#include "modules/ras-aer-handler.h" +#include "events-arch-x86/ras-mce-handler.h" +#include "core/ras-mc-handler.h" +#include "events/ras-memory-failure-handler.h" +#include "events-arch-arm/ras-non-standard-handler.h" +#include "modules/ras-page-isolation.h" +#include "events/ras-signal-handler.h" +#include "db/ras-record.h" +#include "events/ras-reri-handler.h" +#include "core/trigger.h" + +#define TOOL_NAME "rasdaemon" + +/* Compatibility with libtraceevent versions that predate the host aliases. */ +#ifndef KBUFFER_LSIZE_SAME_AS_HOST +# if __SIZEOF_LONG__ == 8 +# define KBUFFER_LSIZE_SAME_AS_HOST KBUFFER_LSIZE_8 +# elif __SIZEOF_LONG__ == 4 +# define KBUFFER_LSIZE_SAME_AS_HOST KBUFFER_LSIZE_4 +# else +# error "Unsupported long size" +# endif +#endif + +#ifndef KBUFFER_ENDIAN_SAME_AS_HOST +# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define KBUFFER_ENDIAN_SAME_AS_HOST KBUFFER_ENDIAN_LITTLE +# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# define KBUFFER_ENDIAN_SAME_AS_HOST KBUFFER_ENDIAN_BIG +# else +# error "Unsupported byte order" +# endif +#endif /* * Polling time, if read() doesn't block. Currently, trace_pipe_raw never @@ -55,6 +78,7 @@ #endif char *choices_disable; +long user_hz; static const struct event_trigger event_triggers[] = { { "mc_event", &mc_event_trigger_setup }, @@ -576,8 +600,12 @@ static int read_ras_event_all_cpus(struct pthread_data *pdata, log(TERM, LOG_INFO, "Listening to events for cpus 0 to %d\n", n_cpus - 1); if (pdata[0].ras->record_events) { - if (ras_mc_event_opendb(pdata[0].cpu, pdata[0].ras)) +#ifdef HAVE_DB + if (ras_mc_event_opendb(pdata[0].cpu, pdata[0].ras)) { + log(TERM, LOG_ERR, "Failed to open SQL database\n"); goto error; + } +#endif #ifdef HAVE_NON_STANDARD if (ras_ns_add_vendor_tables(pdata[0].ras)) log(TERM, LOG_ERR, "Can't add vendor table\n"); @@ -756,6 +784,7 @@ static void *handle_ras_events_cpu(void *priv) log(TERM, LOG_INFO, "Listening to events on cpu %d\n", pdata->cpu); if (pdata->ras->record_events) { pthread_mutex_lock(&pdata->ras->db_lock); +#ifdef HAVE_DB if (ras_mc_event_opendb(pdata->cpu, pdata->ras)) { pthread_mutex_unlock(&pdata->ras->db_lock); log(TERM, LOG_ERR, "Can't open database\n"); @@ -764,6 +793,7 @@ static void *handle_ras_events_cpu(void *priv) free(page); return 0; } +#endif #ifdef HAVE_NON_STANDARD if (ras_ns_add_vendor_tables(pdata->ras)) log(TERM, LOG_ERR, "Can't add vendor table\n"); @@ -997,14 +1027,14 @@ static int add_event_handler(struct ras_events *ras, struct tep_handle *pevent, return 0; } -int handle_ras_events(int record_events, int enable_ipmitool) +int handle_ras_events(struct ras_events *ras, int record_events, + int enable_ipmitool) { int rc, page_size, i; int num_events = 0; unsigned int cpus; struct tep_handle *pevent = NULL; struct pthread_data *data = NULL; - struct ras_events *ras = NULL; #ifdef HAVE_DEVLINK char *filter_str = NULL; #endif @@ -1012,12 +1042,6 @@ int handle_ras_events(int record_events, int enable_ipmitool) char signal_filter[64]; #endif - ras = calloc(1, sizeof(*ras)); - if (!ras) { - log(TERM, LOG_ERR, "Can't allocate memory for ras struct\n"); - return -errno; - } - rc = get_tracing_dir(ras); if (rc < 0) { log(TERM, LOG_ERR, "Can't locate a mounted debugfs\n"); @@ -1295,7 +1319,7 @@ int handle_ras_events(int record_events, int enable_ipmitool) /* Poll doesn't work on this kernel. Fallback to pthread way */ if (rc == LEGACY_KERNEL) { if (pthread_mutex_init(&ras->db_lock, NULL) != 0) { - log(SYSLOG, LOG_INFO, "sqlite db lock init has failed\n"); + log(SYSLOG, LOG_INFO, "SQL DB lock init has failed\n"); goto err; } diff --git a/ras-events.h b/core/ras-events.h similarity index 75% rename from ras-events.h rename to core/ras-events.h index e6c97262..4c33e9d6 100644 --- a/ras-events.h +++ b/core/ras-events.h @@ -10,9 +10,10 @@ #include #include -#include "types.h" +#include "core/types.h" extern char *choices_disable; +extern long user_hz; struct mce_priv; struct ras_mc_offline_event; @@ -41,30 +42,33 @@ enum { NR_EVENTS }; +struct ras_db; + struct ras_events { - char tracing[MAX_PATH + 1]; - struct tep_handle *pevent; - int page_size; + char tracing[MAX_PATH + 1]; + struct tep_handle *pevent; + int page_size; /* Booleans */ - unsigned use_uptime: 1; - unsigned record_events: 1; + unsigned use_uptime: 1; + unsigned record_events: 1; /* For timestamp */ - time_t uptime_diff; + time_t uptime_diff; - /* For ras-record */ - void *db_priv; - int db_ref_count; - pthread_mutex_t db_lock; + /* For ras-record and ras-db */ + struct ras_db *db; + void *db_priv; + int db_ref_count; + pthread_mutex_t db_lock; /* For the mce handler */ - struct mce_priv *mce_priv; + struct mce_priv *mce_priv; /* For ABRT socket*/ - int socketfd; + int socketfd; - struct tep_event_filter *filters[NR_EVENTS]; + struct tep_event_filter *filters[NR_EVENTS]; }; struct pthread_data { @@ -100,8 +104,9 @@ enum ghes_severity { /* Function prototypes */ int toggle_ras_mc_event(int enable); -int handle_ras_events(int record_events, int enable_ipmitool); int ras_offline_mce_event(struct ras_mc_offline_event *event); -int handle_ras_events(int record_events, int enable_ipmitool); + +int handle_ras_events(struct ras_events *ras, + int record_events, int enable_ipmitool); #endif diff --git a/ras-extlog-handler.c b/core/ras-extlog-handler.c similarity index 97% rename from ras-extlog-handler.c rename to core/ras-extlog-handler.c index 56acf1a3..85859263 100644 --- a/ras-extlog-handler.c +++ b/core/ras-extlog-handler.c @@ -13,10 +13,10 @@ #include #include -#include "ras-extlog-handler.h" -#include "ras-logger.h" -#include "ras-report.h" -#include "types.h" +#include "core/ras-extlog-handler.h" +#include "core/ras-logger.h" +#include "modules/ras-report.h" +#include "core/types.h" static char *err_type(int etype) { @@ -294,7 +294,7 @@ int ras_extlog_mem_event_handler(struct trace_seq *s, report_extlog_mem_event(ras, record, s, &ev); - ras_store_extlog_mem_record(ras, &ev); + db_extlog_mem_record(ras, &ev); return 0; } diff --git a/ras-extlog-handler.h b/core/ras-extlog-handler.h similarity index 92% rename from ras-extlog-handler.h rename to core/ras-extlog-handler.h index 4a973237..af415d06 100644 --- a/ras-extlog-handler.h +++ b/core/ras-extlog-handler.h @@ -10,7 +10,7 @@ #include #include -#include "ras-events.h" +#include "core/ras-events.h" int ras_extlog_mem_event_handler(struct trace_seq *s, struct tep_record *record, diff --git a/core/ras-logger.c b/core/ras-logger.c new file mode 100644 index 00000000..b62feedf --- /dev/null +++ b/core/ras-logger.c @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2013 Petr Holasek + */ + +#include +#include + +#include "core/ras-logger.h" + +static bool stdout_is_vt = false; + +bool mock_output = false; + +char *mock_log_buf = NULL; +size_t mock_log_len = 0; + +const char *reset_color = ""; + +void ras_logger_clean(void) +{ + free(mock_log_buf); + mock_log_buf = NULL; + mock_log_len = 0; +} + +void ras_logger_flush(void) +{ + fputs(mock_log_buf, stderr); + ras_logger_clean(); +} + +enum ansi_color { + GREEN, + RED, + YELLOW, + RESET, + + ANSI_MAX_COLORS +}; + +static const char *const codes[] = { + [LOG_EMERG] = "\033[1;37;41m", + [LOG_ALERT] = "\033[31;47m", + [LOG_CRIT] = "\033[33;47m", + [LOG_ERR] = "\033[31;1m", + [LOG_WARNING] = "\033[36;1m", + [LOG_NOTICE] = "\033[37;1m", + [LOG_INFO] = "\033[37m", + [LOG_DEBUG] = "\033[0m", +}; + +const char *log_color(int color) +{ + if (!stdout_is_vt || color > LOG_DEBUG) + return ""; + + return codes[color]; +} + +__attribute__((constructor(200))) void ras_logger_init(void) +{ + stdout_is_vt = isatty(fileno(stdout)); + + reset_color = log_color(LOG_DEBUG); +} diff --git a/core/ras-logger.h b/core/ras-logger.h new file mode 100644 index 00000000..bfb7fce0 --- /dev/null +++ b/core/ras-logger.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * Copyright (C) 2013 Petr Holasek + */ + +#ifndef __RAS_LOGGER_H +#define __RAS_LOGGER_H + +#include +#include +#include +#include +#include +#include +#include + +#include "core/types.h" + +/* + * Logging macros + */ + +#define binary_name (program_invocation_short_name) + +#define SYSLOG BIT(0) +#define TERM BIT(1) +#define ALL (SYSLOG | TERM) + +extern bool mock_output; +extern char *mock_log_buf ; +extern size_t mock_log_len; + +extern const char *reset_color; + +const char *log_color(int color); + + +/* TODO: global logging limit mask */ + +#define log(where, level, fmt, args...) do { \ + if (mock_output) { \ + char tmp[4096] ; \ + int len = snprintf(tmp, sizeof(tmp), \ + "\t" fmt, ##args); \ + size_t new_len = mock_log_len + len; \ + mock_log_buf = realloc(mock_log_buf, new_len + 1); \ + assert(mock_log_buf); \ + strcpy(mock_log_buf + mock_log_len, tmp); \ + mock_log_len = new_len; \ + } else { \ + if ((where) & SYSLOG) \ + syslog(level, fmt, ##args); \ + if ((where) & TERM) { \ + fputs(log_color(level), stderr); \ + fprintf(stderr, "%s: ", binary_name); \ + fprintf(stderr, fmt, ##args); \ + fputs(reset_color, stderr); \ + fflush(stderr); \ + } \ + } \ +} while (0) + +/* Ancillary routines to output logs when mock_output is true */ + +void ras_logger_clean(void); +void ras_logger_flush(void); + +#endif diff --git a/ras-mc-handler.c b/core/ras-mc-handler.c similarity index 97% rename from ras-mc-handler.c rename to core/ras-mc-handler.c index 0e9f5638..b3703ffc 100644 --- a/ras-mc-handler.c +++ b/core/ras-mc-handler.c @@ -4,7 +4,6 @@ * Copyright (C) 2013 Mauro Carvalho Chehab */ -#define _GNU_SOURCE #include #include #include @@ -13,12 +12,12 @@ #include #include -#include "ras-logger.h" -#include "ras-mc-handler.h" -#include "ras-page-isolation.h" -#include "ras-report.h" -#include "trigger.h" -#include "types.h" +#include "core/ras-logger.h" +#include "core/ras-mc-handler.h" +#include "modules/ras-page-isolation.h" +#include "modules/ras-report.h" +#include "core/trigger.h" +#include "core/types.h" #define MAX_ENV 30 static const char *mc_ce_trigger = NULL; @@ -300,7 +299,7 @@ int ras_mc_event_handler(struct trace_seq *s, /* Insert data into the SGBD */ - ras_store_mc_event(ras, &ev); + db_mc_event(ras, &ev); ras_mc_event_stat(now, &ev); diff --git a/ras-mc-handler.h b/core/ras-mc-handler.h similarity index 93% rename from ras-mc-handler.h rename to core/ras-mc-handler.h index cf12959e..b43f0771 100644 --- a/ras-mc-handler.h +++ b/core/ras-mc-handler.h @@ -9,7 +9,7 @@ #include -#include "ras-events.h" +#include "core/ras-events.h" extern unsigned long long mc_ce_stat_threshold; void mc_event_trigger_setup(void); diff --git a/rasdaemon.c b/core/rasdaemon.c similarity index 72% rename from rasdaemon.c rename to core/rasdaemon.c index 9368b123..60f3a413 100644 --- a/rasdaemon.c +++ b/core/rasdaemon.c @@ -10,26 +10,34 @@ #include #include -#include "ras-erst.h" -#include "ras-events.h" -#include "ras-logger.h" -#include "ras-poison-page-stat.h" -#include "ras-record.h" -#include "ras-mc-handler.h" -#include "types.h" +#include "core/types.h" +#include "core/ras-env.h" +#include "core/ras-events.h" +#include "core/ras-logger.h" +#include "core/ras-mc-handler.h" +#include "core/modules.h" + +#include "db/ras-db.h" +#include "db/ras-record.h" + +#include "events/ras-poison-page-stat.h" + +#include "events-arch-x86/ras-erst.h" /* * Arguments(argp) handling logic and main */ -#define TOOL_NAME "rasdaemon" +#define PROG_NAME "rasdaemon" #define TOOL_DESCRIPTION "RAS daemon to log the RAS events." #define ARGS_DOC "" #define DISABLE "DISABLE" #define MC_CE_STAT_THRESHOLD "MC_CE_STAT_THRESHOLD" #define POISON_STAT_THRESHOLD "POISON_STAT_THRESHOLD" -const char *argp_program_version = TOOL_NAME " " VERSION; +static const char *const rasdaemon_conf = RASDAEMON_ENV; + +const char *argp_program_version = PROG_NAME " " VERSION; const char *argp_program_bug_address = "Mauro Carvalho Chehab "; struct arguments { @@ -38,6 +46,7 @@ struct arguments { int enable_ipmitool; int foreground; int offline; + char *cfg_file; }; enum OFFLINE_ARG_KEYS { @@ -63,7 +72,12 @@ static error_t parse_opt(int k, char *arg, struct argp_state *state) case 'd': args->enable_ras--; break; -#ifdef HAVE_SQLITE3 + + case 'c': + args->cfg_file = arg; + return 0; + +#ifdef HAVE_DB case 'r': args->record_events++; break; @@ -122,26 +136,13 @@ static error_t parse_opt_offline(int key, char *arg, } #endif -long user_hz; - int main(int argc, char *argv[]) { + struct ras_events *ras; struct arguments args; int idx = -1; - choices_disable = getenv(DISABLE); - - if (getenv(MC_CE_STAT_THRESHOLD)) - mc_ce_stat_threshold = strtoull(getenv(MC_CE_STAT_THRESHOLD), NULL, 0); - if (mc_ce_stat_threshold) - log(TERM, LOG_INFO, "Threshold of memory Corrected Errors statistics is %lld\n", mc_ce_stat_threshold); - -#ifdef HAVE_POISON_PAGE_STAT - if (getenv(POISON_STAT_THRESHOLD)) - poison_stat_threshold = strtoull(getenv(POISON_STAT_THRESHOLD), NULL, 0); - if (poison_stat_threshold) - log(TERM, LOG_INFO, "Threshold of poison page statistics is %lld kB\n", poison_stat_threshold); -#endif + /* Handle arguments before anything else */ #ifdef HAVE_MCE const struct argp_option offline_options[] = { @@ -163,24 +164,26 @@ int main(int argc, char *argv[]) }; struct argp_child offline_parser[] = { - {&offline_argp, 0, "Post-Processing Options:", 0}, + {&offline_argp, 0, "MCE Post-Processing Options:", 1}, {0, 0, 0, 0}, }; #endif const struct argp_option options[] = { - {"enable", 'e', 0, 0, "enable RAS events and exit", 0}, - {"disable", 'd', 0, 0, "disable RAS events and exit", 0}, -#ifdef HAVE_SQLITE3 - {"record", 'r', 0, 0, "record events via sqlite3", 0}, + {"enable", 'e', 0, 0, "enable RAS events and exit", 0}, + {"disable", 'd', 0, 0, "disable RAS events and exit", 0}, + {"config", 'c', "FNAME", 0, "config file with env vars", 0}, + {"foreground", 'f', 0, 0, "run foreground, not daemonize", 0}, + +#ifdef HAVE_DB + {"record", 'r', 0, 0, "record events at the SQL backend", 0}, #endif - {"foreground", 'f', 0, 0, "run foreground, not daemonize"}, #ifdef HAVE_OPENBMC_UNIFIED_SEL - {"ipmitool", 'i', 0, 0, "enable ipmitool logging", 0}, + {"ipmitool", 'i', 0, 0, "enable ipmitool logging", 0}, #endif #ifdef HAVE_MCE {"post-processing", 'p', 0, 0, - "Post-processing MCE's with raw register values"}, + "Post-processing MCE's with raw register values", 2}, #endif { 0, 0, 0, 0, 0, 0 } @@ -194,17 +197,37 @@ int main(int argc, char *argv[]) .children = offline_parser, #endif }; - memset(&args, 0, sizeof(args)); - - user_hz = sysconf(_SC_CLK_TCK); + memset(&args, 0, sizeof(args)); argp_parse(&argp, argc, argv, 0, &idx, &args); - if (idx < 0) { - argp_help(&argp, stderr, ARGP_HELP_STD_HELP, TOOL_NAME); + argp_help(&argp, stderr, ARGP_HELP_STD_HELP, PROG_NAME); return -1; } + /* Now that arguments were parsed and it is not help, proceed */ + + user_hz = sysconf(_SC_CLK_TCK); + + if (args.cfg_file) + ras_set_env(args.cfg_file); + else + ras_set_env(rasdaemon_conf); + + choices_disable = getenv(DISABLE); + + if (getenv(MC_CE_STAT_THRESHOLD)) + mc_ce_stat_threshold = strtoull(getenv(MC_CE_STAT_THRESHOLD), NULL, 0); + if (mc_ce_stat_threshold) + log(TERM, LOG_INFO, "Threshold of memory Corrected Errors statistics is %lld\n", mc_ce_stat_threshold); + +#ifdef HAVE_POISON_PAGE_STAT + if (getenv(POISON_STAT_THRESHOLD)) + poison_stat_threshold = strtoull(getenv(POISON_STAT_THRESHOLD), NULL, 0); + if (poison_stat_threshold) + log(TERM, LOG_INFO, "Threshold of poison page statistics is %lld kB\n", poison_stat_threshold); +#endif + if (args.enable_ras) { int enable; @@ -221,7 +244,7 @@ int main(int argc, char *argv[]) } #endif - openlog(TOOL_NAME, 0, LOG_DAEMON); + openlog(PROG_NAME, 0, LOG_DAEMON); if (!args.foreground) if (daemon(0, 0)) exit(EXIT_FAILURE); @@ -236,7 +259,17 @@ int main(int argc, char *argv[]) #endif #endif - handle_ras_events(args.record_events, args.enable_ipmitool); + ras = calloc(1, sizeof(*ras)); + if (!ras) { + log(TERM, LOG_ERR, "Can't allocate memory for ras struct\n"); + return -errno; + } + + modules_init(ras); + + db_backend_enable(NULL); + + handle_ras_events(ras, args.record_events, args.enable_ipmitool); return 0; } diff --git a/rbtree.c b/core/rbtree.c similarity index 99% rename from rbtree.c rename to core/rbtree.c index e2caf35a..c35c04ec 100644 --- a/rbtree.c +++ b/core/rbtree.c @@ -7,7 +7,7 @@ * Taken from the Linux 2.6.30 source with some minor modifications. */ -#include "rbtree.h" +#include "core/rbtree.h" static void __rb_rotate_left(struct rb_node *node, struct rb_root *root) { diff --git a/rbtree.h b/core/rbtree.h similarity index 100% rename from rbtree.h rename to core/rbtree.h diff --git a/trigger.c b/core/trigger.c similarity index 94% rename from trigger.c rename to core/trigger.c index aa19a22f..bcc47e18 100644 --- a/trigger.c +++ b/core/trigger.c @@ -1,13 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 -#define _GNU_SOURCE #include #include #include #include -#include "ras-logger.h" -#include "trigger.h" +#include "core/ras-logger.h" +#include "core/trigger.h" void run_trigger(const char *trigger, char *argv[], char **env, const char *reporter) { diff --git a/trigger.h b/core/trigger.h similarity index 100% rename from trigger.h rename to core/trigger.h diff --git a/types.c b/core/types.c similarity index 93% rename from types.c rename to core/types.c index 64a77a02..dd043744 100644 --- a/types.c +++ b/core/types.c @@ -4,7 +4,7 @@ * Copyright (C) 2025 Alibaba Inc */ -#include "types.h" +#include "core/types.h" const char *loglevel_str[] = { [LOGLEVEL_EMERG] = "[EMERG]", diff --git a/types.h b/core/types.h similarity index 100% rename from types.h rename to core/types.h diff --git a/db/db-mysql.c b/db/db-mysql.c new file mode 100644 index 00000000..cca6732e --- /dev/null +++ b/db/db-mysql.c @@ -0,0 +1,643 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + * + * MySQL / MariaDB backend for rasdaemon. + * + * BuildRequires: mysql-devel (or mariadb-devel) + * Links: -lmysqlclient (or -lmariadb) + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "config.h" + +#include "core/modules.h" +#include "core/ras-logger.h" + +#include "db/ras-db.h" +#include "db/ras-db-backend.h" +#include "db/db-mysql.h" + +//#define DEBUG_SQL + +void *db_mysql_get_conn_parms(void) +{ + static struct db_mysql_conn_params cp; + + cp.connect_timeout = env_or_int("RAS_MYSQL_CONNECT_TIMEOUT", 10); + cp.port = env_or_int("RAS_MYSQL_PORT", 3306); + + cp.host = env_or("RAS_MYSQL_HOST", NULL); + cp.user = env_or("RAS_MYSQL_USER", "rasdaemon"); + cp.password = env_or("RAS_MYSQL_PASSWORD", ""); + cp.database = env_or("RAS_MYSQL_DATABASE", "rasdaemon"); + cp.socket = env_or("RAS_MYSQL_SOCKET", NULL); + + cp.use_ssl = env_or_bool("RAS_MYSQL_USE_SSL", false); + + return &cp; +} + +static MYSQL *to_db(struct ras_db *__db) +{ + return (MYSQL *)__db; +} + + +struct mysql_stmt_priv { + MYSQL_STMT *stmt; + unsigned int n_params; + MYSQL_BIND *binds; + bool has_hostname; +}; + +// TODO: assert that allocs won't return errors + +static int db_mysql_open(struct ras_db **__db, void *__conn_parms, + unsigned int cpu) +{ + struct db_mysql_conn_params *cp = __conn_parms; + const char *host, *user, *pass, *database, *sock; + MYSQL *raw = mysql_init(NULL); + unsigned int port; + MYSQL *db = NULL; + + if (!raw) { + log(TERM, LOG_ERR, "mysql_init failed\n"); + return -ENOMEM; + } + + if (cp->use_ssl) { +#ifdef MARIADB_BASE_VERSION + my_bool enforce_tls = 1; + + mysql_options(raw, MYSQL_OPT_SSL_ENFORCE, &enforce_tls); +#else + unsigned int ssl_mode = SSL_MODE_REQUIRED; + + mysql_options(raw, MYSQL_OPT_SSL_MODE, &ssl_mode); +#endif + } + + if (cp->connect_timeout) + mysql_options(raw, MYSQL_OPT_CONNECT_TIMEOUT, + (void *)&cp->connect_timeout); + + host = (cp && cp->host) ? cp->host : NULL; + user = (cp && cp->user) ? cp->user : "root"; + pass = (cp && cp->password) ? cp->password : ""; + database = (cp && cp->database) ? cp->database : NULL; + port = (cp && cp->port) ? cp->port : 3306; + sock = (cp && cp->socket) ? cp->socket : NULL; + + db = mysql_real_connect(raw, host, user, pass, database, port, sock, 0); + + if (!db) { + log(TERM, LOG_ERR, + "cpu %u: Failed to connect to MySQL: %s\n", + cpu, mysql_error(raw)); + mysql_close(raw); + return -1; + } + + log(TERM, LOG_INFO, "cpu %u: Connected to MySQL (%s)\n", + cpu, db->host ? db->host : "local socket"); + + *__db = (void *)db; + return 0; +} + +static int db_mysql_close(struct ras_db *__db, unsigned int cpu) +{ + MYSQL *db = to_db(__db); + + if (db) + mysql_close(db); + + return 0; +} + +static const char *db_mysql_get_sql_type(enum db_field_type type, bool is_pk) +{ + switch (type) { + case DB_TYPE_SERIAL: + if (is_pk) + return "BIGINT AUTO_INCREMENT"; + return "BIGINT"; + case DB_TYPE_INT32: + if (is_pk) + return "INT PRIMARY KEY"; + return "INT"; + case DB_TYPE_INT64: + if (is_pk) + return "BIGINT PRIMARY KEY"; + return "BIGINT"; + case DB_TYPE_TIMESTAMP: + /* MySQL DATETIME(6) stores ISO-like timestamps */ + if (is_pk) + return "DATETIME(6) PRIMARY KEY"; + return "DATETIME(6)"; + case DB_TYPE_TEXT: + if (is_pk) + return "TEXT PRIMARY KEY"; + return "TEXT"; + case DB_TYPE_BLOB: + if (is_pk) + return "BLOB PRIMARY KEY"; + return "BLOB"; + default: + if (is_pk) + return "TEXT PRIMARY KEY"; + return "TEXT"; + } +} + +static int bind_iso_datetime(MYSQL_BIND *mb, const char *value) +{ + MYSQL_TIME *time; + struct tm tm = {0}; + char *end; + + end = strptime(value, "%Y-%m-%d %H:%M:%S %z", &tm); + if (!end) + return -1; + + time = calloc(1, sizeof(*time)); + if (!time) + return -1; + + time->year = tm.tm_year + 1900; + time->month = tm.tm_mon + 1; + time->day = tm.tm_mday; + time->hour = tm.tm_hour; + time->minute = tm.tm_min; + time->second = tm.tm_sec; + + time->second_part = 0; + time->neg = false; + time->time_type = MYSQL_TIMESTAMP_DATETIME; + + mb->buffer_type = MYSQL_TYPE_DATETIME; + mb->buffer = time; + mb->buffer_length = sizeof(*time); + + return 0; +} + +static int db_mysql_bind_type(struct ras_stmt *__stmt, + const enum db_field_type type, + const int pos, uint64_t value, int len) +{ + struct mysql_stmt_priv *priv = (struct mysql_stmt_priv *)__stmt; + unsigned int idx = (unsigned int)pos - 1; + MYSQL_BIND *mb; + + if (idx >= priv->n_params) { + log(TERM, LOG_ERR, + "mysql_bind_type: pos %d out of range (n=%u)\n", + pos, priv->n_params); + return -1; + } + mb = &priv->binds[idx]; + + memset(mb, 0, sizeof(*mb)); + + switch (type) { + case DB_TYPE_SERIAL: + /* In practice, should never happen */ + mb->buffer_type = MYSQL_TYPE_NULL; + mb->is_null = malloc(sizeof(bool)); + if (!mb->is_null) { + log(TERM, LOG_ERR, + "Failed to allocate memory for NULL\n"); + return -1; + } + *(bool *)mb->is_null = true; + return 0; + + case DB_TYPE_INT32: + mb->buffer_type = MYSQL_TYPE_LONG; + mb->buffer_length = sizeof(int32_t); + mb->buffer = malloc(mb->buffer_length); + if (!mb->buffer) { + log(TERM, LOG_ERR, + "Failed to allocate memory for INT\n"); + return -1; + } + mb->length = &mb->buffer_length; + *((int32_t *)mb->buffer) = value; + + return 0; + + case DB_TYPE_INT64: + mb->buffer_type = MYSQL_TYPE_LONGLONG; + mb->buffer_length = sizeof(int64_t); + mb->buffer = malloc(mb->buffer_length); + if (!mb->buffer) { + log(TERM, LOG_ERR, + "Failed to allocate memory for BIG INT\n"); + return -1; + } + mb->length = &mb->buffer_length; + *(int64_t *)mb->buffer = (int64_t)value; + return 0; + + case DB_TYPE_TIMESTAMP: + return bind_iso_datetime(mb, (const char *)(uintptr_t)value); + + case DB_TYPE_TEXT: + mb->buffer_type = MYSQL_TYPE_VAR_STRING; + break; + + default: + case DB_TYPE_BLOB: + mb->buffer_type = MYSQL_TYPE_BLOB; + break; + } + + if (!value) { + mb->is_null = malloc(sizeof(bool)); + if (!mb->is_null) { + log(TERM, LOG_ERR, + "Failed to allocate memory for NULL\n"); + return -1; + } + *(bool *)mb->is_null = true; + } else { + const char *str = (const char *)value; + + if (len < 0) + len = strlen(str); + + mb->buffer_length = len; + mb->length = &mb->buffer_length; + + if (type == DB_TYPE_BLOB) { + mb->buffer = malloc(len); + if (!mb->buffer) { + log(TERM, LOG_ERR, + "Failed to allocate memory for BLOB\n"); + return -1; + } + + memcpy(mb->buffer, str, len); + } else { + mb->buffer = malloc(len + 1); + if (!mb->buffer) { + log(TERM, LOG_ERR, + "Failed to allocate memory for TEXT\n"); + return -1; + } + + strncpy(mb->buffer, str, len); + *(char *)(mb->buffer + len) = '\0'; + } + } + return 0; +} + +static int db_mysql_exec_sql(struct ras_db *__db, const char *sql) +{ + MYSQL *db = to_db(__db); + int rc; + +#ifdef DEBUG_SQL + log(TERM, LOG_INFO, "SQL: %s\n", sql); + ras_logger_flush(); +#endif + + rc = mysql_query(db, sql); + if (rc) { + log(TERM, LOG_ERR, + "Failed to exec '%s': %s\n", sql, mysql_error(db)); + return -1; + } + + return 0; +} + +static int db_mysql_create_table(struct ras_db *__db, + const struct db_table_descriptor *db_tab) +{ + char sql[2048], *p = sql, *end = sql + sizeof(sql) - 1; + const struct db_fields *field; + const char *type; + int i; + + p += snprintf(p, end - p, "CREATE TABLE IF NOT EXISTS %s (", + db_tab->name); + + for (i = 0; i < (int)db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + type = db_mysql_get_sql_type(field->type, field->is_pk); + + p += snprintf(p, end - p, "`%s` %s", field->name, type); + + /* Add hostname */ + if (!i) + p += snprintf(p, end - p, ", `hostname` VARCHAR(255)"); + + if (i < (int)db_tab->num_fields - 1) + p += snprintf(p, end - p, ", "); + } + + /* MySQL requires an explicit PRIMARY KEY clause if SERIAL was used */ + for (i = 0; i < (int)db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + if (field->is_pk && + field->type == DB_TYPE_SERIAL) { + p += snprintf(p, end - p, ", PRIMARY KEY (%s)", + field->name); + break; + } + } + + p += snprintf(p, end - p, ") ENGINE=InnoDB"); + *end = '\0'; + + return db_mysql_exec_sql(__db, sql); +} + +static int db_mysql_alter_table(struct ras_db *__db, + struct ras_stmt **__stmt, + const struct db_table_descriptor *db_tab) +{ + MYSQL *db = to_db(__db); + MYSQL_RES *res = NULL; + MYSQL_ROW row; + unsigned long *lengths = NULL; + char sql[1024]; + const struct db_fields *field; + int i, found, rc = 0; + + snprintf(sql, sizeof(sql), + "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS " + "WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = '%s'", + db_tab->name); + + res = mysql_query(db, sql) == 0 ? mysql_store_result(db) : NULL; + if (!res) { + log(TERM, LOG_ERR, "Failed to query columns of %s: %s\n", + db_tab->name, mysql_error(db)); + return -1; + } + + for (i = 0; i < (int)db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + found = 0; + + /* scan the result set */ + mysql_data_seek(res, 0); + while ((row = mysql_fetch_row(res))) { + if (!strcmp(field->name, row[0])) { + found = 1; + break; + } + } + + if (!found) { + const char *type = db_mysql_get_sql_type( + field->type, field->is_pk); + + snprintf(sql, sizeof(sql), + "ALTER TABLE %s ADD COLUMN `%s` %s", + db_tab->name, field->name, type); + + if (mysql_query(db, sql)) { + log(TERM, LOG_ERR, + "ALTER TABLE %s ADD `%s`: %s\n", + db_tab->name, field->name, + mysql_error(db)); + rc = -1; + } + } + } + + if (lengths) + free(lengths); + mysql_free_result(res); + + return rc; +} + +static int db_mysql_prepare_insert_stmt(struct ras_db *__db, + struct ras_stmt **__stmt, + const struct db_table_descriptor *db_tab) +{ + char sql[2048], *p = sql, *end; + struct mysql_stmt_priv *priv; + const struct db_fields *field; + unsigned int n_params = 0; + MYSQL *db = to_db(__db); + MYSQL_STMT *ms; + unsigned int i; + + end = sql + sizeof(sql) - 1; + + p += snprintf(p, end - p, "INSERT INTO %s (", db_tab->name); + + for (i = 0; i < db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + p += snprintf(p, end - p, "`%s`", field->name); + + if (i < db_tab->num_fields - 1) + p += snprintf(p, end - p, ", "); + } + p += snprintf(p, end - p, ", `hostname`"); + p += snprintf(p, end - p, ") VALUES ("); + + for (i = 0; i < db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + if (field->type == DB_TYPE_SERIAL) { + p += snprintf(p, end - p, "DEFAULT"); + } else { + n_params++; + p += snprintf(p, end - p, "?"); + } + + if (i < db_tab->num_fields - 1) + p += snprintf(p, end - p, ", "); + } + p += snprintf(p, end - p, ", ?)"); + n_params++; + *end = '\0'; + +#ifdef DEBUG_SQL + log(TERM, LOG_INFO, "SQL: %s\n", sql); + ras_logger_flush(); +#endif + + ms = mysql_stmt_init(db); + + if (!ms) { + log(TERM, LOG_ERR, + "mysql_stmt_init failed: %s\n", mysql_error(db)); + return -1; + } + + if (mysql_stmt_prepare(ms, sql, (unsigned int)strlen(sql))) { + log(TERM, LOG_ERR, + "mysql_stmt_prepare(%s) failed: %s\n", + sql, mysql_stmt_error(ms)); + mysql_stmt_close(ms); + return -1; + } + + priv = calloc(1, sizeof(*priv)); + if (!priv) { + log(TERM, LOG_ERR, "No memory for MySQL stmt priv\n"); + mysql_stmt_close(ms); + return -ENOMEM; + } + + priv->stmt = ms; + priv->n_params = n_params; + priv->binds = calloc(n_params, sizeof(MYSQL_BIND)); + if (!priv->binds) { + log(TERM, LOG_ERR, "No memory for MySQL statement binds\n"); + mysql_stmt_close(ms); + free(priv); + return -ENOMEM; + } + priv->has_hostname = true; + + *__stmt = (void *)priv; + + log(TERM, LOG_INFO, "Recording %s events (mysql)\n", db_tab->name); + return 0; +} + +static void db_mysql_free_stmt(struct mysql_stmt_priv *priv) +{ + for (int i = 0; i < priv->n_params; i++) { + if (priv->binds[i].buffer) { + free(priv->binds[i].buffer); + priv->binds[i].buffer = NULL; + } + if (priv->binds[i].is_null) { + free(priv->binds[i].is_null); + priv->binds[i].is_null = NULL; + } + } +} + +static int db_mysql_eval_stmt(struct ras_stmt *__stmt, const char *tab_name) +{ + struct mysql_stmt_priv *priv = (struct mysql_stmt_priv *)__stmt; + MYSQL_STMT *ms = priv->stmt; + int rc1, rc2; + + if (priv->has_hostname && + db_mysql_bind_type(__stmt, DB_TYPE_TEXT, priv->n_params, + (uint64_t)rasdaemon_hostname, -1)) { + db_mysql_free_stmt(priv); + return -1; + } + + rc1 = mysql_stmt_bind_param(ms, priv->binds); + + if (!rc1) + rc2 = mysql_stmt_execute(ms); + + db_mysql_free_stmt(priv); + + if (rc1) { + log(TERM, LOG_ERR, "mysql_stmt_bind_param (%s): %s\n", + tab_name, mysql_stmt_error(ms)); + ras_logger_flush(); + return -1; + } + + if (rc2) { + log(TERM, LOG_ERR, "mysql_stmt_execute (%s): %s\n", + tab_name, mysql_stmt_error(ms)); + ras_logger_flush(); + return -1; + } + + /* reset for next use */ + mysql_stmt_reset(ms); + + return 0; +} + +static int db_mysql_finalize(unsigned int cpu, + struct ras_stmt *__stmt, const char *name) +{ + struct mysql_stmt_priv *priv = (struct mysql_stmt_priv *)__stmt; + + if (!priv) + return 0; + + db_mysql_free_stmt(priv); + + mysql_stmt_close(priv->stmt); + free(priv->binds); + free(priv); + + return 0; +} + +/* + * Backend registration + */ + +static const struct ras_db_backend_ops mysql_backend_ops = { + .open = db_mysql_open, + .close = db_mysql_close, + .get_conn_parms = db_mysql_get_conn_parms, + + .get_sql_type = db_mysql_get_sql_type, + .bind_type = db_mysql_bind_type, + + .db_exec_sql = db_mysql_exec_sql, + + .eval_stmt = db_mysql_eval_stmt, + .create_table = db_mysql_create_table, + .alter_table = db_mysql_alter_table, + .prepare_stmt = db_mysql_prepare_insert_stmt, + .finalize = db_mysql_finalize, +}; + +static struct ras_db_backend_entry mysql_backend_entry = { + .name = "mysql", + .ops = &mysql_backend_ops, + .allow_remote = true, +}; + +static int mysql_module_init(const char *name, struct ras_events *ras, + void **priv) +{ + int ret; + + ret = db_backend_register(&mysql_backend_entry); + if (ret != 0) + log(TERM, LOG_ERR, "Failed to init MySQL backend: %d\n", ret); + + return ret; +} + +const struct ras_module_entry db_mysql_module = { + .name = "db-mysql", + .init = mysql_module_init, + .level = DB_MODULE, + .postpone_init = true, +}; + +__attribute__((constructor)) void mysql_register(void) +{ + int ret; + + ret = module_register(&db_mysql_module); + if (ret != 0) + log(TERM, LOG_ERR, "Failed to register MySQL module: %d\n", + ret); +} diff --git a/db/db-mysql.h b/db/db-mysql.h new file mode 100644 index 00000000..68709cec --- /dev/null +++ b/db/db-mysql.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +#ifndef DB_MYSQL_H +#define DB_MYSQL_H + +#include + +/** + * struct db_mysql_conn_params - MySQL/MariaDB connection parameters + * @host: Hostname or IP. NULL or "localhost" for local Unix socket. + * @port: TCP port (default 3306). Ignored for local socket. + * @user: Username (default "rasdaemon"). + * @password: Password (default NULL / empty). + * @database: Database name (default "rasdaemon"). + * @socket: Unix socket path for local connections + * (default "/var/lib/mysql/mysql.sock"). + */ +struct db_mysql_conn_params { + const char *host; + unsigned int port; + const char *user; + const char *password; + const char *database; + const char *socket; + + unsigned int connect_timeout; + + bool use_ssl; +}; + +void mysql_register_backend(void); + +#endif /* DB_MYSQL_H */ diff --git a/db/db-postgresql-priv.h b/db/db-postgresql-priv.h new file mode 100644 index 00000000..32f65644 --- /dev/null +++ b/db/db-postgresql-priv.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +#ifndef DB_POSTGRESQL_PRIV_H +#define DB_POSTGRESQL_PRIV_H + +#include + +/* + * This should never be used anywhere, except at postgresql unit test + * + * The goal of this struct is to allow embedding the schema inside the + * DB to allow create/alter table to use the right schema. + */ + +struct pg_conn_priv { + PGconn *conn; + const char *schema; +}; + +#endif /* DB_POSTGRESQL_PRIV_H */ diff --git a/db/db-postgresql.c b/db/db-postgresql.c new file mode 100644 index 00000000..0a2f5516 --- /dev/null +++ b/db/db-postgresql.c @@ -0,0 +1,741 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + * + * PostgreSQL backend for rasdaemon. + * + * BuildRequires: postgresql-devel (libpq) + * Links: -lpq + */ + +#include +#include +#include +#include +#include +#include + +#include + +#include "config.h" + +#include "core/modules.h" +#include "core/ras-logger.h" + +#include "db/ras-db.h" +#include "db/ras-db-backend.h" +#include "db/db-postgresql.h" +#include "db/db-postgresql-priv.h" + +//#define DEBUG_SQL + +struct pg_stmt_priv { + PGconn *conn; + char *stmt_name; + unsigned int n_params; + + char **values; + int *lengths; + bool *is_blob; + bool has_hostname; +}; + +static bool valid_identifier(const char *name) +{ + const unsigned char *p = (const unsigned char *)name; + + if (!p || strlen(name) > 63 || (!isalpha(*p) && *p != '_')) + return false; + + for (p++; *p; p++) + if (!isalnum(*p) && *p != '_') + return false; + + return true; +} + +static void *db_pg_get_conn_parms(void) +{ + static struct db_postgresql_conn_params cp; + + cp.connect_timeout = env_or_int("RAS_PG_CONNECT_TIMEOUT", 10); + cp.port = env_or_int("RAS_PG_PORT", 5432); + + cp.host = env_or("RAS_PG_HOST", NULL); + cp.user = env_or("RAS_PG_USER", "rasdaemon"); + cp.password = env_or("RAS_PG_PASSWORD", ""); + cp.schema = env_or("RAS_PG_SCHEMA", "rasdaemon"); + cp.database = env_or("RAS_PG_DATABASE", "rasdaemon"); + cp.sslmode = env_or("RAS_PG_SSL_MODE", NULL); + + cp.use_ssl = env_or_bool("RAS_PG_USE_SSL", false); + + return &cp; +} + +static int db_pg_open(struct ras_db **__db, void *__conn_parms, + unsigned int cpu) +{ + struct db_postgresql_conn_params *cp = __conn_parms; + struct pg_conn_priv *conn_priv; + const char *keywords[9] = { 0 }; + const char *values[9] = { 0 }; + char port[16], timeout[16]; + unsigned int idx = 0; + const char *schema; + PGconn *conn; + + conn_priv = calloc(1, sizeof(struct pg_conn_priv)); + if (!conn_priv) { + log(TERM, LOG_ERR, + "Failed to allocate memory for PostgreSQL connection\n"); + return -1; + } + + if (cp) { + if (cp->host && *cp->host) { + keywords[idx] = "host"; + values[idx++] = cp->host; + if (cp->port) { + snprintf(port, sizeof(port), "%hu", cp->port); + keywords[idx] = "port"; + values[idx++] = port; + } + } + + if (!cp->user || !*cp->user) + cp->user = "rasdaemon"; + + keywords[idx] = "user"; + values[idx++] = cp->user; + + if (cp->password && *cp->password) { + keywords[idx] = "password"; + values[idx++] = cp->password; + } + + if (cp->schema && *cp->schema) + schema = cp->schema; + else + schema = "rasdaemon"; + + if (cp->database && *cp->database) { + keywords[idx] = "dbname"; + values[idx++] = cp->database; + } + + if (cp->use_ssl) { + keywords[idx] = "sslmode"; + values[idx++] = cp->sslmode && *cp->sslmode ? + cp->sslmode : "require"; + } + + if (cp->connect_timeout) { + snprintf(timeout, sizeof(timeout), "%u", cp->connect_timeout); + keywords[idx] = "connect_timeout"; + values[idx++] = timeout; + } + } else { + schema = "rasdaemon"; + } + + if (!valid_identifier(schema)) { + log(TERM, LOG_ERR, "Invalid PostgreSQL schema name: %s\n", schema); + free(conn_priv); + return -1; + } + + conn = PQconnectdbParams(keywords, values, 0); + if (!conn) { + log(TERM, LOG_ERR, "Failed to allocate PostgreSQL connection\n"); + free(conn_priv); + return -ENOMEM; + } + + if (PQstatus(conn) != CONNECTION_OK) { + log(TERM, LOG_ERR, + "cpu %u: PostgreSQL connection failed: %s\n", + cpu, PQerrorMessage(conn)); + PQfinish(conn); + free(conn_priv); + return -1; + } + + conn_priv->conn = conn; + conn_priv->schema = schema; + + log(TERM, LOG_INFO, + "cpu %u: Connected to PostgreSQL at %s, schema: %s\n", + cpu, PQhost(conn), schema); + + *__db = (void *)conn_priv; + return 0; +} + +static int db_pg_close(struct ras_db *__db, unsigned int cpu) +{ + struct pg_conn_priv *conn_priv = (void *)__db; + PGconn *conn = conn_priv->conn; + int rc = 0; + + if (conn) { + ConnStatusType st = PQstatus(conn); + + if (st == CONNECTION_OK || st == CONNECTION_BAD) + PQfinish(conn); + + if (st != CONNECTION_OK && st != CONNECTION_BAD) { + log(TERM, LOG_ERR, + "cpu %u: Unexpected PGconn state %d\n", + cpu, (int)st); + rc = -1; + } + } + free(conn_priv); + + return rc; +} + +static const char *db_pg_get_sql_type(enum db_field_type type, bool is_pk) +{ + switch (type) { + case DB_TYPE_SERIAL: + /* PostgreSQL uses SERIAL / BIGSERIAL for identity */ + if (is_pk) + return "BIGSERIAL"; + return "BIGINT"; + case DB_TYPE_INT32: + if (is_pk) + return "INTEGER PRIMARY KEY"; + return "INTEGER"; + case DB_TYPE_INT64: + if (is_pk) + return "BIGINT PRIMARY KEY"; + return "BIGINT"; + case DB_TYPE_TIMESTAMP: + if (is_pk) + return "TIMESTAMPTZ PRIMARY KEY"; + return "TIMESTAMPTZ"; + case DB_TYPE_TEXT: + if (is_pk) + return "TEXT PRIMARY KEY"; + return "TEXT"; + case DB_TYPE_BLOB: + default: + if (is_pk) + return "BYTEA PRIMARY KEY"; + return "BYTEA"; + } +} + +static int db_pg_bind_type(struct ras_stmt *__stmt, + const enum db_field_type type, + const int pos, uint64_t value, int len) +{ + struct pg_stmt_priv *priv = (struct pg_stmt_priv *)__stmt; + unsigned int idx = (unsigned int)pos - 1; + PGconn *conn = priv->conn; + size_t encoded_len; + const char *str; + char *buf; + + if (idx >= priv->n_params) { + log(TERM, LOG_ERR, + "pg_bind_type: pos %d out of range (n=%u)\n", + pos, priv->n_params); + return -1; + } + + /* Just in case, to avoid memory leaks */ + if (priv->values[idx]) { + if (priv->is_blob[idx]) + PQfreemem(priv->values[idx]); + else + free(priv->values[idx]); + priv->values[idx] = NULL; + } + priv->is_blob[idx] = false; + + switch (type) { + case DB_TYPE_SERIAL: + priv->values[idx] = NULL; + priv->lengths[idx] = 0; + return 0; + + case DB_TYPE_INT32: + asprintf(&buf, "%d", (int32_t)value); + if (!buf) { + log(TERM, LOG_ERR,"Failed to allocate memory for INT32\n"); + return -1; + } + + priv->values[idx] = buf; + priv->lengths[idx] = strlen(buf); + return 0; + + case DB_TYPE_INT64: + asprintf(&buf, "%lld", (long long)value); + if (!buf) { + log(TERM, LOG_ERR,"Failed to allocate memory for INT64\n"); + return -1; + } + priv->values[idx] = buf; + priv->lengths[idx] = strlen(buf); + return 0; + + case DB_TYPE_TIMESTAMP: + case DB_TYPE_TEXT: + case DB_TYPE_BLOB: + default: + break; + } + + if (!value) { + priv->values[idx] = NULL; + priv->lengths[idx] = 0; + return 0; + } + + str = (const char *)value; + if (len < 0) + len = strlen(str); + + priv->lengths[idx] = len; + + if (type == DB_TYPE_BLOB) { + buf = (char *)PQescapeByteaConn(conn, (unsigned char *)str, + len, &encoded_len); + if (!buf) { + log(TERM, LOG_ERR,"Failed to allocate memory for BLOB\n"); + return -1; + } + + priv->is_blob[idx] = true; + priv->values[idx] = buf; + priv->lengths[idx] = encoded_len; + return 0; + } + + buf = malloc(len + 1); + if (!buf) { + log(TERM, LOG_ERR, + "Failed to allocate memory for TEXT\n"); + return -1; + } + + memcpy(buf, str, len); + buf[len] = '\0'; + + priv->values[idx] = buf; + priv->lengths[idx] = len; + return 0; +} + +static int db_pg_exec_sql(struct ras_db *__db, const char *sql) +{ + struct pg_conn_priv *conn_priv = (void *)__db; + PGconn *conn = conn_priv->conn; + PGresult *res; + int rc = 0; + +#ifdef DEBUG_SQL + log(TERM, LOG_INFO, "SQL: %s\n", sql); + ras_logger_flush(); +#endif + + res = PQexec(conn, sql); + if (!res) { + log(TERM, LOG_ERR, "Failed to allocate PostgreSQL result\n"); + return -ENOMEM; + } + if (PQresultStatus(res) != PGRES_COMMAND_OK) { + log(TERM, LOG_ERR, "Failed to exec '%s': %s\n", + sql, PQresultErrorMessage(res)); + rc = -1; + } + PQclear(res); + + return rc; +} + + +static int db_pg_create_table(struct ras_db *__db, + const struct db_table_descriptor *db_tab) +{ + struct pg_conn_priv *conn_priv = (void *)__db; + char sql[2048], *p = sql, *end = sql + sizeof(sql) - 1; + const struct db_fields *field; + const char *type; + int i; + + p += snprintf(p, end - p, "CREATE TABLE IF NOT EXISTS %s.%s (", + conn_priv->schema, db_tab->name); + + for (i = 0; i < (int)db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + type = db_pg_get_sql_type(field->type, field->is_pk); + + p += snprintf(p, end - p, "\"%s\" %s", field->name, type); + + /* Add hostname */ + if (!i) + p += snprintf(p, end - p, ", \"hostname\" TEXT"); + + if (i < (int)db_tab->num_fields - 1) + p += snprintf(p, end - p, ", "); + } + + /* + * For SERIAL / BIGSERIAL we need an explicit PRIMARY KEY clause + * (SERIAL already implies NOT NULL + a sequence). + */ + for (i = 0; i < (int)db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + if (field->is_pk && field->type == DB_TYPE_SERIAL) { + p += snprintf(p, end - p, ", PRIMARY KEY (\"%s\")", + field->name); + break; + } + } + + p += snprintf(p, end - p, ")"); + *end = '\0'; + + return db_pg_exec_sql(__db, sql); +} + +static int db_pg_alter_table(struct ras_db *__db, + struct ras_stmt **__stmt, + const struct db_table_descriptor *db_tab) +{ + struct pg_conn_priv *conn_priv = (void *)__db; + PGconn *conn = conn_priv->conn; + char sql[512]; + PGresult *res; + const struct db_fields *field; + int i, nf, found, rc = 0; + + { + const char *params[] = { conn_priv->schema, db_tab->name }; + + res = PQexecParams(conn, + "SELECT column_name FROM information_schema.columns " + "WHERE table_schema = $1 AND table_name = $2", + 2, NULL, params, NULL, NULL, 0); + } + if (!res) { + log(TERM, LOG_ERR, "Failed to allocate PostgreSQL result\n"); + return -ENOMEM; + } + if (PQresultStatus(res) != PGRES_TUPLES_OK) { + log(TERM, LOG_ERR, + "Failed to query columns of %s: %s\n", + db_tab->name, PQresultErrorMessage(res)); + PQclear(res); + return -1; + } + + nf = PQntuples(res); + + for (i = 0; i < (int)db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + found = 0; + + for (int r = 0; r < nf; r++) { + if (!strcmp(field->name, PQgetvalue(res, r, 0))) { + found = 1; + break; + } + } + + if (!found) { + const char *type = db_pg_get_sql_type( + field->type, field->is_pk); + + snprintf(sql, sizeof(sql), + "ALTER TABLE %s.%s ADD COLUMN \"%s\" %s", + conn_priv->schema, db_tab->name, + field->name, type); + + { + PGresult *r2 = PQexec(conn, sql); + + if (!r2) { + log(TERM, LOG_ERR, + "Failed to allocate PostgreSQL result\n"); + rc = -ENOMEM; + } else if (PQresultStatus(r2) != PGRES_COMMAND_OK) { + log(TERM, LOG_ERR, + "ALTER TABLE %s ADD \"%s\": %s\n", + db_tab->name, field->name, + PQresultErrorMessage(r2)); + rc = -1; + } + if (r2) + PQclear(r2); + } + } + } + + PQclear(res); + return rc; +} + +static int db_pg_prepare_insert_stmt(struct ras_db *__db, + struct ras_stmt **__stmt, + const struct db_table_descriptor *db_tab) +{ + struct pg_conn_priv *conn_priv = (void *)__db; + const char *schema = conn_priv->schema; + PGconn *conn = conn_priv->conn; + char sql[2048], *p = sql, *end = sql + sizeof(sql) - 1; + char stmt_name[128]; + const struct db_fields *field; + unsigned int n_parms = 0; + struct pg_stmt_priv *priv; + int status, idx; + unsigned int i; + PGresult *res; + + for (i = 0; i < db_tab->num_fields; i++) { + if (db_tab->fields[i].type != DB_TYPE_SERIAL) + n_parms++; + } + + /* unique statement name: "ins_" */ + snprintf(stmt_name, sizeof(stmt_name), "ins_%s", db_tab->name); + + p = sql; + p += snprintf(p, end - p, "INSERT INTO %s.%s (", schema, db_tab->name); + for (i = 0; i < db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + + p += snprintf(p, end - p, "\"%s\"", field->name); + + if (i < db_tab->num_fields - 1) + p += snprintf(p, end - p, ", "); + } + p += snprintf(p, end - p, ", \"hostname\""); + p += snprintf(p, end - p, ") VALUES ("); + + idx = 1; + for (i = 0; i < db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + if (field->type == DB_TYPE_SERIAL) + p += snprintf(p, end - p, "DEFAULT"); + else + p += snprintf(p, end - p, "$%u", idx++); + + if (i < db_tab->num_fields - 1) + p += snprintf(p, end - p, ", "); + } + p += snprintf(p, end - p, ", $%u)", idx++); + n_parms++; + *end = '\0'; + +#ifdef DEBUG_SQL + log(TERM, LOG_INFO, "SQL: %s\n", sql); + ras_logger_flush(); +#endif + + res = PQprepare(conn, stmt_name, sql, n_parms, NULL); + if (!res) { + log(TERM, LOG_ERR, + "PQprepare failed for %s\n", db_tab->name); + return -1; + } + + status = PQresultStatus(res); + if (status != PGRES_COMMAND_OK) { + log(TERM, LOG_ERR, + "PQprepare failed for: %s\nStatus: %s, result: %sconnection: %s\n", + sql, + PQresStatus(status), + PQresultErrorMessage(res), + PQerrorMessage(conn)); + PQclear(res); + return -1; + } + PQclear(res); + + priv = calloc(1, sizeof(*priv)); + if (!priv) { + log(TERM, LOG_ERR, + "No memory for PostgreSQL stmt priv\n"); + return -ENOMEM; + } + + priv->values = calloc(n_parms, sizeof(char *)); + if (!priv->values) { + log(TERM, LOG_ERR, + "No memory for PostgreSQL stmt priv\n"); + free(priv); + return -ENOMEM; + } + + priv->lengths = calloc(n_parms, sizeof(*priv->lengths)); + if (!priv->lengths) { + log(TERM, LOG_ERR, + "No memory for PostgreSQL stmt priv\n"); + free(priv->values); + free(priv); + return -ENOMEM; + } + + priv->is_blob = calloc(n_parms, sizeof(*priv->is_blob)); + if (!priv->is_blob) { + log(TERM, LOG_ERR, + "No memory for PostgreSQL stmt priv\n"); + free(priv->lengths); + free(priv->values); + free(priv); + return -ENOMEM; + } + + priv->conn = conn; + priv->stmt_name = strdup(stmt_name); + if (!priv->stmt_name) { + free(priv->is_blob); + free(priv->lengths); + free(priv->values); + free(priv); + return -ENOMEM; + } + priv->n_params = n_parms; + priv->has_hostname = true; + + *__stmt = (void *)priv; + + log(TERM, LOG_INFO, "Recording %s events (postgresql)\n", + db_tab->name); + return 0; +} + +static void db_pg_free_stmt(struct pg_stmt_priv *priv) +{ + for (int i = 0; i < priv->n_params; i++) { + if (priv->values[i]) { + if (priv->is_blob[i]) + PQfreemem(priv->values[i]); + else + free(priv->values[i]); + + priv->values[i] = NULL; + } + } +} + + +static int db_pg_eval_stmt(struct ras_stmt *__stmt, const char *tab_name) +{ + struct pg_stmt_priv *priv = (struct pg_stmt_priv *)__stmt; + PGconn *conn = priv->conn; + PGresult *res; + int rc = 0; + + if (priv->has_hostname && + db_pg_bind_type(__stmt, DB_TYPE_TEXT, priv->n_params, + (uint64_t)rasdaemon_hostname, -1)) { + db_pg_free_stmt(priv); + return -1; + } + + res = PQexecPrepared(conn, priv->stmt_name, priv->n_params, + (const char * const*)priv->values, + priv->lengths, NULL, 0); + + if (!res) { + log(TERM, LOG_ERR, + "PQexecPrepared (%s) failed: %s\n", + tab_name, PQerrorMessage(conn)); + db_pg_free_stmt(priv); + return -1; + } + + if (PQresultStatus(res) != PGRES_COMMAND_OK && + PQresultStatus(res) != PGRES_TUPLES_OK) { + log(TERM, LOG_ERR, + "PQexecPrepared (%s): %s\n", + tab_name, PQresultErrorMessage(res)); + rc = -1; + } + + PQclear(res); + db_pg_free_stmt(priv); + + return rc; +} + +static int db_pg_finalize(unsigned int cpu, + struct ras_stmt *__stmt, const char *name) +{ + struct pg_stmt_priv *priv = (struct pg_stmt_priv *)__stmt; + + if (!priv) + return 0; + + db_pg_free_stmt(priv); + free(priv->stmt_name); + free(priv->values); + free(priv->lengths); + free(priv->is_blob); + free(priv); + + return 0; +} + +/* + * Backend registration + */ + +static const struct ras_db_backend_ops pg_backend_ops = { + .open = db_pg_open, + .close = db_pg_close, + .get_conn_parms = db_pg_get_conn_parms, + + .get_sql_type = db_pg_get_sql_type, + .bind_type = db_pg_bind_type, + + .db_exec_sql = db_pg_exec_sql, + + .eval_stmt = db_pg_eval_stmt, + .create_table = db_pg_create_table, + .alter_table = db_pg_alter_table, + .prepare_stmt = db_pg_prepare_insert_stmt, + .finalize = db_pg_finalize, +}; + +static struct ras_db_backend_entry pg_backend_entry = { + .name = "postgresql", + .ops = &pg_backend_ops, + .allow_remote = true, +}; + +static int pg_init(const char *name, struct ras_events *ras, void **priv) +{ + int ret; + + ret = db_backend_register(&pg_backend_entry); + if (ret != 0) + log(TERM, LOG_ERR, + "Failed to init PostgreSQL backend: %d\n", ret); + + return ret; +} + +const struct ras_module_entry db_postgresql_module = { + .name = "db-postgresql", + .init = pg_init, + .level = DB_MODULE, + .postpone_init = true, +}; + +__attribute__((constructor)) void pg_register(void) +{ + int ret; + + ret = module_register(&db_postgresql_module); + if (ret != 0) + log(TERM, LOG_ERR, + "Failed to register PostgreSQL module: %d\n", ret); +} diff --git a/db/db-postgresql.h b/db/db-postgresql.h new file mode 100644 index 00000000..74cfcf3c --- /dev/null +++ b/db/db-postgresql.h @@ -0,0 +1,36 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +#ifndef DB_POSTGRESQL_H +#define DB_POSTGRESQL_H + +#include + +/** + * struct db_postgresql_conn_params - PostgreSQL connection parameters + * @host: Hostname or IP. NULL or "localhost" for local Unix socket. + * @port: TCP port (default 5432). Ignored for local socket. + * @user: Username (default "rasdaemon"). + * @password: Password (default NULL / empty). + * @schema: Schema to be used (default "rasdaemon"). + * @database: Database name (default "rasdaemon"). + */ +struct db_postgresql_conn_params { + const char *host; + unsigned int port; + const char *user; + const char *password; + const char *schema; + const char *database; + + unsigned int connect_timeout; + + bool use_ssl; + const char *sslmode; +}; + +void postgresql_register_backend(void); + +#endif /* DB_POSTGRESQL_H */ diff --git a/db/db-sqlite3.c b/db/db-sqlite3.c new file mode 100644 index 00000000..17738daf --- /dev/null +++ b/db/db-sqlite3.c @@ -0,0 +1,520 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "config.h" + +#include "core/modules.h" +#include "core/ras-logger.h" + +#include "db/ras-db.h" +#include "db/ras-db-backend.h" +#include "db/db-sqlite3.h" + +//#define DEBUG_SQL + +/* Store the DB name on a static var to be used later on logs */ +static char *full_fname = NULL; + +static void *db_sqlite3_get_conn_parms(void) +{ + static struct db_sqlite3_conn_params cp; + + cp.database = env_or("RAS_SQLITE3_DATABASE", SQLITE3_DATABASE); + + return &cp; +} + +static int db_sqlite3_create_db_dir(const char *database) +{ + char *dir, *p; + struct stat st = {0}; + int rc = 0; + + dir = strdup(database); + if (!dir) + return -1; + + p = strrchr(dir, '/'); + if (!p) { + free(dir); + return 0; + } + + *p = '\0'; + + if (stat(dir, &st) == -1) { + if (errno != ENOENT || mkdir(dir, 0700) == -1) { + log(TERM, LOG_ERR, + "Failed to create SQLite3 database directory %s: %s\n", + dir, strerror(errno)); + rc = -1; + } + } else if (!S_ISDIR(st.st_mode)) { + log(TERM, LOG_ERR, + "SQLite3 database parent %s is not a directory\n", dir); + rc = -1; + } + + free(dir); + return rc; +} + +static int db_sqlite3_open(struct ras_db **__db, void *__conn_parms, + unsigned int cpu) +{ + struct db_sqlite3_conn_params *conn_parms = __conn_parms; + const char *database = SQLITE3_DATABASE; + sqlite3 **db = (void *)__db; + int flags, rc; + + *db = NULL; + + flags = SQLITE_OPEN_FULLMUTEX | + SQLITE_OPEN_READWRITE | + SQLITE_OPEN_CREATE; + + /* + * Allow overriding default values with private parameters + */ + if (conn_parms) { + if (conn_parms->database) + database = conn_parms->database; + if (conn_parms->extra_flags) + flags |= conn_parms->extra_flags; + } + + free(full_fname); + full_fname = strdup(database); + if (!full_fname) { + log(TERM, LOG_ERR, + "Failed to allocate SQLite3 database filename\n"); + return -1; + } + + if (db_sqlite3_create_db_dir(full_fname) < 0) { + free(full_fname); + full_fname = NULL; + return -1; + } + + rc = sqlite3_initialize(); + if (rc != SQLITE_OK) { + log(TERM, LOG_ERR, + "cpu %u: Failed to initialize sqlite: %s (error %d)\n", + cpu, sqlite3_errstr(rc), rc); + if (*db) { + sqlite3_close_v2(*db); + *db = NULL; + } + sqlite3_shutdown(); + free(full_fname); + full_fname = NULL; + return -1; + } + + do { + rc = sqlite3_open_v2(full_fname, db, flags, NULL); + if (rc == SQLITE_BUSY) + usleep(10000); + } while (rc == SQLITE_BUSY); + + if (rc != SQLITE_OK) { + log(TERM, LOG_ERR, + "cpu %u: Failed to connect to %s: %s (error %d)\n", + cpu, full_fname, sqlite3_errstr(rc), rc); + if (*db) { + sqlite3_close_v2(*db); + *db = NULL; + } + sqlite3_shutdown(); + free(full_fname); + full_fname = NULL; + return -1; + } + + return 0; +} + +static int db_sqlite3_close(struct ras_db *__db, unsigned int cpu) +{ + sqlite3 *db = (void *) __db; + int rc; + + rc = sqlite3_close_v2((sqlite3 *)db); + if (rc != SQLITE_OK) + log(TERM, LOG_ERR, + "cpu %u: Failed to close sqlite: %s (error %d)\n", cpu, + sqlite3_errstr(rc), rc); + + rc = sqlite3_shutdown(); + if (rc != SQLITE_OK) + log(TERM, LOG_ERR, + "cpu %u: Failed to shutdown sqlite: %s (error %d)\n", cpu, + sqlite3_errstr(rc), rc); + + free(full_fname); + full_fname = NULL; + + return rc; +} + +static const char *db_sqlite3_get_sql_type(enum db_field_type type, bool is_pk) +{ + /* + * On sqlite3, integers are 64 bits and there's no timestamp type + */ + switch (type) { + case DB_TYPE_SERIAL: + case DB_TYPE_INT64: + case DB_TYPE_INT32: + if (is_pk) + return "INTEGER PRIMARY KEY"; + return "INTEGER"; + case DB_TYPE_TIMESTAMP: + case DB_TYPE_TEXT: + if (is_pk) + return "TEXT PRIMARY KEY"; + return "TEXT"; + case DB_TYPE_BLOB: + default: + if (is_pk) + return "BLOB PRIMARY KEY"; + return "BLOB"; + } +} + +static int db_sqlite3_bind_type(struct ras_stmt *__stmt, + const enum db_field_type type, + const int pos, uint64_t value, int len) +{ + sqlite3_stmt *stmt = (void *)__stmt; + + switch (type) { + case DB_TYPE_SERIAL: + /* Use NULL to let sqlite3 to autofill it */ + return sqlite3_bind_null(stmt, pos); + + case DB_TYPE_INT32: + return sqlite3_bind_int(stmt, pos, value); + + case DB_TYPE_INT64: + return sqlite3_bind_int64(stmt, pos, value); + + case DB_TYPE_TIMESTAMP: + case DB_TYPE_TEXT: + case DB_TYPE_BLOB: + default: + if (!value) + return sqlite3_bind_null(stmt, pos); + + return sqlite3_bind_text(stmt, pos, (const char *)value, + len, SQLITE_TRANSIENT); + } +} + +static int db_sqlite3_eval_stmt(struct ras_stmt *__stmt, const char *tab_name) +{ + sqlite3_stmt *stmt = (void *)__stmt; + int rc; + + rc = sqlite3_step(stmt); + if (rc != SQLITE_DONE) + log(TERM, LOG_ERR, + "Failed to do step on sqlite. Table = %s: %s (error %d)\n", + tab_name, sqlite3_errstr(rc), rc); + + rc = sqlite3_reset(stmt); + if (rc != SQLITE_OK) + log(TERM, LOG_ERR, + "Failed to reset on sqlite. Table = %s: %s (error %d)\n", + tab_name, sqlite3_errstr(rc), rc); + + rc = sqlite3_clear_bindings(stmt); + if (rc != SQLITE_OK && rc != SQLITE_DONE) + log(TERM, LOG_ERR, + "Failed to clear bindings on sqlite. Table = %s: %s (error %d)\n", + tab_name, sqlite3_errstr(rc), rc); + + return rc; +} + +static int db_sqlite3_exec_sql(struct ras_db *__db, const char *sql) +{ + sqlite3 *db = (void *)__db; + int rc; + +#ifdef DEBUG_SQL + log(TERM, LOG_INFO, "SQL: %s\n", sql); + ras_logger_flush(); +#endif + + rc = sqlite3_exec(db, sql, NULL, NULL, NULL); + if (rc != SQLITE_OK) { + log(TERM, LOG_ERR, + "Failed to exec '%s': %s (error %d)\n", + sql, sqlite3_errstr(rc), rc); + } + + return rc; +} + +static int db_sqlite3_create_table(struct ras_db *__db, + const struct db_table_descriptor *db_tab) +{ + char sql[1024], *p = sql, *end = sql + sizeof(sql); + const struct db_fields *field; + const char *type; + int i; + + p += snprintf(p, end - p, "CREATE TABLE IF NOT EXISTS %s (", + db_tab->name); + + for (i = 0; i < db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + type = db_get_sql_type(field->type, field->is_pk); + + p += snprintf(p, end - p, "%s %s", field->name, type); + + if (i < db_tab->num_fields - 1) + p += snprintf(p, end - p, ", "); + } + p += snprintf(p, end - p, ")"); + + return db_sqlite3_exec_sql(__db, sql); +} + +static int db_sqlite3_alter_table(struct ras_db *__db, + struct ras_stmt **__stmt, + const struct db_table_descriptor *db_tab) +{ + char sql[1024], *p = sql, *end = sql + sizeof(sql); + sqlite3_stmt *schema_stmt = NULL; + const struct db_fields *field; + sqlite3 *db = (void *)__db; + const char *type; + int col_count; + int i, j, rc, found; + + (void)__stmt; + + snprintf(p, end - p, "SELECT * FROM %s", db_tab->name); + rc = sqlite3_prepare_v2(db, sql, -1, &schema_stmt, NULL); + if (rc != SQLITE_OK) { + log(TERM, LOG_ERR, + "Failed to query fields from the table %s on %s: : %s (error %d)\n", + db_tab->name, full_fname, sqlite3_errstr(rc), rc); + return rc; + } + + col_count = sqlite3_column_count(schema_stmt); + for (i = 0; i < db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + found = 0; + for (j = 0; j < col_count; j++) { + if (!strcmp(field->name, + sqlite3_column_name(schema_stmt, j))) { + found = 1; + break; + } + } + + if (!found) { + int ret; + type = db_get_sql_type(field->type, field->is_pk); + + /* add new field */ + p += snprintf(p, end - p, "ALTER TABLE %s ADD ", + db_tab->name); + p += snprintf(p, end - p, + "%s %s", field->name, type); + + ret = db_sqlite3_exec_sql(__db, sql); + if (ret) + rc = ret; + + p = sql; + *p = '\0'; + } + } + + if (sqlite3_finalize(schema_stmt) != SQLITE_OK && rc == SQLITE_OK) + rc = SQLITE_ERROR; + + return rc; +} + +static int __db_prepare_insert_stmt(struct sqlite3 *db, + sqlite3_stmt **stmt, + const struct db_table_descriptor *db_tab) + +{ + int i, rc; + char sql[1024], *p = sql, *end = sql + sizeof(sql); + const struct db_fields *field; + + p += snprintf(p, end - p, "INSERT INTO %s (", + db_tab->name); + + for (i = 0; i < db_tab->num_fields; i++) { + field = &db_tab->fields[i]; + p += snprintf(p, end - p, "%s", field->name); + + if (i < db_tab->num_fields - 1) + p += snprintf(p, end - p, ", "); + } + + p += snprintf(p, end - p, ") VALUES ("); + + for (i = 0; i < db_tab->num_fields; i++) { + if (db_tab->fields[i].type == DB_TYPE_SERIAL) + strscat(sql, "NULL", sizeof(sql)); + else + strscat(sql, "?", sizeof(sql)); + + if (i < db_tab->num_fields - 1) + strscat(sql, ", ", sizeof(sql)); + else + strscat(sql, ")", sizeof(sql)); + } + +#ifdef DEBUG_SQL + log(TERM, LOG_INFO, "SQL: %s\n", sql); + ras_logger_flush(); +#endif + + rc = sqlite3_prepare_v2(db, sql, -1, stmt, NULL); + if (rc != SQLITE_OK) { + log(TERM, LOG_ERR, + "Failed to prepare insert db at table %s (db %s): error = %s\n", + db_tab->name, full_fname, sqlite3_errmsg(db)); + stmt = NULL; + } else { + log(TERM, LOG_INFO, "Recording %s events\n", db_tab->name); + } + + return rc; +} + +static int db_sqlite3_prepare_insert_stmt(struct ras_db *__db, + struct ras_stmt **__stmt, + const struct db_table_descriptor *db_tab) +{ + sqlite3_stmt **stmt = (sqlite3_stmt **)__stmt; + sqlite3 *db = (sqlite3 *)__db; + int rc; + + rc = __db_prepare_insert_stmt(db, stmt, db_tab); + if (rc != SQLITE_OK) { + log(TERM, LOG_ERR, + "Failed to prepare insert db at table %s (db %s): error = %s\n", + db_tab->name, full_fname, sqlite3_errmsg(db)); + + log(TERM, LOG_INFO, "Trying to alter db at table %s (db %s)\n", + db_tab->name, full_fname); + + rc = db_alter_table(__db, __stmt, db_tab); + if (rc != SQLITE_OK && rc != SQLITE_DONE) { + log(TERM, LOG_ERR, + "Failed to alter db at table %s (db %s): error = %s\n", + db_tab->name, full_fname, sqlite3_errmsg(db)); + stmt = NULL; + return rc; + } + + rc = __db_prepare_insert_stmt(db, stmt, db_tab); + } + + return rc; +} + +static int db_sqlite3_finalize(unsigned int cpu, + struct ras_stmt *__stmt, const char *name) +{ + sqlite3_stmt *stmt = (void *)__stmt; + int rc; + + rc = sqlite3_finalize(stmt); + if (rc == SQLITE_OK) + return 0; + + if (cpu >= 0) + log(TERM, LOG_ERR, + "cpu %u: Failed to finalize %s. Sqlite: %s (error %d)\n", + cpu, name, sqlite3_errstr(rc), rc); + else + log(TERM, LOG_ERR, + "Failed to finalize sqlite: error = %d\n", rc); + + return rc; +} + +/* + * Database register data and init code + */ + +static const struct ras_db_backend_ops sqlite3_backend_ops = { + .get_conn_parms = db_sqlite3_get_conn_parms, + .open = db_sqlite3_open, + .close = db_sqlite3_close, + + .get_sql_type = db_sqlite3_get_sql_type, + .bind_type = db_sqlite3_bind_type, + + .db_exec_sql = db_sqlite3_exec_sql, + + .eval_stmt = db_sqlite3_eval_stmt, + .create_table = db_sqlite3_create_table, + .alter_table = db_sqlite3_alter_table, + .prepare_stmt = db_sqlite3_prepare_insert_stmt, + .finalize = db_sqlite3_finalize, +}; + +static struct ras_db_backend_entry sqlite3_backend_entry = { + .name = "sqlite3", + .ops = &sqlite3_backend_ops, +}; + +static int sqlite3_init(const char *name, struct ras_events *ras, void **priv) +{ + int ret; + + ret = db_backend_register(&sqlite3_backend_entry); + if (ret != 0) + log(TERM, LOG_ERR, "Failed to init SQLite3 backend: %d\n", ret); + + return ret; +} + +/* + * Module auto-register data and code + */ + +const struct ras_module_entry db_sqlite3_module = { + .name = "db-sqlite3", + .init = sqlite3_init, + .level = DB_MODULE, + .postpone_init = true, +}; + +/* + * Automatically register the module. + */ + +__attribute__((constructor)) void sqlite3_register(void) +{ + int ret; + + ret = module_register(&db_sqlite3_module); + if (ret != 0) + log(TERM, LOG_ERR, "Failed to register SQLite3 module: %d", ret); +} diff --git a/db/db-sqlite3.h b/db/db-sqlite3.h new file mode 100644 index 00000000..c0be48f6 --- /dev/null +++ b/db/db-sqlite3.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +struct db_sqlite3_conn_params { + const char *database; + int extra_flags; +}; + +void sqlite3_register_backend(void); diff --git a/db/ras-db-backend.h b/db/ras-db-backend.h new file mode 100644 index 00000000..dc78788b --- /dev/null +++ b/db/ras-db-backend.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef RAS_DB_REGISTER_H +#define RAS_DB_REGISTER_H + +#include +#include "db/ras-db.h" + +struct ras_db_backend_ops { + /* optional callbacks */ + void *(*get_conn_parms)(void); + + /* Mandatory callbacks */ + int (*open)(struct ras_db **db, void *conn_parms, + unsigned int cpu); + int (*close)(struct ras_db *db, unsigned int cpu); + + const char *(*get_sql_type)(enum db_field_type type, bool is_pk); + int (*bind_type)(struct ras_stmt *stmt, enum db_field_type type, + int pos, uint64_t value, int len); + + int (*db_exec_sql)(struct ras_db *__db, const char *sql); + + int (*eval_stmt)(struct ras_stmt *stmt, const char *tab_name); + + int (*create_table)(struct ras_db *db, + const struct db_table_descriptor *tab); + int (*alter_table)(struct ras_db *db, struct ras_stmt **stmt, + const struct db_table_descriptor *tab); + + int (*prepare_stmt)(struct ras_db *db, struct ras_stmt **stmt, + const struct db_table_descriptor *tab); + + int (*finalize)(unsigned int cpu, struct ras_stmt *stmt, + const char *name); +}; + +struct ras_db_backend_entry { + const char *name; + const struct ras_db_backend_ops *ops; + void *priv; + bool allow_remote; + + struct ras_db_backend_entry *next; +}; + +int db_backend_register(struct ras_db_backend_entry *entry); + +#endif /* RAS_DB_REGISTER_H */ diff --git a/db/ras-db.c b/db/ras-db.c new file mode 100644 index 00000000..4de82cb9 --- /dev/null +++ b/db/ras-db.c @@ -0,0 +1,369 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +#include +#include +#include + +#include "config.h" + +#include "core/ras-events.h" +#include "core/ras-logger.h" + +#include "db/ras-db.h" +#include "db/ras-db-backend.h" + +const char *selected_backend = NULL; +struct ras_db_backend_entry ras_db_backends = { 0 }; +const struct ras_db_backend_ops *ras_db_ops = NULL; + +const char *rasdaemon_hostname = ""; + +static bool add_hostname = false; + +int db_backend_register(struct ras_db_backend_entry *entry) +{ + const struct ras_db_backend_ops *ops; + const char *name; + struct ras_db_backend_entry **head = &ras_db_backends.next; + struct ras_db_backend_entry *new, *cur, *prev = NULL; + + if (!entry) { + log(TERM, LOG_ERR, "Backend entry is missing!\n"); + return -EINVAL; + } + ops = entry->ops; + name = entry->name; + + if (!ops || !ops->get_sql_type || !ops->bind_type || + !ops->eval_stmt || !ops->create_table || !ops->alter_table || + !ops->prepare_stmt || !ops->finalize || !ops->open || + !ops->close || !ops->db_exec_sql) { + log(TERM, LOG_ERR, "Incomplete ops for backend %s\n", name); + return -EINVAL; + } + + new = malloc(sizeof(*new)); + if (!new) { + log(ALL, LOG_ERR, "no memory to register module %s\n", + entry->name); + return -ENOMEM; + } + memcpy(new, entry, sizeof(*entry)); + + /* Keep it alphabetically sorted */ + for (cur = ras_db_backends.next; cur; cur = cur->next) { + if (strcmp(entry->name, cur->name) < 0) + break; + + prev = cur; + } + + if (!prev) { + new->next = *head; + *head = new; + } else { + new->next = prev->next; + prev->next = new; + } + + return 0; +} + +const char *db_list_available_backends(void) +{ + const struct ras_db_backend_entry *entry; + static char buf[256]; + int len = 0; + + buf[0] = '\0'; + + for (entry = ras_db_backends.next; entry; entry = entry->next) { + if (len > 0) + strncat(buf, ", ", sizeof(buf) - len - 1); + strncat(buf, entry->name, sizeof(buf) - len - 1); + len = (int)strlen(buf); + } + + return buf; +} + +int db_backend_enable(const char *name) +{ + const struct ras_db_backend_entry *entry = NULL; + const char *backend; + + if (name) + backend = name; + else + backend = env_or("RASDAEMON_DB_BACKEND", "sqlite3"); + + for (entry = ras_db_backends.next; entry; entry = entry->next) { + if (strcmp(entry->name, backend) == 0) + break; + } + + if (!entry) { + log(TERM, LOG_ERR, + "Backend '%s' not found. Available: %s\n", + backend, db_list_available_backends()); + return -1; + } + + log(TERM, LOG_INFO, "Enabling DB backend: %s\n", backend); + selected_backend = backend; + return 0; +} + +static void db_get_rasdaemon_hostname(void) +{ + const char *env_hostname; + char hostname[256]; + + /* Hostname already set */ + if (*rasdaemon_hostname) + return; + + env_hostname = getenv("RASDAEMON_HOSTNAME"); + if (env_hostname != NULL && env_hostname[0] != '\0') { + rasdaemon_hostname = env_hostname; + return; + } + + if (gethostname(hostname, sizeof(hostname)) != 0) { + log(TERM, LOG_ERR, "Failed to get hostname\n"); + return; + } + + rasdaemon_hostname = strdup(hostname); +} + +/* + * Callback wrappers. + * + * NOTE: They don't need to check if ras_db_ops->callback is not + * NULL, as the register code above already warrants it. + */ + +/* + * While multiple backends can be compiled, only one can be active, + * as we're storing database pointers inside ras->db and we have only + * one db_priv at ras_events. To keep it simple, use a static var to + * store the active backend, + */ + +int db_open(struct db_backend *backend, unsigned int cpu, + struct ras_events *ras, size_t size_priv) +{ + struct ras_db_backend_entry *entry = &ras_db_backends; + const char *backend_name; + void *conn_parms; + void *db_priv; + int rc; + + ras->db_ref_count++; + if (ras->db_ref_count > 1) { + log(TERM, LOG_INFO, + "Database was already opened.\n"); + return 0; + } + + db_priv = calloc(1, size_priv); + if (!db_priv) { + log(TERM, LOG_ERR, + "Failed to allocate memory for backend\n"); + ras->db_ref_count--; + return -ENOMEM; + } + + if (backend && backend->name) + backend_name = backend->name; + else + backend_name = selected_backend; + + for (entry = entry->next; entry; entry = entry->next) { + if (strcmp(backend_name, entry->name)) { + continue; + } + + if (backend) + conn_parms = backend->conn_parms; + else if (entry->ops->get_conn_parms) + conn_parms = entry->ops->get_conn_parms(); + else + conn_parms = NULL; + + if (entry->allow_remote) { + add_hostname = true; + db_get_rasdaemon_hostname(); + } else { + add_hostname = false; + } + + rc = entry->ops->open(&ras->db, conn_parms, cpu); + if (!rc) { + ras->db_priv = db_priv; + ras_db_ops = entry->ops; + log(TERM, LOG_INFO, + "Database backend started: %s.\n", entry->name); + + return 0; + } + } + log(TERM, LOG_INFO, "Database backend %s not found.\n", backend_name); + free(db_priv); + + ras->db_ref_count--; + return -1; +} + +int db_close(unsigned int cpu, struct ras_events *ras) +{ + int rc; + + if (!ras_db_ops) + return 0; + if (ras->db_ref_count <= 0) + return -EINVAL; + + ras->db_ref_count--; + + if (ras->db_ref_count > 0) + return 0; + + rc = ras_db_ops->close(ras->db, cpu); + ras_db_ops = NULL; + free(ras->db_priv); + ras->db = NULL; + + return rc; +} + +const char *db_get_sql_type(enum db_field_type type, bool is_pk) +{ + if (!ras_db_ops) + return ""; + + return ras_db_ops->get_sql_type(type, is_pk); +} + +int db_bind_type(struct ras_stmt *stmt, const enum db_field_type type, + int pos, uint64_t value, int len) +{ + if (!ras_db_ops) + return 0; + + return ras_db_ops->bind_type(stmt, type, pos, value, len); +} + +int db_bind(const struct db_table_descriptor *db_tab, + struct ras_stmt *stmt, int pos, uint64_t value, int len) +{ + const struct db_fields *fields = db_tab->fields; + int i, field_pos = 0; + + if (!ras_db_ops) + return 0; + + if (pos < 1) { + log(TERM, LOG_INFO, "table %s: invalid placeholder: %d\n", + db_tab->name, pos); + return -1; + } + + for (i = 0; i < db_tab->num_fields; i++) { + if (fields[i].type == DB_TYPE_SERIAL) { + continue; + } + + if (field_pos == pos - 1) + break; + + field_pos++; + } + if (field_pos != pos - 1) { + log(TERM, LOG_INFO, "table %s: invalid placeholder: %d\n", + db_tab->name, pos); + return -1; + } + + return db_bind_type(stmt, db_tab->fields[i].type, + pos, value, len); +} + +int db_eval_stmt(struct ras_stmt *stmt, const char *tab_name) +{ + if (!ras_db_ops) + return 0; + + return ras_db_ops->eval_stmt(stmt, tab_name); +} + +int db_create_table(struct ras_db *db, const struct db_table_descriptor *db_tab) +{ + if (!ras_db_ops) + return 0; + + return ras_db_ops->create_table(db, db_tab); +} + +int db_alter_table(struct ras_db *db, struct ras_stmt **stmt, + const struct db_table_descriptor *db_tab) +{ + if (!ras_db_ops) + return 0; + + return ras_db_ops->alter_table(db, stmt, db_tab); +} + +int db_prepare_insert_stmt(struct ras_db *db, struct ras_stmt **stmt, + const struct db_table_descriptor *db_tab) +{ + if (!ras_db_ops) + return 0; + return ras_db_ops->prepare_stmt(db, stmt, db_tab); +} + +int db_create_table_prep_stmt(struct ras_events *ras, struct ras_stmt **stmt, + const struct db_table_descriptor *db_tab) +{ + int rc; + + if (!ras_db_ops) + return 0; + + rc = ras_db_ops->create_table(ras->db, db_tab); + if (rc) + return rc; + + return ras_db_ops->prepare_stmt(ras->db, stmt, db_tab); +} + +int db_exec_sql(struct ras_db *db, const char *sql) +{ + if (!ras_db_ops) + return 0; + + return ras_db_ops->db_exec_sql(db, sql); +} + +int db_finalize(struct ras_stmt *stmt) +{ + if (!ras_db_ops) + return 0; + + if (!stmt) + return 0; + + return ras_db_ops->finalize(-1, stmt, NULL); +} + +int db_cpu_finalize(unsigned int cpu, struct ras_stmt *stmt, const char *name) +{ + if (!ras_db_ops) + return 0; + + return ras_db_ops->finalize(cpu, stmt, name); +} diff --git a/db/ras-db.h b/db/ras-db.h new file mode 100644 index 00000000..dba92aa9 --- /dev/null +++ b/db/ras-db.h @@ -0,0 +1,305 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (C) 2026 Mauro Carvalho Chehab + */ + +#ifndef RAS_DB_H +#define RAS_DB_H + +#include "config.h" + +#include +#include +#include + +#ifndef HAVE_DB + +static inline int db_backend_enable(const char *name) { return 0; } + +#else + +extern const char *rasdaemon_hostname; + +/** + * db_backend_enable - select backend to use + * @name: name of the backend. NULL to allow selecting via env vars + * Returns: if the env var exists, return its content; otherwise returns @def. + */ +int db_backend_enable(const char *name); + +/* #define DEBUG_SQL 1 */ + +/* Opaque types to make SQL data structs generic */ +struct ras_db; +struct ras_stmt; +struct ras_events; + +/** + * enum db_field_type - Supported database column types + * @DB_TYPE_SERIAL: Auto-increment integer + * @DB_TYPE_INT32: 32-bit signed integer + * @DB_TYPE_INT64: 64-bit signed integer + * @DB_TYPE_TIMESTAMP: ISO timestamp (string or numeric value) + * @DB_TYPE_TEXT: Variable-length string + * @DB_TYPE_BLOB: Binary data + */ +enum db_field_type { + DB_TYPE_SERIAL, + DB_TYPE_INT32, + DB_TYPE_INT64, + DB_TYPE_TIMESTAMP, + DB_TYPE_TEXT, + DB_TYPE_BLOB, +}; + +/** + * env_or - ancillary routine to get an environment with a default value + * @name: name of the variable + * @def: default value + * Returns: if the env var exists, return its content; otherwise returns @def. + */ +static inline const char *env_or(const char *name, const char *def) +{ + const char *v = getenv(name); + + return (v && v[0]) ? v : def; +} + +/** + * env_or_bool - get a boolean from an environment variable + * @name: name of the variable + * @def: default value (0 or 1) + * Returns: false if env var is false, 0 or no; true otherwise. + */ +static inline int env_or_bool(const char *name, int def) +{ + const char *v = getenv(name); + + if (!v || !v[0]) + return def; + + return (!strcmp(v, "0") || + !strcmp(v, "false") || + !strcmp(v, "no")) ? false : true; +} + +/** + * env_or_int - get an integer from an environment variable + * @name: name of the variable + * @def: default value + * Returns: the parsed integer, or @def if parsing fails. + */ +static inline int env_or_int(const char *name, int def) +{ + const char *v = getenv(name); + int val; + + if (!v || !v[0]) + return def; + + val = atoi(v); + return (val) ? val : def; +} + +/** + * struct db_fields - Definition of a single column in a table descriptor + * @name: Column name identifier + * @type: Data type enumeration for binding logic + * @is_pk: True if this field is the primary key (affects SQL generation) + */ +struct db_fields { + const char *name; + enum db_field_type type; + bool is_pk; +}; + +/** + * struct db_table_descriptor - Metadata describing a database table schema + * @name: Name of the table in the database + * @fields: Array of column definitions + * @num_fields: Total count of columns in the array + */ +struct db_table_descriptor { + const char *name; + const struct db_fields *fields; + size_t num_fields; +}; + +#ifdef HAVE_UNITTEST +struct db_table_descriptor_list { + const struct db_table_descriptor * const *tables; + size_t num_tables; +}; + +struct db_table_descriptor_list ras_record_table_descriptors(void); +struct db_table_descriptor_list ampere_table_descriptors(void); +struct db_table_descriptor_list hip08_table_descriptors(void); +struct db_table_descriptor_list hisilicon_table_descriptors(void); +struct db_table_descriptor_list jaguarmicro_table_descriptors(void); +struct db_table_descriptor_list nvidia_table_descriptors(void); +struct db_table_descriptor_list yitian_table_descriptors(void); +#endif + +/** + * struct db_backend - Specify what DB backend will be used + * @backend: Name of backend driver + * @conn_parms: Connection parameters (specific to each type of DB + */ +struct db_backend { + const char *name; + void *conn_parms; +}; + +/** + * ops_bind_type - Bind a single value based on its type descriptor + * @stmt: Statement handle provided by the backend + * @type: The type of data being bound + * @pos: Parameter position (1-based index) + * @value: Raw 64-bit integer representation of the value + * @len: Length for text/blob types, -1 if null-terminated + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_bind_type(struct ras_stmt *stmt, const enum db_field_type type, + const int pos, uint64_t value, int len); + +/** + * ops_bind - Bind fields from an event structure using fields definition + * @db_tab: Database table descriptor + * @stmt: Statement handle provided by the backend + * @pos: Starting position index placeholder (starts with 1) + * @value: Pointer to raw data buffer containing all field values + * @len: Length of the buffer (optional, depends on implementation) + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_bind(const struct db_table_descriptor *db_tab, + struct ras_stmt *stmt, int pos, uint64_t value, int len); + +/** + * db_get_sql_type - Return SQL column type string for a given field type + * @type: Field type descriptor from the enum db_field_type + * @is_pk: True if the column is declared as primary key in SQL + * + * Returns: + * an opaque C-string describing the SQL type to use, e.g. + * "INTEGER PRIMARY KEY", "TEXT", or "BLOB". The caller must free + * the returned string when it is no longer needed. + */ +const char *db_get_sql_type(enum db_field_type type, bool is_pk); + +/** + * db_eval_stmt - Execute a prepared SQL statement + * @stmt: Prepared statement handle to execute + * @tab_name: Name of the table whose data should be read/written + * + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_eval_stmt(struct ras_stmt *stmt, const char *tab_name); + +/** + * db_create_table - Create a new database table from its descriptor + * @db: Database connection handle (opaque) + * @db_tab: Table descriptor containing the schema to create + * + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_create_table(struct ras_db *db, + const struct db_table_descriptor *db_tab); + +/** + * db_alter_table - Modify an existing database table structure + * @db: Database connection handle (opaque) + * @stmt: Output pointer for a prepared statement describing the change + * @db_tab: Table descriptor containing the new schema to apply + * + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_alter_table(struct ras_db *db, + struct ras_stmt **stmt, + const struct db_table_descriptor *db_tab); + +/** + * db_prepare_insert_stmt - Prepare a generic SQL statement for execution + * @db: Database connection handle (opaque) + * @stmt: Output pointer for the prepared statement handle + * @db_tab: Table descriptor providing context for the query + * + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_prepare_insert_stmt(struct ras_db *db, + struct ras_stmt **stmt, + const struct db_table_descriptor *db_tab); + +/** + * db_create_table_prep_stmt - Prepare a CREATE TABLE statement for caching + * @ras: RAS events context (opaque) + * @stmt: Output pointer for the prepared statement handle + * @db_tab: Table descriptor containing the schema to create + * + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_create_table_prep_stmt(struct ras_events *ras, struct ras_stmt **stmt, + const struct db_table_descriptor *db_tab); + + +/** + * db_exec_sql - Execute a SQL statement + * @stmt: Prepared statement handle to finalize + * @sql: SQL command to execute + * + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_exec_sql(struct ras_db *db, const char *sql); + +/** + * db_finalize - Finalize and release resources for a prepared statement + * @stmt: Prepared statement handle to finalize + * + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_finalize(struct ras_stmt *stmt); + +/** + * db_cpu_finalize - CPU-local cleanup of a prepared statement resource + * @cpu: Logical CPU number for per-CPU bookkeeping (opaque) + * @stmt: Prepared statement handle to finalize + * @name: Name string for the resource being cleaned up + * + * Returns: + * 0 on success or a negative errno value on failure..conn + */ +int db_cpu_finalize(unsigned int cpu, struct ras_stmt *stmt, const char *name); + +/** + * db_open - Open and initialize a database connection + * @cpu: Logical CPU number for per-CPU bookkeeping (opaque) + * @ras: RAS events context (opaque) + * @size_priv: Private memory size to allocate for the database handle + * + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_open(struct db_backend *backend, unsigned int cpu, + struct ras_events *ras, size_t size_priv); + +/** + * db_close - Close and release resources of an open database connection + * @cpu: Logical CPU number for per-CPU bookkeeping (opaque) + * @ras: RAS events context (opaque) + * + * Returns: + * 0 on success or a negative errno value on failure. + */ +int db_close(unsigned int cpu, struct ras_events *ras); + +#endif /* HAVE_DB */ + +#endif /* RAS_DB_H */ diff --git a/db/ras-record.c b/db/ras-record.c new file mode 100644 index 00000000..032c7c52 --- /dev/null +++ b/db/ras-record.c @@ -0,0 +1,1458 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +/* + * Copyright (C) 2013 Mauro Carvalho Chehab + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#include "modules/ras-aer-handler.h" +#include "core/ras-events.h" +#include "core/ras-logger.h" +#include "events-arch-x86/ras-mce-handler.h" +#include "core/ras-mc-handler.h" +#include "db/ras-record.h" +#include "events/ras-reri-handler.h" + +#ifdef HAVE_DB + +/* + * Table and functions to handle ras:mc_event + */ + +static const struct db_fields mc_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP}, + { .name = "err_count", .type = DB_TYPE_INT32 }, + { .name = "err_type", .type = DB_TYPE_TEXT }, + { .name = "err_msg", .type = DB_TYPE_TEXT }, + { .name = "label", .type = DB_TYPE_TEXT }, + { .name = "mc", .type = DB_TYPE_INT32 }, + { .name = "top_layer", .type = DB_TYPE_INT32 }, + { .name = "middle_layer", .type = DB_TYPE_INT32 }, + { .name = "lower_layer", .type = DB_TYPE_INT32 }, + { .name = "address", .type = DB_TYPE_INT64 }, + { .name = "grain", .type = DB_TYPE_INT64 }, + { .name = "syndrome", .type = DB_TYPE_INT64 }, + { .name = "driver_detail", .type = DB_TYPE_TEXT }, +}; + +static const struct db_table_descriptor mc_event_tab = { + .name = "mc_event", + .fields = mc_event_fields, + .num_fields = ARRAY_SIZE(mc_event_fields), +}; + +int db_mc_event(struct ras_events *ras, struct ras_mc_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_mc_event) + return 0; + log(TERM, LOG_INFO, "mc_event store: %p\n", priv->stmt_mc_event); + + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, ev->error_count, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, (uint64_t)ev->error_type, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, (uint64_t)ev->msg, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, (uint64_t)ev->label, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, ev->mc_index, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, ev->top_layer, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, ev->middle_layer, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, ev->lower_layer, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, ev->address, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, ev->grain, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, ev->syndrome, -1); + db_bind(&mc_event_tab, priv->stmt_mc_event, pos++, (uint64_t)ev->driver_detail, -1); + + rc = db_eval_stmt(priv->stmt_mc_event, "mc_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} + +/* + * Table and functions to handle ras:aer + */ + +#ifdef HAVE_AER +static const struct db_fields aer_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "dev_name", .type = DB_TYPE_TEXT }, + { .name = "err_type", .type = DB_TYPE_TEXT }, + { .name = "err_msg", .type = DB_TYPE_TEXT }, +}; + +static const struct db_table_descriptor aer_event_tab = { + .name = "aer_event", + .fields = aer_event_fields, + .num_fields = ARRAY_SIZE(aer_event_fields), +}; + +int db_aer_event(struct ras_events *ras, struct ras_aer_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_aer_event) + return 0; + log(TERM, LOG_INFO, "aer_event store: %p\n", priv->stmt_aer_event); + + db_bind(&aer_event_tab, priv->stmt_aer_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&aer_event_tab, priv->stmt_aer_event, pos++, (uint64_t)ev->dev_name, -1); + db_bind(&aer_event_tab, priv->stmt_aer_event, pos++, (uint64_t)ev->error_type, -1); + db_bind(&aer_event_tab, priv->stmt_aer_event, pos++, (uint64_t)ev->msg, -1); + + rc = db_eval_stmt(priv->stmt_aer_event, "aer_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +/* + * Table and functions to handle ras:non standard + */ + +#ifdef HAVE_NON_STANDARD +static const struct db_fields non_standard_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "sec_type", .type = DB_TYPE_BLOB }, + { .name = "fru_id", .type = DB_TYPE_BLOB }, + { .name = "fru_text", .type = DB_TYPE_TEXT }, + { .name = "severity", .type = DB_TYPE_TEXT }, + { .name = "error", .type = DB_TYPE_BLOB }, +}; + +static const struct db_table_descriptor non_standard_event_tab = { + .name = "non_standard_event", + .fields = non_standard_event_fields, + .num_fields = ARRAY_SIZE(non_standard_event_fields), +}; + +int db_non_standard_record(struct ras_events *ras, struct ras_non_standard_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_non_standard_record) + return 0; + log(TERM, LOG_INFO, "non_standard_event store: %p\n", priv->stmt_non_standard_record); + + db_bind(&non_standard_event_tab, priv->stmt_non_standard_record, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&non_standard_event_tab, priv->stmt_non_standard_record, pos++, (uint64_t)ev->sec_type, -1); + db_bind(&non_standard_event_tab, priv->stmt_non_standard_record, pos++, (uint64_t)ev->fru_id, 16); + db_bind(&non_standard_event_tab, priv->stmt_non_standard_record, pos++, (uint64_t)ev->fru_text, -1); + db_bind(&non_standard_event_tab, priv->stmt_non_standard_record, pos++, (uint64_t)ev->severity, -1); + db_bind(&non_standard_event_tab, priv->stmt_non_standard_record, pos++, (uint64_t)ev->error, ev->length); + + rc = db_eval_stmt(priv->stmt_non_standard_record, "non_standard_record"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +/* + * Table and functions to handle ras:arm + */ + +#ifdef HAVE_ARM +static const struct db_fields arm_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "error_count", .type = DB_TYPE_INT32 }, + { .name = "affinity", .type = DB_TYPE_INT32 }, + { .name = "mpidr", .type = DB_TYPE_INT64 }, + { .name = "running_state", .type = DB_TYPE_INT32 }, + { .name = "psci_state", .type = DB_TYPE_INT32 }, + { .name = "err_info", .type = DB_TYPE_BLOB }, + { .name = "context_info", .type = DB_TYPE_BLOB }, + { .name = "vendor_info", .type = DB_TYPE_BLOB }, + { .name = "error_type", .type = DB_TYPE_TEXT }, + { .name = "error_flags", .type = DB_TYPE_TEXT }, + { .name = "error_info", .type = DB_TYPE_INT64 }, + { .name = "virt_fault_addr", .type = DB_TYPE_INT64 }, + { .name = "phy_fault_addr", .type = DB_TYPE_INT64 }, +}; + +static const struct db_table_descriptor arm_event_tab = { + .name = "arm_event", + .fields = arm_event_fields, + .num_fields = ARRAY_SIZE(arm_event_fields), +}; + +int db_arm_record(struct ras_events *ras, struct ras_arm_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_arm_record) + return 0; + log(TERM, LOG_INFO, "arm_event store: %p\n", priv->stmt_arm_record); + + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, ev->error_count, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, ev->affinity, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, ev->mpidr, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, ev->running_state, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, ev->psci_state, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, (uint64_t)ev->pei_error, ev->pei_len); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, (uint64_t)ev->ctx_error, ev->ctx_len); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, (uint64_t)ev->vsei_error, ev->oem_len); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, (uint64_t)ev->error_types, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, (uint64_t)ev->error_flags, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, ev->error_info, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, ev->virt_fault_addr, -1); + db_bind(&arm_event_tab, priv->stmt_arm_record, pos++, ev->phy_fault_addr, -1); + + rc = db_eval_stmt(priv->stmt_arm_record, "arm_record"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +#ifdef HAVE_EXTLOG +static const struct db_fields extlog_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "etype", .type = DB_TYPE_INT32 }, + { .name = "error_count", .type = DB_TYPE_INT32 }, + { .name = "severity", .type = DB_TYPE_INT32 }, + { .name = "address", .type = DB_TYPE_INT64 }, + { .name = "fru_id", .type = DB_TYPE_BLOB }, + { .name = "fru_text", .type = DB_TYPE_TEXT }, + { .name = "cper_data", .type = DB_TYPE_BLOB }, +}; + +static const struct db_table_descriptor extlog_event_tab = { + .name = "extlog_event", + .fields = extlog_event_fields, + .num_fields = ARRAY_SIZE(extlog_event_fields), +}; + +int db_extlog_mem_record(struct ras_events *ras, struct ras_extlog_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_extlog_record) + return 0; + log(TERM, LOG_INFO, "extlog_record store: %p\n", priv->stmt_extlog_record); + + db_bind(&extlog_event_tab, priv->stmt_extlog_record, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&extlog_event_tab, priv->stmt_extlog_record, pos++, ev->etype, -1); + db_bind(&extlog_event_tab, priv->stmt_extlog_record, pos++, ev->error_seq, -1); + db_bind(&extlog_event_tab, priv->stmt_extlog_record, pos++, ev->severity, -1); + db_bind(&extlog_event_tab, priv->stmt_extlog_record, pos++, ev->address, -1); + db_bind(&extlog_event_tab, priv->stmt_extlog_record, pos++, (uint64_t)ev->fru_id, 16); + db_bind(&extlog_event_tab, priv->stmt_extlog_record, pos++, (uint64_t)ev->fru_text, -1); + db_bind(&extlog_event_tab, priv->stmt_extlog_record, pos++, (uint64_t)ev->cper_data, ev->cper_data_length); + + rc = db_eval_stmt(priv->stmt_extlog_record, "extlog_record"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +/* + * Table and functions to handle mce:mce_record + */ + +#ifdef HAVE_MCE +static const struct db_fields mce_record_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + + /* MCE registers */ + { .name = "mcgcap", .type = DB_TYPE_INT32 }, + { .name = "mcgstatus", .type = DB_TYPE_INT32 }, + { .name = "status", .type = DB_TYPE_INT64 }, + { .name = "addr", .type = DB_TYPE_INT64 }, // 5 + { .name = "misc", .type = DB_TYPE_INT64 }, + { .name = "ip", .type = DB_TYPE_INT64 }, + { .name = "tsc", .type = DB_TYPE_INT64 }, + { .name = "walltime", .type = DB_TYPE_INT64 }, + { .name = "ppin", .type = DB_TYPE_INT32 }, // 10 + { .name = "cpu", .type = DB_TYPE_INT32 }, + { .name = "cpuid", .type = DB_TYPE_INT32 }, + { .name = "apicid", .type = DB_TYPE_INT32 }, + { .name = "socketid", .type = DB_TYPE_INT32 }, + { .name = "cs", .type = DB_TYPE_INT32 }, // 15 + { .name = "bank", .type = DB_TYPE_INT32 }, + { .name = "cpuvendor", .type = DB_TYPE_INT32 }, + { .name = "microcode", .type = DB_TYPE_INT32 }, + + /* Parsed data - will likely change */ + { .name = "bank_name", .type = DB_TYPE_TEXT }, + { .name = "error_msg", .type = DB_TYPE_TEXT }, // 20 + { .name = "mcgstatus_msg", .type = DB_TYPE_TEXT }, + { .name = "mcistatus_msg", .type = DB_TYPE_TEXT }, + { .name = "mcastatus_msg", .type = DB_TYPE_TEXT }, + { .name = "user_action", .type = DB_TYPE_TEXT }, + { .name = "mc_location", .type = DB_TYPE_TEXT }, +}; + +static const struct db_table_descriptor mce_record_tab = { + .name = "mce_record", + .fields = mce_record_fields, + .num_fields = ARRAY_SIZE(mce_record_fields), +}; + +int db_mce_record(struct ras_events *ras, struct mce_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_mce_record) + return 0; + log(TERM, LOG_INFO, "mce_record store: %p\n", priv->stmt_mce_record); + + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->mcgcap, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->mcgstatus, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->status, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->addr, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->misc, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->ip, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->tsc, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->walltime, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->ppin, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->cpu, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->cpuid, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->apicid, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->socketid, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->cs, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->bank, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->cpuvendor, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, ev->microcode, -1); + + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, (uint64_t)ev->bank_name, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, (uint64_t)ev->error_msg, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, (uint64_t)ev->mcgstatus_msg, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, (uint64_t)ev->mcistatus_msg, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, (uint64_t)ev->mcastatus_msg, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, (uint64_t)ev->user_action, -1); + db_bind(&mce_record_tab, priv->stmt_mce_record, pos++, (uint64_t)ev->mc_location, -1); + + rc = db_eval_stmt(priv->stmt_mce_record, "mce_record"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +/* + * Table and functions to handle devlink:devlink_health_report + */ + +#ifdef HAVE_DEVLINK +static const struct db_fields devlink_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "bus_name", .type = DB_TYPE_TEXT }, + { .name = "dev_name", .type = DB_TYPE_TEXT }, + { .name = "driver_name", .type = DB_TYPE_TEXT }, + { .name = "reporter_name", .type = DB_TYPE_TEXT }, + { .name = "msg", .type = DB_TYPE_TEXT }, +}; + +static const struct db_table_descriptor devlink_event_tab = { + .name = "devlink_event", + .fields = devlink_event_fields, + .num_fields = ARRAY_SIZE(devlink_event_fields), +}; + +int db_devlink_event(struct ras_events *ras, struct devlink_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_devlink_event) + return 0; + log(TERM, LOG_INFO, "devlink_event store: %p\n", priv->stmt_devlink_event); + + db_bind(&devlink_event_tab, priv->stmt_devlink_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&devlink_event_tab, priv->stmt_devlink_event, pos++, (uint64_t)ev->bus_name, -1); + db_bind(&devlink_event_tab, priv->stmt_devlink_event, pos++, (uint64_t)ev->dev_name, -1); + db_bind(&devlink_event_tab, priv->stmt_devlink_event, pos++, (uint64_t)ev->driver_name, -1); + db_bind(&devlink_event_tab, priv->stmt_devlink_event, pos++, (uint64_t)ev->reporter_name, -1); + db_bind(&devlink_event_tab, priv->stmt_devlink_event, pos++, (uint64_t)ev->msg, -1); + + rc = db_eval_stmt(priv->stmt_devlink_event, "devlink_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +/* + * Table and functions to handle block:block_rq_{complete|error} + */ + +#ifdef HAVE_DISKERROR +static const struct db_fields diskerror_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "dev", .type = DB_TYPE_TEXT }, + { .name = "sector", .type = DB_TYPE_INT64 }, + { .name = "nr_sector", .type = DB_TYPE_INT32 }, + { .name = "error", .type = DB_TYPE_TEXT }, + { .name = "rwbs", .type = DB_TYPE_TEXT }, + { .name = "cmd", .type = DB_TYPE_TEXT }, +}; + +static const struct db_table_descriptor diskerror_event_tab = { + .name = "disk_errors", + .fields = diskerror_event_fields, + .num_fields = ARRAY_SIZE(diskerror_event_fields), +}; + +int db_diskerror_event(struct ras_events *ras, struct diskerror_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_diskerror_event) + return 0; + log(TERM, LOG_INFO, "diskerror_event store: %p\n", priv->stmt_diskerror_event); + + db_bind(&diskerror_event_tab, priv->stmt_diskerror_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&diskerror_event_tab, priv->stmt_diskerror_event, pos++, (uint64_t)ev->dev, -1); + db_bind(&diskerror_event_tab, priv->stmt_diskerror_event, pos++, ev->sector, -1); + db_bind(&diskerror_event_tab, priv->stmt_diskerror_event, pos++, ev->nr_sector, -1); + db_bind(&diskerror_event_tab, priv->stmt_diskerror_event, pos++, (uint64_t)ev->error, -1); + db_bind(&diskerror_event_tab, priv->stmt_diskerror_event, pos++, (uint64_t)ev->rwbs, -1); + db_bind(&diskerror_event_tab, priv->stmt_diskerror_event, pos++, (uint64_t)ev->cmd, -1); + + rc = db_eval_stmt(priv->stmt_diskerror_event, "diskerror_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +/* + * Table and functions to handle ras:memory_failure + */ + +#ifdef HAVE_MEMORY_FAILURE +static const struct db_fields mf_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "pfn", .type = DB_TYPE_TEXT }, + { .name = "page_type", .type = DB_TYPE_TEXT }, + { .name = "action_result", .type = DB_TYPE_TEXT }, +}; + +static const struct db_table_descriptor mf_event_tab = { + .name = "memory_failure_event", + .fields = mf_event_fields, + .num_fields = ARRAY_SIZE(mf_event_fields), +}; + +int db_mf_event(struct ras_events *ras, struct ras_mf_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_mf_event) + return 0; + log(TERM, LOG_INFO, "memory_failure_event store: %p\n", priv->stmt_mf_event); + + db_bind(&mf_event_tab, priv->stmt_mf_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&mf_event_tab, priv->stmt_mf_event, pos++, (uint64_t)ev->pfn, -1); + db_bind(&mf_event_tab, priv->stmt_mf_event, pos++, (uint64_t)ev->page_type, -1); + db_bind(&mf_event_tab, priv->stmt_mf_event, pos++, (uint64_t)ev->action_result, -1); + + rc = db_eval_stmt(priv->stmt_mf_event, "mf_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +#ifdef HAVE_CXL +/* + * Table and functions to handle cxl:cxl_poison + */ +static const struct db_fields cxl_poison_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "memdev", .type = DB_TYPE_TEXT }, + { .name = "host", .type = DB_TYPE_TEXT }, + { .name = "serial", .type = DB_TYPE_INT64 }, + { .name = "trace_type", .type = DB_TYPE_TEXT }, + { .name = "region", .type = DB_TYPE_TEXT }, + { .name = "region_uuid", .type = DB_TYPE_TEXT }, + { .name = "hpa", .type = DB_TYPE_INT64 }, + { .name = "dpa", .type = DB_TYPE_INT64 }, + { .name = "dpa_length", .type = DB_TYPE_INT32 }, + { .name = "source", .type = DB_TYPE_TEXT }, + { .name = "flags", .type = DB_TYPE_INT32 }, + { .name = "overflow_ts", .type = DB_TYPE_TEXT }, + { .name = "hpa_alias0", .type = DB_TYPE_INT64}, +}; + +static const struct db_table_descriptor cxl_poison_event_tab = { + .name = "cxl_poison_event", + .fields = cxl_poison_event_fields, + .num_fields = ARRAY_SIZE(cxl_poison_event_fields), +}; + +int db_cxl_poison_event(struct ras_events *ras, struct ras_cxl_poison_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_cxl_poison_event) + return 0; + log(TERM, LOG_INFO, "cxl_poison_event store: %p\n", priv->stmt_cxl_poison_event); + + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, (uint64_t)ev->memdev, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, (uint64_t)ev->host, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, ev->serial, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, (uint64_t)ev->trace_type, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, (uint64_t)ev->region, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, (uint64_t)ev->uuid, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, ev->hpa, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, ev->dpa, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, ev->dpa_length, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, (uint64_t)ev->source, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, ev->flags, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, (uint64_t)ev->overflow_ts, -1); + db_bind(&cxl_poison_event_tab, priv->stmt_cxl_poison_event, pos++, ev->hpa_alias0, -1); + + rc = db_eval_stmt(priv->stmt_cxl_poison_event, "cxl_poison_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} + +/* + * Table and functions to handle cxl:cxl_aer_uncorrectable_error + */ +static const struct db_fields cxl_aer_ue_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "memdev", .type = DB_TYPE_TEXT }, + { .name = "host", .type = DB_TYPE_TEXT }, + { .name = "serial", .type = DB_TYPE_INT64 }, + { .name = "error_status", .type = DB_TYPE_INT32 }, + { .name = "first_error", .type = DB_TYPE_INT32 }, + { .name = "header_log", .type = DB_TYPE_BLOB }, +}; + +static const struct db_table_descriptor cxl_aer_ue_event_tab = { + .name = "cxl_aer_ue_event", + .fields = cxl_aer_ue_event_fields, + .num_fields = ARRAY_SIZE(cxl_aer_ue_event_fields), +}; + +int db_cxl_aer_ue_event(struct ras_events *ras, struct ras_cxl_aer_ue_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_cxl_aer_ue_event) + return 0; + log(TERM, LOG_INFO, "cxl_aer_ue_event store: %p\n", priv->stmt_cxl_aer_ue_event); + + db_bind(&cxl_aer_ue_event_tab, priv->stmt_cxl_aer_ue_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&cxl_aer_ue_event_tab, priv->stmt_cxl_aer_ue_event, pos++, (uint64_t)ev->memdev, -1); + db_bind(&cxl_aer_ue_event_tab, priv->stmt_cxl_aer_ue_event, pos++, (uint64_t)ev->host, -1); + db_bind(&cxl_aer_ue_event_tab, priv->stmt_cxl_aer_ue_event, pos++, ev->serial, -1); + db_bind(&cxl_aer_ue_event_tab, priv->stmt_cxl_aer_ue_event, pos++, ev->error_status, -1); + db_bind(&cxl_aer_ue_event_tab, priv->stmt_cxl_aer_ue_event, pos++, ev->first_error, -1); + db_bind(&cxl_aer_ue_event_tab, priv->stmt_cxl_aer_ue_event, pos++, (uint64_t)ev->header_log, CXL_HEADERLOG_SIZE); + + rc = db_eval_stmt(priv->stmt_cxl_aer_ue_event, "cxl_aer_ue_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} + +/* + * Table and functions to handle cxl:cxl_aer_correctable_error + */ +static const struct db_fields cxl_aer_ce_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "memdev", .type = DB_TYPE_TEXT }, + { .name = "host", .type = DB_TYPE_TEXT }, + { .name = "serial", .type = DB_TYPE_INT64 }, + { .name = "error_status", .type = DB_TYPE_INT32 }, +}; + +static const struct db_table_descriptor cxl_aer_ce_event_tab = { + .name = "cxl_aer_ce_event", + .fields = cxl_aer_ce_event_fields, + .num_fields = ARRAY_SIZE(cxl_aer_ce_event_fields), +}; + +int db_cxl_aer_ce_event(struct ras_events *ras, struct ras_cxl_aer_ce_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_cxl_aer_ce_event) + return 0; + log(TERM, LOG_INFO, "cxl_aer_ce_event store: %p\n", priv->stmt_cxl_aer_ce_event); + + db_bind(&cxl_aer_ce_event_tab, priv->stmt_cxl_aer_ce_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&cxl_aer_ce_event_tab, priv->stmt_cxl_aer_ce_event, pos++, (uint64_t)ev->memdev, -1); + db_bind(&cxl_aer_ce_event_tab, priv->stmt_cxl_aer_ce_event, pos++, (uint64_t)ev->host, -1); + db_bind(&cxl_aer_ce_event_tab, priv->stmt_cxl_aer_ce_event, pos++, ev->serial, -1); + db_bind(&cxl_aer_ce_event_tab, priv->stmt_cxl_aer_ce_event, pos++, ev->error_status, -1); + + rc = db_eval_stmt(priv->stmt_cxl_aer_ce_event, "cxl_aer_ce_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} + +/* + * Table and functions to handle cxl:cxl_overflow + */ +static const struct db_fields cxl_overflow_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "memdev", .type = DB_TYPE_TEXT }, + { .name = "host", .type = DB_TYPE_TEXT }, + { .name = "serial", .type = DB_TYPE_INT64 }, + { .name = "log_type", .type = DB_TYPE_TEXT }, + { .name = "count", .type = DB_TYPE_INT32 }, + { .name = "first_ts", .type = DB_TYPE_TEXT }, + { .name = "last_ts", .type = DB_TYPE_TEXT }, +}; + +static const struct db_table_descriptor cxl_overflow_event_tab = { + .name = "cxl_overflow_event", + .fields = cxl_overflow_event_fields, + .num_fields = ARRAY_SIZE(cxl_overflow_event_fields), +}; + +int db_cxl_overflow_event(struct ras_events *ras, struct ras_cxl_overflow_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int rc, pos = 1; + + if (!priv || !priv->stmt_cxl_overflow_event) + return 0; + log(TERM, LOG_INFO, "cxl_overflow_event store: %p\n", priv->stmt_cxl_overflow_event); + + db_bind(&cxl_overflow_event_tab, priv->stmt_cxl_overflow_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&cxl_overflow_event_tab, priv->stmt_cxl_overflow_event, pos++, (uint64_t)ev->memdev, -1); + db_bind(&cxl_overflow_event_tab, priv->stmt_cxl_overflow_event, pos++, (uint64_t)ev->host, -1); + db_bind(&cxl_overflow_event_tab, priv->stmt_cxl_overflow_event, pos++, ev->serial, -1); + db_bind(&cxl_overflow_event_tab, priv->stmt_cxl_overflow_event, pos++, (uint64_t)ev->log_type, -1); + db_bind(&cxl_overflow_event_tab, priv->stmt_cxl_overflow_event, pos++, ev->count, -1); + db_bind(&cxl_overflow_event_tab, priv->stmt_cxl_overflow_event, pos++, (uint64_t)ev->first_ts, -1); + db_bind(&cxl_overflow_event_tab, priv->stmt_cxl_overflow_event, pos++, (uint64_t)ev->last_ts, -1); + + rc = db_eval_stmt(priv->stmt_cxl_overflow_event, "cxl_overflow_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} + +static int db_cxl_common_hdr(const struct db_table_descriptor *db_tab, + struct ras_stmt *stmt, + struct ras_cxl_event_common_hdr *hdr) +{ + int idx = 1; + + if (!stmt || !hdr) + return -1; + + db_bind(db_tab, stmt, idx++, (uint64_t)hdr->timestamp, -1); + db_bind(db_tab, stmt, idx++, (uint64_t)hdr->memdev, -1); + db_bind(db_tab, stmt, idx++, (uint64_t)hdr->host, -1); + db_bind(db_tab, stmt, idx++, hdr->serial, -1); + db_bind(db_tab, stmt, idx++, (uint64_t)hdr->log_type, -1); + db_bind(db_tab, stmt, idx++, (uint64_t)hdr->hdr_uuid, -1); + db_bind(db_tab, stmt, idx++, hdr->hdr_flags, -1); + db_bind(db_tab, stmt, idx++, hdr->hdr_handle, -1); + db_bind(db_tab, stmt, idx++, hdr->hdr_related_handle, -1); + db_bind(db_tab, stmt, idx++, (uint64_t)hdr->hdr_timestamp, -1); + db_bind(db_tab, stmt, idx++, hdr->hdr_length, -1); + db_bind(db_tab, stmt, idx++, hdr->hdr_maint_op_class, -1); + db_bind(db_tab, stmt, idx++, hdr->hdr_maint_op_sub_class, -1); + db_bind(db_tab, stmt, idx++, hdr->hdr_ld_id, -1); + db_bind(db_tab, stmt, idx++, hdr->hdr_head_id, -1); + + return idx; +} + +/* + * Table and functions to handle cxl:cxl_generic_event + */ +static const struct db_fields cxl_generic_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "memdev", .type = DB_TYPE_TEXT }, + { .name = "host", .type = DB_TYPE_TEXT }, + { .name = "serial", .type = DB_TYPE_INT64 }, + { .name = "log_type", .type = DB_TYPE_TEXT }, + { .name = "hdr_uuid", .type = DB_TYPE_TEXT }, + { .name = "hdr_flags", .type = DB_TYPE_INT32 }, + { .name = "hdr_handle", .type = DB_TYPE_INT32 }, + { .name = "hdr_related_handle", .type = DB_TYPE_INT32 }, + { .name = "hdr_ts", .type = DB_TYPE_TEXT }, + { .name = "hdr_length", .type = DB_TYPE_INT32 }, + { .name = "hdr_maint_op_class", .type = DB_TYPE_INT32 }, + { .name = "hdr_maint_op_sub_class", .type = DB_TYPE_INT32 }, + { .name = "hdr_ld_id", .type = DB_TYPE_INT32 }, + { .name = "hdr_head_id", .type = DB_TYPE_INT32 }, + { .name = "data", .type = DB_TYPE_BLOB }, +}; + +static const struct db_table_descriptor cxl_generic_event_tab = { + .name = "cxl_generic_event", + .fields = cxl_generic_event_fields, + .num_fields = ARRAY_SIZE(cxl_generic_event_fields), +}; + +int db_cxl_generic_event(struct ras_events *ras, struct ras_cxl_generic_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int idx; + int rc; + + if (!priv || !priv->stmt_cxl_generic_event) + return -1; + log(TERM, LOG_INFO, "cxl_generic_event store: %p\n", priv->stmt_cxl_generic_event); + + idx = db_cxl_common_hdr(&cxl_generic_event_tab, + priv->stmt_cxl_generic_event, &ev->hdr); + if (idx <= 0) + return -1; + + db_bind(&cxl_generic_event_tab, priv->stmt_cxl_generic_event, + idx++, (uint64_t)ev->data, CXL_EVENT_RECORD_DATA_LENGTH); + + rc = db_eval_stmt(priv->stmt_cxl_generic_event, "cxl_generic_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} + +/* + * Table and functions to handle cxl:cxl_general_media_event + */ +static const struct db_fields cxl_general_media_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "memdev", .type = DB_TYPE_TEXT }, + { .name = "host", .type = DB_TYPE_TEXT }, + { .name = "serial", .type = DB_TYPE_INT64 }, + { .name = "log_type", .type = DB_TYPE_TEXT }, + { .name = "hdr_uuid", .type = DB_TYPE_TEXT }, + { .name = "hdr_flags", .type = DB_TYPE_INT32 }, + { .name = "hdr_handle", .type = DB_TYPE_INT32 }, + { .name = "hdr_related_handle", .type = DB_TYPE_INT32 }, + { .name = "hdr_ts", .type = DB_TYPE_TEXT }, + { .name = "hdr_length", .type = DB_TYPE_INT32 }, + { .name = "hdr_maint_op_class", .type = DB_TYPE_INT32 }, + { .name = "hdr_maint_op_sub_class", .type = DB_TYPE_INT32 }, + { .name = "hdr_ld_id", .type = DB_TYPE_INT32 }, + { .name = "hdr_head_id", .type = DB_TYPE_INT32 }, + + { .name = "dpa", .type = DB_TYPE_INT64 }, + { .name = "dpa_flags", .type = DB_TYPE_INT32 }, + { .name = "descriptor", .type = DB_TYPE_INT32 }, + { .name = "type", .type = DB_TYPE_INT32 }, + { .name = "transaction_type", .type = DB_TYPE_INT32 }, + { .name = "channel", .type = DB_TYPE_INT32 }, + { .name = "rank", .type = DB_TYPE_INT32 }, + { .name = "device", .type = DB_TYPE_INT32 }, + { .name = "comp_id", .type = DB_TYPE_BLOB }, + { .name = "hpa", .type = DB_TYPE_INT64 }, + { .name = "region", .type = DB_TYPE_TEXT }, + { .name = "region_uuid", .type = DB_TYPE_TEXT }, + { .name = "pldm_entity_id", .type = DB_TYPE_BLOB }, + { .name = "pldm_resource_id", .type = DB_TYPE_BLOB }, + { .name = "sub_type", .type = DB_TYPE_INT32 }, + { .name = "cme_threshold_ev_flags", .type = DB_TYPE_INT32 }, + { .name = "cme_count", .type = DB_TYPE_INT32 }, + { .name = "hpa_alias0", .type = DB_TYPE_INT64 }, +}; + +static const struct db_table_descriptor cxl_general_media_event_tab = { + .name = "cxl_general_media_event", + .fields = cxl_general_media_event_fields, + .num_fields = ARRAY_SIZE(cxl_general_media_event_fields), +}; + +int db_cxl_general_media_event(struct ras_events *ras, + struct ras_cxl_general_media_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int idx; + int rc; + + if (!priv || !priv->stmt_cxl_general_media_event) + return -1; + log(TERM, LOG_INFO, "cxl_general_media_event store: %p\n", + priv->stmt_cxl_general_media_event); + + idx = db_cxl_common_hdr(&cxl_general_media_event_tab, + priv->stmt_cxl_general_media_event, &ev->hdr); + if (idx <= 0) + return -1; + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->dpa, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->dpa_flags, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->descriptor, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->type, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->transaction_type, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->channel, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->rank, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->device, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, (uint64_t)ev->comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->hpa, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, (uint64_t)ev->region, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, (uint64_t)ev->region_uuid, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, (uint64_t)ev->entity_id, CXL_PLDM_ENTITY_ID_LEN); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, (uint64_t)ev->res_id, CXL_PLDM_RES_ID_LEN); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->sub_type, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->cme_threshold_ev_flags, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->cme_count, -1); + db_bind(&cxl_general_media_event_tab, priv->stmt_cxl_general_media_event, idx++, ev->hpa_alias0, -1); + + rc = db_eval_stmt(priv->stmt_cxl_general_media_event, "cxl_general_media_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} + +/* + * Table and functions to handle cxl:cxl_dram_event + */ +static const struct db_fields cxl_dram_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "memdev", .type = DB_TYPE_TEXT }, + { .name = "host", .type = DB_TYPE_TEXT }, + { .name = "serial", .type = DB_TYPE_INT64 }, + { .name = "log_type", .type = DB_TYPE_TEXT }, + { .name = "hdr_uuid", .type = DB_TYPE_TEXT }, + { .name = "hdr_flags", .type = DB_TYPE_INT32 }, + { .name = "hdr_handle", .type = DB_TYPE_INT32 }, + { .name = "hdr_related_handle", .type = DB_TYPE_INT32 }, + { .name = "hdr_ts", .type = DB_TYPE_TEXT }, + { .name = "hdr_length", .type = DB_TYPE_INT32 }, + { .name = "hdr_maint_op_class", .type = DB_TYPE_INT32 }, + { .name = "hdr_maint_op_sub_class", .type = DB_TYPE_INT32 }, + { .name = "hdr_ld_id", .type = DB_TYPE_INT32 }, + { .name = "hdr_head_id", .type = DB_TYPE_INT32 }, + + { .name = "dpa", .type = DB_TYPE_INT64 }, + { .name = "dpa_flags", .type = DB_TYPE_INT32 }, + { .name = "descriptor", .type = DB_TYPE_INT32 }, + { .name = "type", .type = DB_TYPE_INT32 }, + { .name = "transaction_type", .type = DB_TYPE_INT32 }, + { .name = "channel", .type = DB_TYPE_INT32 }, + { .name = "rank", .type = DB_TYPE_INT32 }, + { .name = "nibble_mask", .type = DB_TYPE_INT32 }, + { .name = "bank_group", .type = DB_TYPE_INT32 }, + { .name = "bank", .type = DB_TYPE_INT32 }, + { .name = "row", .type = DB_TYPE_INT32 }, + { .name = "column", .type = DB_TYPE_INT32 }, + { .name = "cor_mask", .type = DB_TYPE_BLOB }, + { .name = "hpa", .type = DB_TYPE_INT64 }, + { .name = "region", .type = DB_TYPE_TEXT }, + { .name = "region_uuid", .type = DB_TYPE_TEXT }, + { .name = "comp_id", .type = DB_TYPE_BLOB }, + { .name = "pldm_entity_id", .type = DB_TYPE_BLOB }, + { .name = "pldm_resource_id", .type = DB_TYPE_BLOB }, + { .name = "sub_type", .type = DB_TYPE_INT32 }, + { .name = "sub_channel", .type = DB_TYPE_INT32 }, + { .name = "cme_threshold_ev_flags", .type = DB_TYPE_INT32 }, + { .name = "cvme_count", .type = DB_TYPE_INT32 }, + { .name = "hpa_alias0", .type = DB_TYPE_INT64 }, +}; + +static const struct db_table_descriptor cxl_dram_event_tab = { + .name = "cxl_dram_event", + .fields = cxl_dram_event_fields, + .num_fields = ARRAY_SIZE(cxl_dram_event_fields), +}; + +int db_cxl_dram_event(struct ras_events *ras, struct ras_cxl_dram_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int idx; + int rc; + + if (!priv || !priv->stmt_cxl_dram_event) + return -1; + log(TERM, LOG_INFO, "cxl_dram_event store: %p\n", + priv->stmt_cxl_dram_event); + + idx = db_cxl_common_hdr(&cxl_dram_event_tab, + priv->stmt_cxl_dram_event, &ev->hdr); + if (idx <= 0) + return -1; + + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->dpa, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->dpa_flags, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->descriptor, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->type, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->transaction_type, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->channel, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->rank, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->nibble_mask, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->bank_group, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->bank, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->row, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->column, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, (uint64_t)ev->cor_mask, CXL_EVENT_DER_CORRECTION_MASK_SIZE); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->hpa, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, (uint64_t)ev->region, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, (uint64_t)ev->region_uuid, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, (uint64_t)ev->comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, (uint64_t)ev->entity_id, CXL_PLDM_ENTITY_ID_LEN); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, (uint64_t)ev->res_id, CXL_PLDM_RES_ID_LEN); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->sub_type, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->sub_channel, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->cme_threshold_ev_flags, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->cvme_count, -1); + db_bind(&cxl_dram_event_tab, priv->stmt_cxl_dram_event, idx++, ev->hpa_alias0, -1); + + rc = db_eval_stmt(priv->stmt_cxl_dram_event, "cxl_dram_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} + +/* + * Table and functions to handle cxl:cxl_memory_module_event + */ +static const struct db_fields cxl_memory_module_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "memdev", .type = DB_TYPE_TEXT }, + { .name = "host", .type = DB_TYPE_TEXT }, + { .name = "serial", .type = DB_TYPE_INT64 }, + { .name = "log_type", .type = DB_TYPE_TEXT }, + { .name = "hdr_uuid", .type = DB_TYPE_TEXT }, + { .name = "hdr_flags", .type = DB_TYPE_INT32 }, + { .name = "hdr_handle", .type = DB_TYPE_INT32 }, + { .name = "hdr_related_handle", .type = DB_TYPE_INT32 }, + { .name = "hdr_ts", .type = DB_TYPE_TEXT }, + { .name = "hdr_length", .type = DB_TYPE_INT32 }, + { .name = "hdr_maint_op_class", .type = DB_TYPE_INT32 }, + { .name = "hdr_maint_op_sub_class", .type = DB_TYPE_INT32 }, + { .name = "hdr_ld_id", .type = DB_TYPE_INT32 }, + { .name = "hdr_head_id", .type = DB_TYPE_INT32 }, + + { .name = "event_type", .type = DB_TYPE_INT32 }, + { .name = "health_status", .type = DB_TYPE_INT32 }, + { .name = "media_status", .type = DB_TYPE_INT32 }, + { .name = "life_used", .type = DB_TYPE_INT32 }, + { .name = "dirty_shutdown_cnt", .type = DB_TYPE_INT32 }, + { .name = "cor_vol_err_cnt", .type = DB_TYPE_INT32 }, + { .name = "cor_per_err_cnt", .type = DB_TYPE_INT32 }, + { .name = "device_temp", .type = DB_TYPE_INT32 }, + { .name = "add_status", .type = DB_TYPE_INT32 }, + { .name = "event_sub_type", .type = DB_TYPE_INT32 }, + { .name = "comp_id", .type = DB_TYPE_BLOB }, + { .name = "pldm_entity_id", .type = DB_TYPE_BLOB }, + { .name = "pldm_resource_id", .type = DB_TYPE_BLOB }, +}; + +static const struct db_table_descriptor cxl_memory_module_event_tab = { + .name = "cxl_memory_module_event", + .fields = cxl_memory_module_event_fields, + .num_fields = ARRAY_SIZE(cxl_memory_module_event_fields), +}; + +int db_cxl_memory_module_event(struct ras_events *ras, + struct ras_cxl_memory_module_event *ev) +{ + struct ras_record_priv *priv = ras->db_priv; + int idx; + int rc; + + if (!priv || !priv->stmt_cxl_memory_module_event) + return -1; + log(TERM, LOG_INFO, "cxl_memory_module_event store: %p\n", + priv->stmt_cxl_memory_module_event); + + idx = db_cxl_common_hdr(&cxl_memory_module_event_tab, + priv->stmt_cxl_memory_module_event, &ev->hdr); + if (idx <= 0) + return -1; + + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->event_type, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->health_status, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->media_status, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->life_used, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->dirty_shutdown_cnt, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->cor_vol_err_cnt, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->cor_per_err_cnt, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->device_temp, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->add_status, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, ev->event_sub_type, -1); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, (uint64_t)ev->comp_id, CXL_EVENT_GEN_MED_COMP_ID_SIZE); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, (uint64_t)ev->entity_id, CXL_PLDM_ENTITY_ID_LEN); + db_bind(&cxl_memory_module_event_tab, priv->stmt_cxl_memory_module_event, idx++, (uint64_t)ev->res_id, CXL_PLDM_RES_ID_LEN); + + rc = db_eval_stmt(priv->stmt_cxl_memory_module_event, "cxl_memory_module_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +#ifdef HAVE_SIGNAL +static const struct db_fields signal_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "sig", .type = DB_TYPE_INT32 }, + { .name = "errorno", .type = DB_TYPE_INT32 }, + { .name = "code", .type = DB_TYPE_INT32 }, + { .name = "comm", .type = DB_TYPE_TEXT }, + { .name = "pid", .type = DB_TYPE_INT32 }, + { .name = "grp", .type = DB_TYPE_INT32 }, + { .name = "res", .type = DB_TYPE_INT32 }, +}; + +static const struct db_table_descriptor signal_event_tab = { + .name = "signal_event", + .fields = signal_event_fields, + .num_fields = ARRAY_SIZE(signal_event_fields), +}; + +int db_signal_event(struct ras_events *ras, struct ras_signal_event *ev) +{ + int rc, pos = 0; + struct ras_record_priv *priv = ras->db_priv; + + if (!priv || !priv->stmt_signal_event) + return -1; + log(TERM, LOG_INFO, "signal_event store: %p\n", priv->stmt_signal_event); + + db_bind(&signal_event_tab, priv->stmt_signal_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&signal_event_tab, priv->stmt_signal_event, pos++, ev->sig, -1); + db_bind(&signal_event_tab, priv->stmt_signal_event, pos++, ev->error_no, -1); + db_bind(&signal_event_tab, priv->stmt_signal_event, pos++, ev->code, -1); + db_bind(&signal_event_tab, priv->stmt_signal_event, pos++, (uint64_t)ev->comm, -1); + db_bind(&signal_event_tab, priv->stmt_signal_event, pos++, ev->pid, -1); + db_bind(&signal_event_tab, priv->stmt_signal_event, pos++, ev->group, -1); + db_bind(&signal_event_tab, priv->stmt_signal_event, pos++, ev->result, -1); + + rc = db_eval_stmt(priv->stmt_signal_event, "signal_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +/* + * Table and functions to handle ras:reri_event + */ + +#ifdef HAVE_RERI +static const struct db_fields reri_event_fields[] = { + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "err_src_id", .type = DB_TYPE_INT32 }, + { .name = "source_type", .type = DB_TYPE_INT32 }, + { .name = "severity", .type = DB_TYPE_INT32 }, + { .name = "hart_id", .type = DB_TYPE_INT32 }, + { .name = "cluster_id", .type = DB_TYPE_INT32 }, + { .name = "status", .type = DB_TYPE_INT64 }, + { .name = "addr_info", .type = DB_TYPE_INT64 }, + { .name = "info", .type = DB_TYPE_INT64 }, + { .name = "suppl_info", .type = DB_TYPE_INT64 }, + { .name = "timestamp_val", .type = DB_TYPE_INT64 }, +}; + +static const struct db_table_descriptor reri_event_tab = { + .name = "reri_event", + .fields = reri_event_fields, + .num_fields = ARRAY_SIZE(reri_event_fields), +}; + +int db_reri_event(struct ras_events *ras, struct ras_reri_event *ev) +{ + int rc, pos = 1; + struct ras_record_priv *priv = ras->db_priv; + + if (!priv || !priv->stmt_reri_event) + return 0; + log(TERM, LOG_INFO, "reri_event store: %p\n", priv->stmt_reri_event); + + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->err_src_id, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->source_type, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->severity, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->hart_id, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->cluster_id, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->status, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->addr_info, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->info, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->suppl_info, -1); + db_bind(&reri_event_tab, priv->stmt_reri_event, pos++, ev->timestamp_val, -1); + + rc = db_eval_stmt(priv->stmt_reri_event, "reri_event"); + if (!rc) + log(TERM, LOG_INFO, "register inserted at db\n"); + + return rc; +} +#endif + +/* + * Generic code + */ + +int ras_mc_event_opendb(unsigned int cpu, struct ras_events *ras) +{ + int rc; + struct ras_record_priv *priv; + + printf("Calling %s()\n", __func__); + + rc = db_open(NULL, cpu, ras, sizeof(*priv)); + if (rc) + return -1; + + priv = ras->db_priv; + +#ifdef HAVE_AER + rc = db_create_table(ras->db, &aer_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_aer_event, + &aer_event_tab); + if (rc) + return -1; + } +#endif + +#ifdef HAVE_EXTLOG + rc = db_create_table(ras->db, &extlog_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_extlog_record, + &extlog_event_tab); + if (rc) + return -1; + } +#endif + +#ifdef HAVE_MCE + rc = db_create_table(ras->db, &mce_record_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_mce_record, + &mce_record_tab); + if (rc) + return -1; + } +#endif + +#ifdef HAVE_NON_STANDARD + rc = db_create_table(ras->db, &non_standard_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_non_standard_record, + &non_standard_event_tab); + if (rc) + return -1; + } +#endif + +#ifdef HAVE_ARM + rc = db_create_table(ras->db, &arm_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_arm_record, + &arm_event_tab); + if (rc) + return -1; + } +#endif +#ifdef HAVE_DEVLINK + rc = db_create_table(ras->db, &devlink_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_devlink_event, + &devlink_event_tab); + if (rc) + return -1; + } +#endif + +#ifdef HAVE_DISKERROR + rc = db_create_table(ras->db, &diskerror_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_diskerror_event, + &diskerror_event_tab); + if (rc) + return -1; + } +#endif + +#ifdef HAVE_MEMORY_FAILURE + rc = db_create_table(ras->db, &mf_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_mf_event, + &mf_event_tab); + if (rc) + return -1; + } +#endif + +#ifdef HAVE_CXL + rc = db_create_table(ras->db, &cxl_poison_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_cxl_poison_event, + &cxl_poison_event_tab); + if (rc) + return -1; + } + + rc = db_create_table(ras->db, &cxl_aer_ue_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_cxl_aer_ue_event, + &cxl_aer_ue_event_tab); + if (rc) + return -1; + } + + rc = db_create_table(ras->db, &cxl_aer_ce_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_cxl_aer_ce_event, + &cxl_aer_ce_event_tab); + if (rc) + return -1; + } + + rc = db_create_table(ras->db, &cxl_overflow_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_cxl_overflow_event, + &cxl_overflow_event_tab); + if (rc) + return -1; + } + + rc = db_create_table(ras->db, &cxl_generic_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_cxl_generic_event, + &cxl_generic_event_tab); + if (rc) + return -1; + } + + rc = db_create_table(ras->db, &cxl_general_media_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_cxl_general_media_event, + &cxl_general_media_event_tab); + if (rc) + return -1; + } + + rc = db_create_table(ras->db, &cxl_dram_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_cxl_dram_event, + &cxl_dram_event_tab); + if (rc) + return -1; + } + + rc = db_create_table(ras->db, &cxl_memory_module_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_cxl_memory_module_event, + &cxl_memory_module_event_tab); + if (rc) + return -1; + } +#endif + +#ifdef HAVE_SIGNAL + rc = db_create_table(ras->db, &signal_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_signal_event, + &signal_event_tab); + if (rc) + return -1; + } +#endif + +#ifdef HAVE_RERI + rc = db_create_table(ras->db, &reri_event_tab); + if (!rc) { + rc = db_prepare_insert_stmt(ras->db, &priv->stmt_reri_event, + &reri_event_tab); + if (rc) + return -1; + } +#endif + + return 0; +} + +int ras_mc_event_closedb(unsigned int cpu, struct ras_events *ras) +{ + struct ras_record_priv *priv = ras->db_priv; + struct ras_db *db; + int rc = 0; + + printf("Calling %s()\n", __func__); + + if (ras->db_ref_count <= 0) + return -1; + if (ras->db_ref_count > 1) + return db_close(cpu, ras); + + if (!priv) + return -1; + + db = ras->db; + if (!db) + return -1; + + if (db_cpu_finalize(cpu, priv->stmt_mc_event, "mc_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_aer_event, "aer_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_extlog_record, "extlog_record")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_mce_record, "mce_record")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_non_standard_record, "non_standard_record")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_arm_record, "arm_record")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_devlink_event, "devlink_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_diskerror_event, "diskerror_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_mf_event, "mf_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_cxl_poison_event, "cxl_poison_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_cxl_aer_ue_event, "cxl_aer_ue_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_cxl_aer_ce_event, "cxl_aer_ce_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_cxl_overflow_event, "cxl_overflow_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_cxl_generic_event, "cxl_generic_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_cxl_general_media_event, "cxl_general_media_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_cxl_dram_event, "cxl_dram_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_cxl_memory_module_event, "cxl_memory_module_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_signal_event, "signal_event")) + rc = -1; + + if (db_cpu_finalize(cpu, priv->stmt_reri_event, "reri_event")) + rc = -1; + + if (db_close(cpu, ras)) + rc = -1; + + return rc; +} + +#ifdef HAVE_UNITTEST +struct db_table_descriptor_list ras_record_table_descriptors(void) +{ + static const struct db_table_descriptor * const tables[] = { + &mc_event_tab, +#ifdef HAVE_AER + &aer_event_tab, +#endif +#ifdef HAVE_NON_STANDARD + &non_standard_event_tab, +#endif +#ifdef HAVE_ARM + &arm_event_tab, +#endif +#ifdef HAVE_EXTLOG + &extlog_event_tab, +#endif +#ifdef HAVE_MCE + &mce_record_tab, +#endif +#ifdef HAVE_DEVLINK + &devlink_event_tab, +#endif +#ifdef HAVE_DISKERROR + &diskerror_event_tab, +#endif +#ifdef HAVE_MEMORY_FAILURE + &mf_event_tab, +#endif +#ifdef HAVE_CXL + &cxl_poison_event_tab, + &cxl_aer_ue_event_tab, + &cxl_aer_ce_event_tab, + &cxl_overflow_event_tab, + &cxl_generic_event_tab, + &cxl_general_media_event_tab, + &cxl_dram_event_tab, + &cxl_memory_module_event_tab, +#endif +#ifdef HAVE_SIGNAL + &signal_event_tab, +#endif +#ifdef HAVE_RERI + &reri_event_tab, +#endif + }; + + return (struct db_table_descriptor_list) { + .tables = tables, + .num_tables = ARRAY_SIZE(tables), + }; +} +#endif + +#endif diff --git a/ras-record.h b/db/ras-record.h similarity index 68% rename from ras-record.h rename to db/ras-record.h index 6b6c708a..ca7d4470 100644 --- a/ras-record.h +++ b/db/ras-record.h @@ -13,9 +13,9 @@ #include #include "config.h" -#include "types.h" -extern long user_hz; +#include "db/ras-db.h" +#include "core/types.h" struct ras_events; @@ -318,145 +318,128 @@ struct ras_signal_event; struct ras_cxl_memory_sparing_event; struct ras_reri_event; -#ifdef HAVE_SQLITE3 +struct ras_record_priv { + struct ras_stmt *stmt_mc_event; + /* AER */ + struct ras_stmt *stmt_aer_event; -#include + /* MCE */ + struct ras_stmt *stmt_mce_record; -struct sqlite3_priv { - sqlite3 *db; - sqlite3_stmt *stmt_mc_event; -#ifdef HAVE_AER - sqlite3_stmt *stmt_aer_event; -#endif -#ifdef HAVE_MCE - sqlite3_stmt *stmt_mce_record; -#endif -#ifdef HAVE_EXTLOG - sqlite3_stmt *stmt_extlog_record; -#endif -#ifdef HAVE_NON_STANDARD - sqlite3_stmt *stmt_non_standard_record; -#endif -#ifdef HAVE_ARM - sqlite3_stmt *stmt_arm_record; -#endif -#ifdef HAVE_DEVLINK - sqlite3_stmt *stmt_devlink_event; -#endif -#ifdef HAVE_DISKERROR - sqlite3_stmt *stmt_diskerror_event; -#endif -#ifdef HAVE_MEMORY_FAILURE - sqlite3_stmt *stmt_mf_event; -#endif -#ifdef HAVE_CXL - sqlite3_stmt *stmt_cxl_poison_event; - sqlite3_stmt *stmt_cxl_aer_ue_event; - sqlite3_stmt *stmt_cxl_aer_ce_event; - sqlite3_stmt *stmt_cxl_overflow_event; - sqlite3_stmt *stmt_cxl_generic_event; - sqlite3_stmt *stmt_cxl_general_media_event; - sqlite3_stmt *stmt_cxl_dram_event; - sqlite3_stmt *stmt_cxl_memory_module_event; -#endif -#ifdef HAVE_SIGNAL - sqlite3_stmt *stmt_signal_event; -#endif -#ifdef HAVE_RERI - sqlite3_stmt *stmt_reri_event; -#endif -}; + /* EXTLOG */ + struct ras_stmt *stmt_extlog_record; -struct db_fields { - const char *name; - const char *type; -}; + /* NON_STANDARD */ + struct ras_stmt *stmt_non_standard_record; + + /* ARM */ + struct ras_stmt *stmt_arm_record; + + /* DEVLINK */ + struct ras_stmt *stmt_devlink_event; + + /* DISKERROR */ + struct ras_stmt *stmt_diskerror_event; -struct db_table_descriptor { - const char *name; - const struct db_fields *fields; - size_t num_fields; + /* MEMORY_FAILURE */ + struct ras_stmt *stmt_mf_event; + + /* CXL */ + struct ras_stmt *stmt_cxl_poison_event; + struct ras_stmt *stmt_cxl_aer_ue_event; + struct ras_stmt *stmt_cxl_aer_ce_event; + struct ras_stmt *stmt_cxl_overflow_event; + struct ras_stmt *stmt_cxl_generic_event; + struct ras_stmt *stmt_cxl_general_media_event; + struct ras_stmt *stmt_cxl_dram_event; + struct ras_stmt *stmt_cxl_memory_module_event; + + /* SIGNAL */ + struct ras_stmt *stmt_signal_event; + + /* RERI */ + struct ras_stmt *stmt_reri_event; }; + +#ifdef HAVE_DB int ras_mc_event_opendb(unsigned int cpu, struct ras_events *ras); int ras_mc_event_closedb(unsigned int cpu, struct ras_events *ras); -int ras_mc_add_vendor_table(struct ras_events *ras, sqlite3_stmt **stmt, - const struct db_table_descriptor *db_tab); -int ras_mc_finalize_vendor_table(sqlite3_stmt *stmt); -int ras_store_mc_event(struct ras_events *ras, struct ras_mc_event *ev); -int ras_store_aer_event(struct ras_events *ras, struct ras_aer_event *ev); -int ras_store_mce_record(struct ras_events *ras, struct mce_event *ev); -int ras_store_extlog_mem_record(struct ras_events *ras, + +int db_mc_event(struct ras_events *ras, struct ras_mc_event *ev); +int db_aer_event(struct ras_events *ras, struct ras_aer_event *ev); +int db_mce_record(struct ras_events *ras, struct mce_event *ev); +int db_extlog_mem_record(struct ras_events *ras, struct ras_extlog_event *ev); -int ras_store_non_standard_record(struct ras_events *ras, +int db_non_standard_record(struct ras_events *ras, struct ras_non_standard_event *ev); -int ras_store_arm_record(struct ras_events *ras, struct ras_arm_event *ev); -int ras_store_devlink_event(struct ras_events *ras, struct devlink_event *ev); -int ras_store_diskerror_event(struct ras_events *ras, +int db_arm_record(struct ras_events *ras, struct ras_arm_event *ev); +int db_devlink_event(struct ras_events *ras, struct devlink_event *ev); +int db_diskerror_event(struct ras_events *ras, struct diskerror_event *ev); -int ras_store_mf_event(struct ras_events *ras, struct ras_mf_event *ev); -int ras_store_cxl_poison_event(struct ras_events *ras, +int db_mf_event(struct ras_events *ras, struct ras_mf_event *ev); +int db_cxl_poison_event(struct ras_events *ras, struct ras_cxl_poison_event *ev); -int ras_store_cxl_aer_ue_event(struct ras_events *ras, +int db_cxl_aer_ue_event(struct ras_events *ras, struct ras_cxl_aer_ue_event *ev); -int ras_store_cxl_aer_ce_event(struct ras_events *ras, +int db_cxl_aer_ce_event(struct ras_events *ras, struct ras_cxl_aer_ce_event *ev); -int ras_store_cxl_overflow_event(struct ras_events *ras, +int db_cxl_overflow_event(struct ras_events *ras, struct ras_cxl_overflow_event *ev); -int ras_store_cxl_generic_event(struct ras_events *ras, +int db_cxl_generic_event(struct ras_events *ras, struct ras_cxl_generic_event *ev); -int ras_store_cxl_general_media_event(struct ras_events *ras, +int db_cxl_general_media_event(struct ras_events *ras, struct ras_cxl_general_media_event *ev); -int ras_store_cxl_dram_event(struct ras_events *ras, +int db_cxl_dram_event(struct ras_events *ras, struct ras_cxl_dram_event *ev); -int ras_store_cxl_memory_module_event(struct ras_events *ras, +int db_cxl_memory_module_event(struct ras_events *ras, struct ras_cxl_memory_module_event *ev); -int ras_store_signal_event(struct ras_events *ras, +int db_signal_event(struct ras_events *ras, struct ras_signal_event *ev); -int ras_store_reri_event(struct ras_events *ras, struct ras_reri_event *ev); +int db_reri_event(struct ras_events *ras, struct ras_reri_event *ev); #else static inline int ras_mc_event_opendb(unsigned int cpu, struct ras_events *ras) { return 0; }; static inline int ras_mc_event_closedb(unsigned int cpu, struct ras_events *ras) { return 0; }; -static inline int ras_store_mc_event(struct ras_events *ras, +static inline int db_mc_event(struct ras_events *ras, struct ras_mc_event *ev) { return 0; }; -static inline int ras_store_aer_event(struct ras_events *ras, +static inline int db_aer_event(struct ras_events *ras, struct ras_aer_event *ev) { return 0; }; -static inline int ras_store_mce_record(struct ras_events *ras, +static inline int db_mce_record(struct ras_events *ras, struct mce_event *ev) { return 0; }; -static inline int ras_store_extlog_mem_record(struct ras_events *ras, +static inline int db_extlog_mem_record(struct ras_events *ras, struct ras_extlog_event *ev) { return 0; }; -static inline int ras_store_non_standard_record(struct ras_events *ras, +static inline int db_non_standard_record(struct ras_events *ras, struct ras_non_standard_event *ev) { return 0; }; -static inline int ras_store_arm_record(struct ras_events *ras, +static inline int db_arm_record(struct ras_events *ras, struct ras_arm_event *ev) { return 0; }; -static inline int ras_store_devlink_event(struct ras_events *ras, +static inline int db_devlink_event(struct ras_events *ras, struct devlink_event *ev) { return 0; }; -static inline int ras_store_diskerror_event(struct ras_events *ras, +static inline int db_diskerror_event(struct ras_events *ras, struct diskerror_event *ev) { return 0; }; -static inline int ras_store_mf_event(struct ras_events *ras, +static inline int db_mf_event(struct ras_events *ras, struct ras_mf_event *ev) { return 0; }; -static inline int ras_store_cxl_poison_event(struct ras_events *ras, +static inline int db_cxl_poison_event(struct ras_events *ras, struct ras_cxl_poison_event *ev) { return 0; }; -static inline int ras_store_cxl_aer_ue_event(struct ras_events *ras, +static inline int db_cxl_aer_ue_event(struct ras_events *ras, struct ras_cxl_aer_ue_event *ev) { return 0; }; -static inline int ras_store_cxl_aer_ce_event(struct ras_events *ras, +static inline int db_cxl_aer_ce_event(struct ras_events *ras, struct ras_cxl_aer_ce_event *ev) { return 0; }; -static inline int ras_store_cxl_overflow_event(struct ras_events *ras, +static inline int db_cxl_overflow_event(struct ras_events *ras, struct ras_cxl_overflow_event *ev) { return 0; }; -static inline int ras_store_cxl_generic_event(struct ras_events *ras, +static inline int db_cxl_generic_event(struct ras_events *ras, struct ras_cxl_generic_event *ev) { return 0; }; -static inline int ras_store_cxl_general_media_event(struct ras_events *ras, +static inline int db_cxl_general_media_event(struct ras_events *ras, struct ras_cxl_general_media_event *ev) { return 0; }; -static inline int ras_store_cxl_dram_event(struct ras_events *ras, +static inline int db_cxl_dram_event(struct ras_events *ras, struct ras_cxl_dram_event *ev) { return 0; }; -static inline int ras_store_cxl_memory_module_event(struct ras_events *ras, +static inline int db_cxl_memory_module_event(struct ras_events *ras, struct ras_cxl_memory_module_event *ev) { return 0; }; -static inline int ras_store_signal_event(struct ras_events *ras, +static inline int db_signal_event(struct ras_events *ras, struct ras_signal_event *ev) { return 0; }; -static inline int ras_store_reri_event(struct ras_events *ras, +static inline int db_reri_event(struct ras_events *ras, struct ras_reri_event *ev) { return 0; }; #endif diff --git a/non-standard-ampere.c b/events-arch-arm/non-standard-ampere.c similarity index 76% rename from non-standard-ampere.c rename to events-arch-arm/non-standard-ampere.c index 664b8880..f0876ac7 100644 --- a/non-standard-ampere.c +++ b/events-arch-arm/non-standard-ampere.c @@ -9,11 +9,11 @@ #include #include -#include "non-standard-ampere.h" -#include "ras-logger.h" -#include "ras-non-standard-handler.h" -#include "ras-report.h" -#include "types.h" +#include "events-arch-arm/non-standard-ampere.h" +#include "core/ras-logger.h" +#include "events-arch-arm/ras-non-standard-handler.h" +#include "modules/ras-report.h" +#include "core/types.h" /*Armv8 RAS compicant Error Record(APEI and BMC Reporting) Payload Type 0*/ static const char * const disp_payload0_err_reg_name[] = { @@ -210,13 +210,17 @@ static const char * const err_bert_sub_type[] = { "PMPRO Fatal", }; -static char *sqlite3_table_list[] = { +#ifdef HAVE_DB + +static char *table_list[] = { "amp_payload0_event_tab", "amp_payload1_event_tab", "amp_payload2_event_tab", "amp_payload3_event_tab", }; +#endif + struct amp_ras_type_info { int id; const char *name; @@ -353,21 +357,21 @@ static const char *oem_subtype_name(const struct amp_ras_type_info *info, return "unknown"; } -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB /*key pair definition for ampere specific error payload type 0*/ static const struct db_fields amp_payload0_event_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "type", .type = "TEXT" }, - { .name = "subtype", .type = "TEXT" }, - { .name = "instance", .type = "INTEGER" }, - { .name = "socket_num", .type = "INTEGER" }, - { .name = "status_reg", .type = "INTEGER" }, - { .name = "addr_reg", .type = "INTEGER" }, - { .name = "misc0", .type = "INTEGER" }, - { .name = "misc1", .type = "INTEGER" }, - { .name = "misc2", .type = "INTEGER" }, - { .name = "misc3", .type = "INTEGER" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "type", .type = DB_TYPE_TEXT }, + { .name = "subtype", .type = DB_TYPE_TEXT }, + { .name = "instance", .type = DB_TYPE_INT32 }, + { .name = "socket_num", .type = DB_TYPE_INT32 }, + { .name = "status_reg", .type = DB_TYPE_INT64 }, + { .name = "addr_reg", .type = DB_TYPE_INT64 }, + { .name = "misc0", .type = DB_TYPE_INT64 }, + { .name = "misc1", .type = DB_TYPE_INT64 }, + { .name = "misc2", .type = DB_TYPE_INT64 }, + { .name = "misc3", .type = DB_TYPE_INT64 }, }; static const struct db_table_descriptor amp_payload0_event_tab = { @@ -378,22 +382,22 @@ static const struct db_table_descriptor amp_payload0_event_tab = { /*key pair definition for ampere specific error payload type 1*/ static const struct db_fields amp_payload1_event_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "type", .type = "TEXT" }, - { .name = "subtype", .type = "TEXT" }, - { .name = "instance", .type = "INTEGER" }, - { .name = "socket_num", .type = "INTEGER" }, - { .name = "uncore_err_status", .type = "INTEGER" }, - { .name = "uncore_err_mask", .type = "INTEGER" }, - { .name = "uncore_err_sev", .type = "INTEGER" }, - { .name = "core_err_status", .type = "INTEGER" }, - { .name = "core_err_mask", .type = "INTEGER" }, - { .name = "root_err_cmd", .type = "INTEGER" }, - { .name = "root_err_status", .type = "INTEGER" }, - { .name = "src_id", .type = "INTEGER" }, - { .name = "reserved1", .type = "INTEGER" }, - { .name = "reserverd2", .type = "INTEGER" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "type", .type = DB_TYPE_TEXT }, + { .name = "subtype", .type = DB_TYPE_TEXT }, + { .name = "instance", .type = DB_TYPE_INT32 }, + { .name = "socket_num", .type = DB_TYPE_INT32 }, + { .name = "uncore_err_status", .type = DB_TYPE_INT32 }, + { .name = "uncore_err_mask", .type = DB_TYPE_INT32 }, + { .name = "uncore_err_sev", .type = DB_TYPE_INT32 }, + { .name = "core_err_status", .type = DB_TYPE_INT32 }, + { .name = "core_err_mask", .type = DB_TYPE_INT32 }, + { .name = "root_err_cmd", .type = DB_TYPE_INT32 }, + { .name = "root_err_status", .type = DB_TYPE_INT32 }, + { .name = "src_id", .type = DB_TYPE_INT32 }, + { .name = "reserved1", .type = DB_TYPE_INT32 }, + { .name = "reserverd2", .type = DB_TYPE_INT64 }, }; static const struct db_table_descriptor amp_payload1_event_tab = { @@ -404,21 +408,21 @@ static const struct db_table_descriptor amp_payload1_event_tab = { /*key pair definition for ampere specific error payload type 2*/ static const struct db_fields amp_payload2_event_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "type", .type = "TEXT" }, - { .name = "subtype", .type = "TEXT" }, - { .name = "instance", .type = "INTEGER" }, - { .name = "socket_num", .type = "INTEGER" }, - { .name = "ce_report_reg", .type = "INTEGER" }, - { .name = "ce_location", .type = "INTEGER" }, - { .name = "ce_addr", .type = "INTEGER" }, - { .name = "ue_report_reg", .type = "INTEGER" }, - { .name = "ue_location", .type = "INTEGER" }, - { .name = "ue_addr", .type = "INTEGER" }, - { .name = "reserved1", .type = "INTEGER" }, - { .name = "reserved2", .type = "INTEGER" }, - { .name = "reserved2", .type = "INTEGER" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "type", .type = DB_TYPE_TEXT }, + { .name = "subtype", .type = DB_TYPE_TEXT }, + { .name = "instance", .type = DB_TYPE_INT32 }, + { .name = "socket_num", .type = DB_TYPE_INT32 }, + { .name = "ce_report_reg", .type = DB_TYPE_INT32 }, + { .name = "ce_location", .type = DB_TYPE_INT32 }, + { .name = "ce_addr", .type = DB_TYPE_INT32 }, + { .name = "ue_report_reg", .type = DB_TYPE_INT32 }, + { .name = "ue_location", .type = DB_TYPE_INT32 }, + { .name = "ue_addr", .type = DB_TYPE_INT32 }, + { .name = "reserved1", .type = DB_TYPE_INT32 }, + { .name = "reserved2", .type = DB_TYPE_INT64 }, + { .name = "reserved3", .type = DB_TYPE_INT64 }, }; static const struct db_table_descriptor amp_payload2_event_tab = { @@ -429,18 +433,18 @@ static const struct db_table_descriptor amp_payload2_event_tab = { /*key pair definition for ampere specific error payload type 3*/ static const struct db_fields amp_payload3_event_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "type", .type = "TEXT" }, - { .name = "subtype", .type = "TEXT" }, - { .name = "instance", .type = "INTEGER" }, - { .name = "socket_num", .type = "INTEGER" }, - { .name = "fw_spec_data0", .type = "INTEGER" }, - { .name = "fw_spec_data1", .type = "INTEGER" }, - { .name = "fw_spec_data2", .type = "INTEGER" }, - { .name = "fw_spec_data3", .type = "INTEGER" }, - { .name = "fw_spec_data4", .type = "INTEGER" }, - { .name = "fw_spec_data5", .type = "INTEGER" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP }, + { .name = "type", .type = DB_TYPE_TEXT }, + { .name = "subtype", .type = DB_TYPE_TEXT }, + { .name = "instance", .type = DB_TYPE_INT32 }, + { .name = "socket_num", .type = DB_TYPE_INT32 }, + { .name = "fw_spec_data0", .type = DB_TYPE_INT64 }, + { .name = "fw_spec_data1", .type = DB_TYPE_INT64 }, + { .name = "fw_spec_data2", .type = DB_TYPE_INT64 }, + { .name = "fw_spec_data3", .type = DB_TYPE_INT64 }, + { .name = "fw_spec_data4", .type = DB_TYPE_INT64 }, + { .name = "fw_spec_data5", .type = DB_TYPE_INT64 }, }; static const struct db_table_descriptor amp_payload3_event_tab = { @@ -449,228 +453,199 @@ static const struct db_table_descriptor amp_payload3_event_tab = { .num_fields = ARRAY_SIZE(amp_payload3_event_fields), }; -/*Save data with different type into sqlite3 db*/ +/* Save data with different type into DB */ static void record_amp_data(struct ras_ns_ev_decoder *ev_decoder, - enum amp_oem_data_type data_type, + enum db_field_type data_type, int id, int64_t data, const char *text) { switch (data_type) { - case AMP_OEM_DATA_TYPE_INT: - sqlite3_bind_int(ev_decoder->stmt_dec_record, id, data); - break; - case AMP_OEM_DATA_TYPE_INT64: - sqlite3_bind_int64(ev_decoder->stmt_dec_record, id, data); - break; - case AMP_OEM_DATA_TYPE_TEXT: - sqlite3_bind_text(ev_decoder->stmt_dec_record, id, - text, -1, NULL); - break; - default: - break; + case DB_TYPE_TEXT: + db_bind_type(ev_decoder->stmt_dec_record, DB_TYPE_INT64, + id, (uint64_t)text, -1); + break; + default: + db_bind_type(ev_decoder->stmt_dec_record, DB_TYPE_INT32, + id, data, -1); + break; } } -static int store_amp_err_data(struct ras_ns_ev_decoder *ev_decoder, - const char *name) -{ - int rc; - - rc = sqlite3_step(ev_decoder->stmt_dec_record); - if (rc != SQLITE_DONE) - log(TERM, LOG_ERR, - "Failed to do %s step on sqlite: error = %d\n", name, rc); - - rc = sqlite3_reset(ev_decoder->stmt_dec_record); - if (rc != SQLITE_OK) - log(TERM, LOG_ERR, - "Failed to reset %s on sqlite: error = %d\n", name, rc); - - rc = sqlite3_clear_bindings(ev_decoder->stmt_dec_record); - if (rc != SQLITE_OK && rc != SQLITE_DONE) - log(TERM, LOG_ERR, - "Failed to clear bindings %s on sqlite: error = %d\n", - name, rc); - - return rc; -} - -/*save all Ampere Specific Error Payload type 0 to sqlite3 database*/ +/* save all Ampere Specific Error Payload type 0 to database */ static void record_amp_payload0_err(struct ras_ns_ev_decoder *ev_decoder, const char *type_str, const char *subtype_str, const struct amp_payload0_type_sec *err) { if (ev_decoder) { - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_TEXT, + record_amp_data(ev_decoder, DB_TYPE_TEXT, AMP_PAYLOAD0_FIELD_TYPE, 0, type_str); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_TEXT, + record_amp_data(ev_decoder, DB_TYPE_TEXT, AMP_PAYLOAD0_FIELD_SUB_TYPE, 0, subtype_str); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD0_FIELD_INS, INSTANCE(err->instance), NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD0_FIELD_SOCKET_NUM, SOCKET_NUM(err->instance), NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD0_FIELD_STATUS_REG, err->err_status, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD0_FIELD_ADDR_REG, err->err_addr, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD0_FIELD_MISC0, err->err_misc_0, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD0_FIELD_MISC1, err->err_misc_1, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD0_FIELD_MISC2, err->err_misc_2, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD0_FIELD_MISC3, err->err_misc_3, NULL); - store_amp_err_data(ev_decoder, "amp_payload0_event_tab"); + db_eval_stmt(ev_decoder->stmt_dec_record, + "amp_payload0_event_tab"); } } -/*save all Ampere Specific Error Payload type 1 to sqlite3 database*/ +/* save all Ampere Specific Error Payload type 1 to database */ static void record_amp_payload1_err(struct ras_ns_ev_decoder *ev_decoder, const char *type_str, const char *subtype_str, const struct amp_payload1_type_sec *err) { if (ev_decoder) { - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_TEXT, + record_amp_data(ev_decoder, DB_TYPE_TEXT, AMP_PAYLOAD1_FIELD_TYPE, 0, type_str); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_TEXT, + record_amp_data(ev_decoder, DB_TYPE_TEXT, AMP_PAYLOAD1_FIELD_SUB_TYPE, 0, subtype_str); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_INS, INSTANCE(err->instance), NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_SOCKET_NUM, SOCKET_NUM(err->instance), NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_UNCORE_ERR_STATUS, err->uncore_status, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_UNCORE_ERR_MASK, err->uncore_mask, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_UNCORE_ERR_SEV, err->uncore_sev, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_CORE_ERR_STATUS, err->core_status, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_CORE_ERR_MASK, err->core_mask, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_ROOT_ERR_CMD, err->root_err_cmd, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_ROOT_ERR_STATUS, err->root_status, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_SRC_ID, err->src_id, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD1_FIELD_RESERVED1, err->reserved1, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD1_FIELD_RESERVED2, err->reserved2, NULL); - store_amp_err_data(ev_decoder, "amp_payload1_event_tab"); + db_eval_stmt(ev_decoder->stmt_dec_record, + "amp_payload1_event_tab"); } } -/*save all Ampere Specific Error Payload type 2 to sqlite3 database*/ +/* save all Ampere Specific Error Payload type 2 to database */ static void record_amp_payload2_err(struct ras_ns_ev_decoder *ev_decoder, const char *type_str, const char *subtype_str, const struct amp_payload2_type_sec *err) { if (ev_decoder) { - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_TEXT, + record_amp_data(ev_decoder, DB_TYPE_TEXT, AMP_PAYLOAD2_FIELD_TYPE, 0, type_str); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_TEXT, + record_amp_data(ev_decoder, DB_TYPE_TEXT, AMP_PAYLOAD2_FIELD_SUB_TYPE, 0, subtype_str); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD2_FIELD_INS, INSTANCE(err->instance), NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD2_FIELD_SOCKET_NUM, SOCKET_NUM(err->instance), NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD2_FIELD_CE_REPORT_REG, err->ce_register, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD2_FIELD_CE_LOACATION, err->ce_location, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD2_FIELD_CE_ADDR, err->ce_addr, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD2_FIELD_UE_REPORT_REG, err->ue_register, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD2_FIELD_UE_LOCATION, err->ue_location, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD2_FIELD_UE_ADDR, err->ue_addr, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD2_FIELD_RESERVED1, err->reserved1, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD2_FIELD_RESERVED2, err->reserved2, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD2_FIELD_RESERVED3, err->reserved3, NULL); - store_amp_err_data(ev_decoder, "amp_payload2_event_tab"); + db_eval_stmt(ev_decoder->stmt_dec_record, + "amp_payload2_event_tab"); } } -/*save all Ampere Specific Error Payload type 3 to sqlite3 database*/ +/* save all Ampere Specific Error Payload type 3 to database */ static void record_amp_payload3_err(struct ras_ns_ev_decoder *ev_decoder, const char *type_str, const char *subtype_str, const struct amp_payload3_type_sec *err) { if (ev_decoder) { - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_TEXT, + record_amp_data(ev_decoder, DB_TYPE_TEXT, AMP_PAYLOAD3_FIELD_TYPE, 0, type_str); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_TEXT, + record_amp_data(ev_decoder, DB_TYPE_TEXT, AMP_PAYLOAD3_FIELD_SUB_TYPE, 0, subtype_str); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD3_FIELD_INS, INSTANCE(err->instance), NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD3_FIELD_SOCKET_NUM, SOCKET_NUM(err->instance), NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT, + record_amp_data(ev_decoder, DB_TYPE_INT32, AMP_PAYLOAD3_FIELD_FW_SPEC_DATA0, err->fw_speci_data0, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD3_FIELD_FW_SPEC_DATA1, err->fw_speci_data1, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD3_FIELD_FW_SPEC_DATA2, err->fw_speci_data2, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD3_FIELD_FW_SPEC_DATA3, err->fw_speci_data3, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD3_FIELD_FW_SPEC_DATA4, err->fw_speci_data4, NULL); - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_INT64, + record_amp_data(ev_decoder, DB_TYPE_INT64, AMP_PAYLOAD3_FIELD_FW_SPEC_DATA5, err->fw_speci_data5, NULL); - store_amp_err_data(ev_decoder, "amp_payload3_event_tab"); + db_eval_stmt(ev_decoder->stmt_dec_record, + "amp_payload3_event_tab"); } } #else -static void record_amp_data(struct ras_ns_ev_decoder *ev_decoder, - enum amp_oem_data_type data_type, - int id, int64_t data, const char *text) -{ -} static void record_amp_payload0_err(struct ras_ns_ev_decoder *ev_decoder, const char *type_str, const char *subtype_str, @@ -696,14 +671,12 @@ static void record_amp_payload3_err(struct ras_ns_ev_decoder *ev_decoder, { } -static int store_amp_err_data(struct ras_ns_ev_decoder *ev_decoder, char *name) -{ - return 0; -} #endif -/*decode ampere specific error payload type 0, the CPU's data is save*/ -/*to sqlite by ras-arm-handler, others are saved by this function.*/ +/* + * decode ampere specific error payload type 0, the CPU's data is save + * to SQL DB by ras-arm-handler, others are saved by this function. + */ void decode_amp_payload0_err_regs(struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, const struct amp_payload0_type_sec *err) @@ -789,7 +762,7 @@ void decode_amp_payload0_err_regs(struct ras_ns_ev_decoder *ev_decoder, trace_seq_printf(s, "%s\n", buf); } -/*decode ampere specific error payload type 1 and save to sqlite db*/ +/* decode ampere specific error payload type 1 and save to database */ static void decode_amp_payload1_err_regs(struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, const struct amp_payload1_type_sec *err) @@ -873,7 +846,7 @@ static void decode_amp_payload1_err_regs(struct ras_ns_ev_decoder *ev_decoder, trace_seq_printf(s, "%s\n", buf); } -/*decode ampere specific error payload type 2 and save to sqlite db*/ +/* decode ampere specific error payload type 2 and save to database */ static void decode_amp_payload2_err_regs(struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, const struct amp_payload2_type_sec *err) @@ -958,7 +931,7 @@ static void decode_amp_payload2_err_regs(struct ras_ns_ev_decoder *ev_decoder, trace_seq_printf(s, "%s\n", buf); } -/*decode ampere specific error payload type 3 and save to sqlite db*/ +/* decode ampere specific error payload type 3 and save to database */ static void decode_amp_payload3_err_regs(struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, const struct amp_payload3_type_sec *err) @@ -1038,7 +1011,7 @@ static int decode_amp_oem_type_error(struct ras_events *ras, { int payload_type = PAYLOAD_TYPE(event->error[0]); -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB struct db_table_descriptor db_tab; int id = 0; @@ -1059,15 +1032,15 @@ static int decode_amp_oem_type_error(struct ras_events *ras, } if (!ev_decoder->stmt_dec_record) { - if (ras_mc_add_vendor_table(ras, &ev_decoder->stmt_dec_record, - &db_tab) != SQLITE_OK) { + if (db_create_table_prep_stmt(ras, &ev_decoder->stmt_dec_record, + &db_tab) != 0) { trace_seq_printf(s, "create sql %s fail\n", - sqlite3_table_list[payload_type]); + table_list[payload_type]); return -1; } } - record_amp_data(ev_decoder, AMP_OEM_DATA_TYPE_TEXT, + record_amp_data(ev_decoder, DB_TYPE_TEXT, id, 0, event->timestamp); #endif @@ -1106,3 +1079,15 @@ static void __attribute__((constructor)) amp_init(void) { register_ns_ev_decoder(amp_ns_oem_decoder); } + +#if defined(HAVE_DB) && defined(HAVE_UNITTEST) +struct db_table_descriptor_list ampere_table_descriptors(void) +{ + static const struct db_table_descriptor * const tables[] = { + &_payload0_event_tab, &_payload1_event_tab, + &_payload2_event_tab, &_payload3_event_tab, + }; + + return (struct db_table_descriptor_list) { tables, ARRAY_SIZE(tables) }; +} +#endif diff --git a/non-standard-ampere.h b/events-arch-arm/non-standard-ampere.h similarity index 97% rename from non-standard-ampere.h rename to events-arch-arm/non-standard-ampere.h index d986d48d..74280d59 100644 --- a/non-standard-ampere.h +++ b/events-arch-arm/non-standard-ampere.h @@ -9,7 +9,7 @@ #include -#include "types.h" +#include "core/types.h" struct ras_ns_ev_decoder; @@ -100,12 +100,6 @@ struct amp_payload3_type_sec { uint64_t fw_speci_data5; }; -enum amp_oem_data_type { - AMP_OEM_DATA_TYPE_INT, - AMP_OEM_DATA_TYPE_INT64, - AMP_OEM_DATA_TYPE_TEXT, -}; - enum { AMP_PAYLOAD0_FIELD_ID, AMP_PAYLOAD0_FIELD_TIMESTAMP, diff --git a/non-standard-hisi_hip08.c b/events-arch-arm/non-standard-hisi_hip08.c similarity index 87% rename from non-standard-hisi_hip08.c rename to events-arch-arm/non-standard-hisi_hip08.c index 3b8d93ce..9292d863 100644 --- a/non-standard-hisi_hip08.c +++ b/events-arch-arm/non-standard-hisi_hip08.c @@ -8,11 +8,11 @@ #include #include -#include "non-standard-hisilicon.h" -#include "ras-logger.h" -#include "ras-non-standard-handler.h" -#include "ras-report.h" -#include "types.h" +#include "events-arch-arm/non-standard-hisilicon.h" +#include "core/ras-logger.h" +#include "events-arch-arm/ras-non-standard-handler.h" +#include "modules/ras-report.h" +#include "core/types.h" /* HISI OEM error definitions */ /* HISI OEM format1 error definitions */ @@ -476,18 +476,18 @@ static const char *pcie_local_sub_module_name(uint8_t id) return "unknown"; } -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB static const struct db_fields hip08_oem_event_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "version", .type = "INTEGER" }, - { .name = "soc_id", .type = "INTEGER" }, - { .name = "socket_id", .type = "INTEGER" }, - { .name = "nimbus_id", .type = "INTEGER" }, - { .name = "module_id", .type = "TEXT" }, - { .name = "sub_module_id", .type = "TEXT" }, - { .name = "err_severity", .type = "TEXT" }, - { .name = "regs_dump", .type = "TEXT" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP}, + { .name = "version", .type = DB_TYPE_INT32 }, + { .name = "soc_id", .type = DB_TYPE_INT32 }, + { .name = "socket_id", .type = DB_TYPE_INT32 }, + { .name = "nimbus_id", .type = DB_TYPE_INT32 }, + { .name = "module_id", .type = DB_TYPE_TEXT }, + { .name = "sub_module_id", .type = DB_TYPE_TEXT }, + { .name = "err_severity", .type = DB_TYPE_TEXT }, + { .name = "regs_dump", .type = DB_TYPE_TEXT }, }; static const struct db_table_descriptor hip08_oem_type1_event_tab = { @@ -503,18 +503,18 @@ static const struct db_table_descriptor hip08_oem_type2_event_tab = { }; static const struct db_fields hip08_pcie_local_event_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "version", .type = "INTEGER" }, - { .name = "soc_id", .type = "INTEGER" }, - { .name = "socket_id", .type = "INTEGER" }, - { .name = "nimbus_id", .type = "INTEGER" }, - { .name = "sub_module_id", .type = "TEXT" }, - { .name = "core_id", .type = "INTEGER" }, - { .name = "port_id", .type = "INTEGER" }, - { .name = "err_severity", .type = "TEXT" }, - { .name = "err_type", .type = "INTEGER" }, - { .name = "regs_dump", .type = "TEXT" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP}, + { .name = "version", .type = DB_TYPE_INT32 }, + { .name = "soc_id", .type = DB_TYPE_INT32 }, + { .name = "socket_id", .type = DB_TYPE_INT32 }, + { .name = "nimbus_id", .type = DB_TYPE_INT32 }, + { .name = "sub_module_id", .type = DB_TYPE_TEXT }, + { .name = "core_id", .type = DB_TYPE_INT32 }, + { .name = "port_id", .type = DB_TYPE_INT32 }, + { .name = "err_severity", .type = DB_TYPE_TEXT }, + { .name = "err_type", .type = DB_TYPE_INT32 }, + { .name = "regs_dump", .type = DB_TYPE_TEXT }, }; static const struct db_table_descriptor hip08_pcie_local_event_tab = { @@ -534,26 +534,26 @@ static void decode_oem_type1_err_hdr(struct ras_ns_ev_decoder *ev_decoder, char *end = buf + HISI_BUF_LEN; p += snprintf(p, end - p, "[ table_version=%d ", err->version); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_OEM_TYPE1_FIELD_VERSION, err->version, NULL); if (err->val_bits & HISI_OEM_VALID_SOC_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "SOC_ID=%d ", err->soc_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_OEM_TYPE1_FIELD_SOC_ID, err->soc_id, NULL); } if (err->val_bits & HISI_OEM_VALID_SOCKET_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "socket_ID=%d ", err->socket_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_OEM_TYPE1_FIELD_SOCKET_ID, err->socket_id, NULL); } if (err->val_bits & HISI_OEM_VALID_NIMBUS_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "nimbus_ID=%d ", err->nimbus_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_OEM_TYPE1_FIELD_NIMBUS_ID, err->nimbus_id, NULL); } @@ -563,7 +563,7 @@ static void decode_oem_type1_err_hdr(struct ras_ns_ev_decoder *ev_decoder, err->module_id); p += snprintf(p, end - p, "module=%s ", str); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE1_FIELD_MODULE_ID, 0, str); } @@ -575,7 +575,7 @@ static void decode_oem_type1_err_hdr(struct ras_ns_ev_decoder *ev_decoder, err->sub_module_id); p += snprintf(p, end - p, "submodule=%s ", str); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE1_FIELD_SUB_MODULE_ID, 0, str); } @@ -584,7 +584,7 @@ static void decode_oem_type1_err_hdr(struct ras_ns_ev_decoder *ev_decoder, IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "error_severity=%s ", err_severity(err->err_severity)); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE1_FIELD_ERR_SEV, 0, err_severity(err->err_severity)); } @@ -646,17 +646,17 @@ static void decode_oem_type1_err_regs(struct ras_ns_ev_decoder *ev_decoder, *p = '\0'; } - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE1_FIELD_REGS_DUMP, 0, buf); step_vendor_data_tab(ev_decoder, "hip08_oem_type1_event_tab"); } static int add_hip08_oem_type1_table(struct ras_events *ras, struct ras_ns_ev_decoder *ev_decoder) { -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB if (ras->record_events && !ev_decoder->stmt_dec_record) { - if (ras_mc_add_vendor_table(ras, &ev_decoder->stmt_dec_record, - &hip08_oem_type1_event_tab) != SQLITE_OK) { + if (db_create_table_prep_stmt(ras, &ev_decoder->stmt_dec_record, + &hip08_oem_type1_event_tab) != 0) { log(TERM, LOG_WARNING, "Failed to create sql hip08_oem_type1_event_tab\n"); return -1; } @@ -680,7 +680,7 @@ static int decode_hip08_oem_type1_error(struct ras_events *ras, return -1; } - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE1_FIELD_TIMESTAMP, 0, event->timestamp); @@ -700,26 +700,26 @@ static void decode_oem_type2_err_hdr(struct ras_ns_ev_decoder *ev_decoder, char *end = buf + HISI_BUF_LEN; p += snprintf(p, end - p, "[ table_version=%d ", err->version); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_OEM_TYPE2_FIELD_VERSION, err->version, NULL); if (err->val_bits & HISI_OEM_VALID_SOC_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "SOC_ID=%d ", err->soc_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_OEM_TYPE2_FIELD_SOC_ID, err->soc_id, NULL); } if (err->val_bits & HISI_OEM_VALID_SOCKET_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "socket_ID=%d ", err->socket_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_OEM_TYPE2_FIELD_SOCKET_ID, err->socket_id, NULL); } if (err->val_bits & HISI_OEM_VALID_NIMBUS_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "nimbus_ID=%d ", err->nimbus_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_OEM_TYPE2_FIELD_NIMBUS_ID, err->nimbus_id, NULL); } @@ -729,7 +729,7 @@ static void decode_oem_type2_err_hdr(struct ras_ns_ev_decoder *ev_decoder, err->module_id); p += snprintf(p, end - p, "module=%s ", str); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE2_FIELD_MODULE_ID, 0, str); } @@ -741,7 +741,7 @@ static void decode_oem_type2_err_hdr(struct ras_ns_ev_decoder *ev_decoder, err->sub_module_id); p += snprintf(p, end - p, "submodule=%s ", str); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE2_FIELD_SUB_MODULE_ID, 0, str); } @@ -750,7 +750,7 @@ static void decode_oem_type2_err_hdr(struct ras_ns_ev_decoder *ev_decoder, IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "error_severity=%s ", err_severity(err->err_severity)); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE2_FIELD_ERR_SEV, 0, err_severity(err->err_severity)); } @@ -822,17 +822,17 @@ static void decode_oem_type2_err_regs(struct ras_ns_ev_decoder *ev_decoder, *p = '\0'; } - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE2_FIELD_REGS_DUMP, 0, buf); step_vendor_data_tab(ev_decoder, "hip08_oem_type2_event_tab"); } static int add_hip08_oem_type2_table(struct ras_events *ras, struct ras_ns_ev_decoder *ev_decoder) { -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB if (ras->record_events && !ev_decoder->stmt_dec_record) { - if (ras_mc_add_vendor_table(ras, &ev_decoder->stmt_dec_record, - &hip08_oem_type2_event_tab) != SQLITE_OK) { + if (db_create_table_prep_stmt(ras, &ev_decoder->stmt_dec_record, + &hip08_oem_type2_event_tab) != 0) { log(TERM, LOG_WARNING, "Failed to create sql hip08_oem_type2_event_tab\n"); return -1; } @@ -855,7 +855,7 @@ static int decode_hip08_oem_type2_error(struct ras_events *ras, return -1; } - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_OEM_TYPE2_FIELD_TIMESTAMP, 0, event->timestamp); @@ -875,14 +875,14 @@ static void decode_pcie_local_err_hdr(struct ras_ns_ev_decoder *ev_decoder, char *end = buf + HISI_BUF_LEN; p += snprintf(p, end - p, "[ table_version=%d ", err->version); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_PCIE_LOCAL_FIELD_VERSION, err->version, NULL); if (err->val_bits & HISI_PCIE_LOCAL_VALID_SOC_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "SOC_ID=%d ", err->soc_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_PCIE_LOCAL_FIELD_SOC_ID, err->soc_id, NULL); } @@ -890,7 +890,7 @@ static void decode_pcie_local_err_hdr(struct ras_ns_ev_decoder *ev_decoder, if (err->val_bits & HISI_PCIE_LOCAL_VALID_SOCKET_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "socket_ID=%d ", err->socket_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_PCIE_LOCAL_FIELD_SOCKET_ID, err->socket_id, NULL); } @@ -898,7 +898,7 @@ static void decode_pcie_local_err_hdr(struct ras_ns_ev_decoder *ev_decoder, if (err->val_bits & HISI_PCIE_LOCAL_VALID_NIMBUS_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "nimbus_ID=%d ", err->nimbus_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_PCIE_LOCAL_FIELD_NIMBUS_ID, err->nimbus_id, NULL); } @@ -907,7 +907,7 @@ static void decode_pcie_local_err_hdr(struct ras_ns_ev_decoder *ev_decoder, IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "submodule=%s ", pcie_local_sub_module_name(err->sub_module_id)); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_PCIE_LOCAL_FIELD_SUB_MODULE_ID, 0, pcie_local_sub_module_name(err->sub_module_id)); } @@ -915,7 +915,7 @@ static void decode_pcie_local_err_hdr(struct ras_ns_ev_decoder *ev_decoder, if (err->val_bits & HISI_PCIE_LOCAL_VALID_CORE_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "core_ID=core%d ", err->core_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_PCIE_LOCAL_FIELD_CORE_ID, err->core_id, NULL); } @@ -923,7 +923,7 @@ static void decode_pcie_local_err_hdr(struct ras_ns_ev_decoder *ev_decoder, if (err->val_bits & HISI_PCIE_LOCAL_VALID_PORT_ID && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "port_ID=port%d ", err->port_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_PCIE_LOCAL_FIELD_PORT_ID, err->port_id, NULL); } @@ -932,7 +932,7 @@ static void decode_pcie_local_err_hdr(struct ras_ns_ev_decoder *ev_decoder, IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "error_severity=%s ", err_severity(err->err_severity)); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_PCIE_LOCAL_FIELD_ERR_SEV, 0, err_severity(err->err_severity)); } @@ -940,7 +940,7 @@ static void decode_pcie_local_err_hdr(struct ras_ns_ev_decoder *ev_decoder, if (err->val_bits & HISI_PCIE_LOCAL_VALID_ERR_TYPE && IN_RANGE(p, buf, end)) { p += snprintf(p, end - p, "error_type=0x%x ", err->err_type); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, + record_vendor_data(ev_decoder, DB_TYPE_INT32, HIP08_PCIE_LOCAL_FIELD_ERR_TYPE, err->err_type, NULL); } @@ -976,17 +976,17 @@ static void decode_pcie_local_err_regs(struct ras_ns_ev_decoder *ev_decoder, *p = '\0'; } - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_PCIE_LOCAL_FIELD_REGS_DUMP, 0, buf); step_vendor_data_tab(ev_decoder, "hip08_pcie_local_event_tab"); } static int add_hip08_pcie_local_table(struct ras_events *ras, struct ras_ns_ev_decoder *ev_decoder) { -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB if (ras->record_events && !ev_decoder->stmt_dec_record) { - if (ras_mc_add_vendor_table(ras, &ev_decoder->stmt_dec_record, - &hip08_pcie_local_event_tab) != SQLITE_OK) { + if (db_create_table_prep_stmt(ras, &ev_decoder->stmt_dec_record, + &hip08_pcie_local_event_tab) != 0) { log(TERM, LOG_WARNING, "Failed to create sql hip08_pcie_local_event_tab\n"); return -1; } @@ -1009,7 +1009,7 @@ static int decode_hip08_pcie_local_error(struct ras_events *ras, return -1; } - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HIP08_PCIE_LOCAL_FIELD_TIMESTAMP, 0, event->timestamp); @@ -1045,3 +1045,15 @@ static void __attribute__((constructor)) hip08_init(void) for (i = 0; i < ARRAY_SIZE(hip08_ns_ev_decoder); i++) register_ns_ev_decoder(&hip08_ns_ev_decoder[i]); } + +#if defined(HAVE_DB) && defined(HAVE_UNITTEST) +struct db_table_descriptor_list hip08_table_descriptors(void) +{ + static const struct db_table_descriptor * const tables[] = { + &hip08_oem_type1_event_tab, &hip08_oem_type2_event_tab, + &hip08_pcie_local_event_tab, + }; + + return (struct db_table_descriptor_list) { tables, ARRAY_SIZE(tables) }; +} +#endif diff --git a/non-standard-hisilicon.c b/events-arch-arm/non-standard-hisilicon.c similarity index 79% rename from non-standard-hisilicon.c rename to events-arch-arm/non-standard-hisilicon.c index 78d7895a..e013dc8a 100644 --- a/non-standard-hisilicon.c +++ b/events-arch-arm/non-standard-hisilicon.c @@ -8,10 +8,10 @@ #include #include -#include "non-standard-hisilicon.h" -#include "ras-logger.h" -#include "ras-report.h" -#include "types.h" +#include "events-arch-arm/non-standard-hisilicon.h" +#include "core/ras-logger.h" +#include "modules/ras-report.h" +#include "core/types.h" #define HISI_BUF_LEN 2048 #define HISI_PCIE_INFO_BUF_LEN 256 @@ -83,55 +83,36 @@ struct hisi_event { char reg_msg[HISI_BUF_LEN]; }; -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB void record_vendor_data(struct ras_ns_ev_decoder *ev_decoder, - enum hisi_oem_data_type data_type, + enum db_field_type data_type, int id, int64_t data, const char *text) { if (!ev_decoder->stmt_dec_record) return; switch (data_type) { - case HISI_OEM_DATA_TYPE_INT: - sqlite3_bind_int(ev_decoder->stmt_dec_record, id, data); + case DB_TYPE_TEXT: + db_bind_type(ev_decoder->stmt_dec_record, DB_TYPE_INT64, + id, (uint64_t)text, -1); break; - case HISI_OEM_DATA_TYPE_INT64: - sqlite3_bind_int64(ev_decoder->stmt_dec_record, id, data); - break; - case HISI_OEM_DATA_TYPE_TEXT: - sqlite3_bind_text(ev_decoder->stmt_dec_record, id, text, -1, NULL); + default: + db_bind_type(ev_decoder->stmt_dec_record, DB_TYPE_INT32, + id, data, -1); break; } } int step_vendor_data_tab(struct ras_ns_ev_decoder *ev_decoder, const char *name) { - int rc; - if (!ev_decoder->stmt_dec_record) return 0; - rc = sqlite3_step(ev_decoder->stmt_dec_record); - if (rc != SQLITE_DONE) - log(TERM, LOG_ERR, - "Failed to do %s step on sqlite: error = %d\n", name, rc); - - rc = sqlite3_reset(ev_decoder->stmt_dec_record); - if (rc != SQLITE_OK) - log(TERM, LOG_ERR, - "Failed to reset %s on sqlite: error = %d\n", name, rc); - - rc = sqlite3_clear_bindings(ev_decoder->stmt_dec_record); - if (rc != SQLITE_OK && rc != SQLITE_DONE) - log(TERM, LOG_ERR, - "Failed to clear bindings %s on sqlite: error = %d\n", - name, rc); - - return rc; + return db_eval_stmt(ev_decoder->stmt_dec_record, name); } #else void record_vendor_data(struct ras_ns_ev_decoder *ev_decoder, - enum hisi_oem_data_type data_type, + enum db_field_type data_type, int id, int64_t data, const char *text) { } @@ -142,25 +123,25 @@ int step_vendor_data_tab(struct ras_ns_ev_decoder *ev_decoder, const char *name) #endif static const struct db_fields hisi_common_section_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "version", .type = "INTEGER" }, - { .name = "soc_id", .type = "INTEGER" }, - { .name = "socket_id", .type = "INTEGER" }, - { .name = "totem_id", .type = "INTEGER" }, - { .name = "nimbus_id", .type = "INTEGER" }, - { .name = "sub_system_id", .type = "INTEGER" }, - { .name = "module_id", .type = "TEXT" }, - { .name = "sub_module_id", .type = "INTEGER" }, - { .name = "core_id", .type = "INTEGER" }, - { .name = "port_id", .type = "INTEGER" }, - { .name = "err_type", .type = "INTEGER" }, - { .name = "pcie_info", .type = "TEXT" }, - { .name = "err_severity", .type = "TEXT" }, - { .name = "regs_dump", .type = "TEXT" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP}, + { .name = "version", .type = DB_TYPE_INT32 }, + { .name = "soc_id", .type = DB_TYPE_INT32 }, + { .name = "socket_id", .type = DB_TYPE_INT32 }, + { .name = "totem_id", .type = DB_TYPE_INT32 }, + { .name = "nimbus_id", .type = DB_TYPE_INT32 }, + { .name = "sub_system_id", .type = DB_TYPE_INT32 }, + { .name = "module_id", .type = DB_TYPE_TEXT }, + { .name = "sub_module_id", .type = DB_TYPE_INT32 }, + { .name = "core_id", .type = DB_TYPE_INT32 }, + { .name = "port_id", .type = DB_TYPE_INT32 }, + { .name = "err_type", .type = DB_TYPE_INT32 }, + { .name = "pcie_info", .type = DB_TYPE_TEXT }, + { .name = "err_severity", .type = DB_TYPE_TEXT }, + { .name = "regs_dump", .type = DB_TYPE_TEXT }, }; -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB static const struct db_table_descriptor hisi_common_section_tab = { .name = "hisi_common_section_v2", .fields = hisi_common_section_fields, @@ -243,12 +224,12 @@ static void decode_module(struct ras_ns_ev_decoder *ev_decoder, { if (module_id >= sizeof(module_name) / sizeof(char *)) { HISI_SNPRINTF(event->error_msg, "module=unknown(id=%hhu) ", module_id); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HISI_COMMON_FIELD_MODULE_ID, 0, "unknown"); } else { HISI_SNPRINTF(event->error_msg, "module=%s ", module_name[module_id]); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HISI_COMMON_FIELD_MODULE_ID, 0, module_name[module_id]); } @@ -267,7 +248,7 @@ static void decode_int_fields(struct ras_ns_ev_decoder *ev_decoder, int id, hisi_common_section_fields[id].name, data); } - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_INT, id, data, NULL); + record_vendor_data(ev_decoder, DB_TYPE_INT32, id, data, NULL); } static void decode_text_fields(struct ras_ns_ev_decoder *ev_decoder, int id, @@ -287,14 +268,14 @@ static void decode_text_fields(struct ras_ns_ev_decoder *ev_decoder, int id, HISI_SNPRINTF(event->pcie_info, "%04x:%02x:%02x.%x", err->pcie_info.segment, err->pcie_info.bus, err->pcie_info.device, err->pcie_info.function); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, id, 0, event->pcie_info); } if (id == HISI_COMMON_FIELD_ERR_SEVERITY) { HISI_SNPRINTF(event->error_msg, "err_severity=%s", err_severity(err->err_severity)); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, id, 0, err_severity(err->err_severity)); } } @@ -340,11 +321,11 @@ static void decode_hisi_common_section_hdr(struct ras_ns_ev_decoder *ev_decoder, static int add_hisi_common_table(struct ras_events *ras, struct ras_ns_ev_decoder *ev_decoder) { -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB if (ras->record_events && !ev_decoder->stmt_dec_record) { - if (ras_mc_add_vendor_table(ras, &ev_decoder->stmt_dec_record, - &hisi_common_section_tab) != SQLITE_OK) { + if (db_create_table_prep_stmt(ras, &ev_decoder->stmt_dec_record, + &hisi_common_section_tab) != 0) { log(TERM, LOG_WARNING, "Failed to create sql hisi_common_section_tab\n"); return -1; } @@ -381,10 +362,10 @@ static int decode_hisi_common_section(struct ras_events *ras, } if (ras->record_events) { - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HISI_COMMON_FIELD_TIMESTAMP, 0, event->timestamp); - record_vendor_data(ev_decoder, HISI_OEM_DATA_TYPE_TEXT, + record_vendor_data(ev_decoder, DB_TYPE_TEXT, HISI_COMMON_FIELD_REGS_DUMP, 0, hevent.reg_msg); step_vendor_data_tab(ev_decoder, "hisi_common_section_tab"); } @@ -407,3 +388,14 @@ static void __attribute__((constructor)) hisi_ns_init(void) for (i = 0; i < ARRAY_SIZE(hisi_section_ns_ev_decoder); i++) register_ns_ev_decoder(&hisi_section_ns_ev_decoder[i]); } + +#if defined(HAVE_DB) && defined(HAVE_UNITTEST) +struct db_table_descriptor_list hisilicon_table_descriptors(void) +{ + static const struct db_table_descriptor * const tables[] = { + &hisi_common_section_tab, + }; + + return (struct db_table_descriptor_list) { tables, ARRAY_SIZE(tables) }; +} +#endif diff --git a/non-standard-hisilicon.h b/events-arch-arm/non-standard-hisilicon.h similarity index 80% rename from non-standard-hisilicon.h rename to events-arch-arm/non-standard-hisilicon.h index afd5e83d..898e5027 100644 --- a/non-standard-hisilicon.h +++ b/events-arch-arm/non-standard-hisilicon.h @@ -7,8 +7,9 @@ #ifndef __NON_STANDARD_HISILICON_H #define __NON_STANDARD_HISILICON_H -#include "ras-mc-handler.h" -#include "ras-non-standard-handler.h" +#include "db/ras-record.h" +#include "core/ras-mc-handler.h" +#include "events-arch-arm/ras-non-standard-handler.h" #define HISI_SNPRINTF mce_snprintf @@ -17,12 +18,6 @@ #define HISI_ERR_SEVERITY_CE 2 #define HISI_ERR_SEVERITY_NONE 3 -enum hisi_oem_data_type { - HISI_OEM_DATA_TYPE_INT, - HISI_OEM_DATA_TYPE_INT64, - HISI_OEM_DATA_TYPE_TEXT, -}; - /* helper functions */ static inline const char *err_severity(uint8_t err_sev) { @@ -38,7 +33,7 @@ static inline const char *err_severity(uint8_t err_sev) } void record_vendor_data(struct ras_ns_ev_decoder *ev_decoder, - enum hisi_oem_data_type data_type, + enum db_field_type data_type, int id, int64_t data, const char *text); int step_vendor_data_tab(struct ras_ns_ev_decoder *ev_decoder, const char *name); diff --git a/non-standard-jaguarmicro.c b/events-arch-arm/non-standard-jaguarmicro.c similarity index 89% rename from non-standard-jaguarmicro.c rename to events-arch-arm/non-standard-jaguarmicro.c index 733eef56..7a46d9e3 100644 --- a/non-standard-jaguarmicro.c +++ b/events-arch-arm/non-standard-jaguarmicro.c @@ -4,12 +4,12 @@ * Copyright (c) 2023, JaguarMicro */ -#include "non-standard-jaguarmicro.h" -#include "ras-logger.h" -#include "ras-mce-handler.h" -#include "ras-non-standard-handler.h" -#include "ras-report.h" -#include "types.h" +#include "events-arch-arm/non-standard-jaguarmicro.h" +#include "core/ras-logger.h" +#include "events-arch-x86/ras-mce-handler.h" +#include "events-arch-arm/ras-non-standard-handler.h" +#include "modules/ras-report.h" +#include "core/types.h" #include #include @@ -20,9 +20,15 @@ #define JM_REG_BUF_LEN 2048 #define JM_SNPRINTF mce_snprintf +#ifdef HAVE_DB static void record_jm_data(struct ras_ns_ev_decoder *ev_decoder, - enum jm_oem_data_type data_type, - int id, int64_t data, const char *text); + enum db_field_type data_type, + int id, int64_t data, const char *text); +#else +static void record_jm_data(struct ras_ns_ev_decoder *ev_decoder, + enum db_field_type data_type, + int id, int64_t data, const char *text) {}; +#endif struct jm_event { char error_msg[JM_BUF_LEN]; @@ -476,14 +482,14 @@ static void decode_jm_common_sec_head(struct ras_ns_ev_decoder *ev_decoder, if (err->val_bits & BIT(JM_COMMON_VALID_SOC_ID)) { JM_SNPRINTF(event->error_msg, "table_version=%hhu decode_version:%hhu", err->version, PAYLOAD_VERSION); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_INT, + record_jm_data(ev_decoder, DB_TYPE_INT32, JM_PAYLOAD_FIELD_VERSION, err->version, NULL); } if (err->val_bits & BIT(JM_COMMON_VALID_SOC_ID)) { JM_SNPRINTF(event->error_msg, "soc=%s", get_jm_soc_desc(err->soc_id)); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_INT, + record_jm_data(ev_decoder, DB_TYPE_INT32, JM_PAYLOAD_FIELD_SOC_ID, err->soc_id, NULL); } @@ -491,7 +497,7 @@ static void decode_jm_common_sec_head(struct ras_ns_ev_decoder *ev_decoder, if (err->val_bits & BIT(JM_COMMON_VALID_SUBSYSTEM_ID)) { JM_SNPRINTF(event->error_msg, "sub system=%s", get_jm_subsystem_desc(err->subsystem_id)); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_TEXT, + record_jm_data(ev_decoder, DB_TYPE_TEXT, JM_PAYLOAD_FIELD_SUB_SYS, 0, get_jm_subsystem_desc(err->subsystem_id)); } @@ -499,10 +505,10 @@ static void decode_jm_common_sec_head(struct ras_ns_ev_decoder *ev_decoder, if (err->val_bits & BIT(JM_COMMON_VALID_MODULE_ID)) { JM_SNPRINTF(event->error_msg, "module=%s", get_jm_module_desc(err->subsystem_id, err->module_id)); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_TEXT, + record_jm_data(ev_decoder, DB_TYPE_TEXT, JM_PAYLOAD_FIELD_MODULE, 0, get_jm_module_desc(err->subsystem_id, err->module_id)); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_INT, + record_jm_data(ev_decoder, DB_TYPE_INT32, JM_PAYLOAD_FIELD_MODULE_ID, err->module_id, NULL); } @@ -511,12 +517,12 @@ static void decode_jm_common_sec_head(struct ras_ns_ev_decoder *ev_decoder, JM_SNPRINTF(event->error_msg, "sub module=%s", get_jm_submod_desc(err->subsystem_id, err->module_id, err->submodule_id)); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_TEXT, + record_jm_data(ev_decoder, DB_TYPE_TEXT, JM_PAYLOAD_FIELD_SUB_MODULE, 0, get_jm_submod_desc(err->subsystem_id, err->module_id, err->submodule_id)); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_INT, + record_jm_data(ev_decoder, DB_TYPE_INT32, JM_PAYLOAD_FIELD_MODULE_ID, err->submodule_id, NULL); } @@ -525,18 +531,18 @@ static void decode_jm_common_sec_head(struct ras_ns_ev_decoder *ev_decoder, JM_SNPRINTF(event->error_msg, "dev=%s", get_jm_dev_desc(err->subsystem_id, err->module_id, err->submodule_id)); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_TEXT, + record_jm_data(ev_decoder, DB_TYPE_TEXT, JM_PAYLOAD_FIELD_DEV, 0, get_jm_dev_desc(err->subsystem_id, err->module_id, err->submodule_id)); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_INT, + record_jm_data(ev_decoder, DB_TYPE_INT32, JM_PAYLOAD_FIELD_DEV_ID, err->dev_id, NULL); } if (err->val_bits & BIT(JM_COMMON_VALID_ERR_TYPE)) { JM_SNPRINTF(event->error_msg, "err_type=%hu", err->err_type); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_INT, + record_jm_data(ev_decoder, DB_TYPE_INT32, JM_PAYLOAD_FIELD_ERR_TYPE, err->err_type, NULL); } @@ -544,7 +550,7 @@ static void decode_jm_common_sec_head(struct ras_ns_ev_decoder *ev_decoder, if (err->val_bits & BIT(JM_COMMON_VALID_ERR_SEVERITY)) { JM_SNPRINTF(event->error_msg, "err_severity=%s", jm_err_severity(err->err_severity)); - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_TEXT, + record_jm_data(ev_decoder, DB_TYPE_TEXT, JM_PAYLOAD_FIELD_ERR_SEVERITY, 0, jm_err_severity(err->err_severity)); } @@ -569,24 +575,28 @@ static void decode_jm_common_sec_tail(struct ras_ns_ev_decoder *ev_decoder, } } -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB + +static void record_jm_data(struct ras_ns_ev_decoder *ev_decoder, + enum db_field_type data_type, + int id, int64_t data, const char *text); /*key pair definition for jaguar micro specific error payload type 0*/ static const struct db_fields jm_payload0_event_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "version", .type = "INTEGER" }, - { .name = "soc_id", .type = "INTEGER" }, - { .name = "subsystem", .type = "TEXT" }, - { .name = "module", .type = "TEXT" }, - { .name = "module_id", .type = "INTEGER" }, - { .name = "sub_module", .type = "TEXT" }, - { .name = "submodule_id", .type = "INTEGER" }, - { .name = "dev", .type = "TEXT" }, - { .name = "dev_id", .type = "INTEGER" }, - { .name = "err_type", .type = "INTEGER" }, - { .name = "err_severity", .type = "TEXT" }, - { .name = "regs_dump", .type = "TEXT" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP}, + { .name = "version", .type = DB_TYPE_INT32 }, + { .name = "soc_id", .type = DB_TYPE_INT32 }, + { .name = "subsystem", .type = DB_TYPE_TEXT }, + { .name = "module", .type = DB_TYPE_TEXT }, + { .name = "module_id", .type = DB_TYPE_INT32 }, + { .name = "sub_module", .type = DB_TYPE_TEXT }, + { .name = "submodule_id", .type = DB_TYPE_INT32 }, + { .name = "dev", .type = DB_TYPE_TEXT }, + { .name = "dev_id", .type = DB_TYPE_INT32 }, + { .name = "err_type", .type = DB_TYPE_INT32 }, + { .name = "err_severity", .type = DB_TYPE_TEXT }, + { .name = "regs_dump", .type = DB_TYPE_TEXT }, }; static const struct db_table_descriptor jm_payload0_event_tab = { @@ -595,71 +605,36 @@ static const struct db_table_descriptor jm_payload0_event_tab = { .num_fields = ARRAY_SIZE(jm_payload0_event_fields), }; -/*Save data with different type into sqlite3 db*/ +/* Save data with different type into database */ static void record_jm_data(struct ras_ns_ev_decoder *ev_decoder, - enum jm_oem_data_type data_type, int id, + enum db_field_type data_type, int id, int64_t data, const char *text) { switch (data_type) { - case JM_OEM_DATA_TYPE_INT: - sqlite3_bind_int(ev_decoder->stmt_dec_record, id, data); - break; - case JM_OEM_DATA_TYPE_INT64: - sqlite3_bind_int64(ev_decoder->stmt_dec_record, id, data); - break; - case JM_OEM_DATA_TYPE_TEXT: - sqlite3_bind_text(ev_decoder->stmt_dec_record, id, text, - -1, NULL); - break; - default: - break; + case DB_TYPE_TEXT: + db_bind_type(ev_decoder->stmt_dec_record, DB_TYPE_INT64, + id, (uint64_t)text, -1); + break; + default: + db_bind_type(ev_decoder->stmt_dec_record, DB_TYPE_INT32, + id, data, -1); + break; } } -static int store_jm_err_data(struct ras_ns_ev_decoder *ev_decoder, - const char *tab_name) -{ - int rc; - - rc = sqlite3_step(ev_decoder->stmt_dec_record); - if (rc != SQLITE_DONE) - log(TERM, LOG_ERR, - "Failed to do step on sqlite. Table = %s error = %d\n", - tab_name, rc); - - rc = sqlite3_reset(ev_decoder->stmt_dec_record); - if (rc != SQLITE_OK) - log(TERM, LOG_ERR, - "Failed to reset on sqlite. Table = %s error = %d\n", - tab_name, rc); - - rc = sqlite3_clear_bindings(ev_decoder->stmt_dec_record); - if (rc != SQLITE_OK && rc != SQLITE_DONE) - log(TERM, LOG_ERR, - "Failed to clear bindings on sqlite. Table = %s error = %d\n", - tab_name, rc); - - return rc; -} - -/*save all JaguarMicro Specific Error Payload type 0 to sqlite3 database*/ +/* save all JaguarMicro Specific Error Payload type 0 to database */ static void record_jm_payload_err(struct ras_ns_ev_decoder *ev_decoder, const char *reg_str) { if (ev_decoder) { - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_TEXT, + record_jm_data(ev_decoder, DB_TYPE_TEXT, JM_PAYLOAD_FIELD_REGS_DUMP, 0, reg_str); - store_jm_err_data(ev_decoder, "jm_payload0_event_tab"); + db_eval_stmt(ev_decoder->stmt_dec_record, + "jm_payload0_event_tab"); } } #else -static void record_jm_data(struct ras_ns_ev_decoder *ev_decoder, - enum jm_oem_data_type data_type, - int id, int64_t data, const char *text) -{ -} - static void record_jm_payload_err(struct ras_ns_ev_decoder *ev_decoder, const char *reg_str) { @@ -667,8 +642,10 @@ static void record_jm_payload_err(struct ras_ns_ev_decoder *ev_decoder, #endif -/*decode JaguarMicro specific error payload type 0, the CPU's data is save*/ -/*to sqlite by ras-arm-handler, others are saved by this function.*/ +/* + * decode JaguarMicro specific error payload type 0, the CPU's data is save + * to SQL database by ras-arm-handler, others are saved by this function. + */ static void decode_jm_payload0_err_regs(struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, const struct jm_payload0_type_sec *err) @@ -755,7 +732,7 @@ static void decode_jm_payload0_err_regs(struct ras_ns_ev_decoder *ev_decoder, trace_seq_printf(s, "%s", jmevent.reg_msg); } -/*decode JaguarMicro specific error payload type 1 and save to sqlite db*/ +/* decode JaguarMicro specific error payload type 1 and save to database */ static void decode_jm_payload1_err_regs(struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, const struct jm_payload1_type_sec *err) @@ -802,7 +779,7 @@ static void decode_jm_payload1_err_regs(struct ras_ns_ev_decoder *ev_decoder, trace_seq_printf(s, "%s", jmevent.reg_msg); } -/*decode JaguarMicro specific error payload type 2 and save to sqlite db*/ +/* decode JaguarMicro specific error payload type 2 and save to database */ static void decode_jm_payload2_err_regs(struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, const struct jm_payload2_type_sec *err) @@ -845,7 +822,7 @@ static void decode_jm_payload2_err_regs(struct ras_ns_ev_decoder *ev_decoder, trace_seq_printf(s, "%s", jmevent.reg_msg); } -/*decode JaguarMicro specific error payload type 5 and save to sqlite db*/ +/* decode JaguarMicro specific error payload type 5 and save to database */ static void decode_jm_payload5_err_regs(struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, const struct jm_payload5_type_sec *err) @@ -928,7 +905,7 @@ static void decode_jm_payload5_err_regs(struct ras_ns_ev_decoder *ev_decoder, trace_seq_printf(s, "%s", jmevent.reg_msg); } -/*decode JaguarMicro specific error payload type 6 and save to sqlite db*/ +/* decode JaguarMicro specific error payload type 6 and save to database */ static void decode_jm_payload6_err_regs(struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, const struct jm_payload6_type_sec *err) @@ -995,7 +972,7 @@ static int decode_jm_oem_type_error(struct ras_events *ras, { int id = JM_PAYLOAD_FIELD_TIMESTAMP; - record_jm_data(ev_decoder, JM_OEM_DATA_TYPE_TEXT, + record_jm_data(ev_decoder, DB_TYPE_TEXT, id, 0, event->timestamp); if (payload_type == PAYLOAD_TYPE_0) { @@ -1073,10 +1050,22 @@ static int decode_jm_oem_type6_error(struct ras_events *ras, static int add_jm_oem_type0_table(struct ras_events *ras, struct ras_ns_ev_decoder *ev_decoder) { -#ifdef HAVE_SQLITE3 + static bool started = false; + + /* + * Don't start table and prepare statement twice, as PostgreSQL + * allows to prepare statements for the same table only once. + */ + + if (started) + return 0; + + started = true; + + #ifdef HAVE_DB if (ras->record_events && !ev_decoder->stmt_dec_record) { - if (ras_mc_add_vendor_table(ras, &ev_decoder->stmt_dec_record, - &jm_payload0_event_tab) != SQLITE_OK) { + if (db_create_table_prep_stmt(ras, &ev_decoder->stmt_dec_record, + &jm_payload0_event_tab) != 0) { log(TERM, LOG_WARNING, "Failed to create sql jm_payload0_event_tab\n"); return -1; } @@ -1121,3 +1110,13 @@ static void __attribute__((constructor)) jm_init(void) register_ns_ev_decoder(&jm_ns_oem_type_decoder[i]); } +#if defined(HAVE_DB) && defined(HAVE_UNITTEST) +struct db_table_descriptor_list jaguarmicro_table_descriptors(void) +{ + static const struct db_table_descriptor * const tables[] = { + &jm_payload0_event_tab, + }; + + return (struct db_table_descriptor_list) { tables, ARRAY_SIZE(tables) }; +} +#endif diff --git a/non-standard-jaguarmicro.h b/events-arch-arm/non-standard-jaguarmicro.h similarity index 95% rename from non-standard-jaguarmicro.h rename to events-arch-arm/non-standard-jaguarmicro.h index bd2b49a5..ec580a92 100644 --- a/non-standard-jaguarmicro.h +++ b/events-arch-arm/non-standard-jaguarmicro.h @@ -9,8 +9,8 @@ #include -#include "ras-events.h" -#include "ras-mce-handler.h" +#include "core/ras-events.h" +#include "events-arch-x86/ras-mce-handler.h" #define PAYLOAD_TYPE_0 0x00 #define PAYLOAD_TYPE_1 0x01 @@ -140,12 +140,6 @@ struct jm_payload6_type_sec { struct jm_common_sec_tail common_tail; }; -enum jm_oem_data_type { - JM_OEM_DATA_TYPE_INT, - JM_OEM_DATA_TYPE_INT64, - JM_OEM_DATA_TYPE_TEXT, -}; - enum { JM_PAYLOAD_FIELD_ID, JM_PAYLOAD_FIELD_TIMESTAMP, diff --git a/non-standard-nvidia.c b/events-arch-arm/non-standard-nvidia.c similarity index 79% rename from non-standard-nvidia.c rename to events-arch-arm/non-standard-nvidia.c index cba121a6..a8ed5373 100644 --- a/non-standard-nvidia.c +++ b/events-arch-arm/non-standard-nvidia.c @@ -11,9 +11,9 @@ #include #include -#include "non-standard-nvidia.h" -#include "ras-logger.h" -#include "ras-non-standard-handler.h" +#include "events-arch-arm/non-standard-nvidia.h" +#include "core/ras-logger.h" +#include "events-arch-arm/ras-non-standard-handler.h" static void nvidia_format_timestamp(char *timestamp, size_t len) { @@ -31,9 +31,7 @@ static void nvidia_format_timestamp(char *timestamp, size_t len) snprintf(timestamp, len, "unknown"); } -#ifdef HAVE_SQLITE3 - -#include +#ifdef HAVE_DB static int nvidia_add_vendor_table(struct ras_events *ras, struct ras_ns_ev_decoder *ev_decoder, @@ -42,33 +40,15 @@ static int nvidia_add_vendor_table(struct ras_events *ras, { int rc; - rc = ras_mc_add_vendor_table(ras, &ev_decoder->stmt_dec_record, table); - if (rc != SQLITE_OK) + rc = db_create_table_prep_stmt(ras, &ev_decoder->stmt_dec_record, table); + if (rc != 0) log(TERM, LOG_ERR, "Failed to create/prepare %s table: %d\n", label, rc); return rc; } -static void nvidia_store_vendor_record(struct ras_ns_ev_decoder *ev_decoder, - const char *label) -{ - int rc; - - rc = sqlite3_step(ev_decoder->stmt_dec_record); - if (rc != SQLITE_DONE) - log(TERM, LOG_ERR, - "Failed to store %s event in database: error = %d\n", - label, rc); - - rc = sqlite3_reset(ev_decoder->stmt_dec_record); - if (rc != SQLITE_OK) - log(TERM, LOG_ERR, - "Failed to reset %s statement: error = %d\n", - label, rc); -} - -#endif /* HAVE_SQLITE3 */ +#endif /* HAVE_DB */ static const char * const nvidia_reg_names[] = { [NVIDIA_FIELD_SIGNATURE] = "Signature:", @@ -525,20 +505,20 @@ static int nvidia_decode_vera_cper_sec(const void *buf, size_t len, return 0; } -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB static const struct db_fields nvidia_ns_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "signature", .type = "TEXT" }, - { .name = "error_type", .type = "INTEGER" }, - { .name = "error_instance", .type = "INTEGER" }, - { .name = "severity", .type = "INTEGER" }, - { .name = "socket", .type = "INTEGER" }, - { .name = "number_regs", .type = "INTEGER" }, - { .name = "instance_base", .type = "INTEGER" }, - { .name = "reg_data", .type = "BLOB" }, - { .name = "raw_data", .type = "BLOB" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP}, + { .name = "signature", .type = DB_TYPE_TEXT }, + { .name = "error_type", .type = DB_TYPE_INT32 }, + { .name = "error_instance", .type = DB_TYPE_INT32 }, + { .name = "severity", .type = DB_TYPE_INT32 }, + { .name = "socket", .type = DB_TYPE_INT32 }, + { .name = "number_regs", .type = DB_TYPE_INT32 }, + { .name = "instance_base", .type = DB_TYPE_INT64 }, + { .name = "reg_data", .type = DB_TYPE_BLOB }, + { .name = "raw_data", .type = DB_TYPE_BLOB }, }; static const struct db_table_descriptor nvidia_ns_table = { @@ -560,8 +540,9 @@ static int nvidia_ns_decode(struct ras_events *ras, struct ras_non_standard_event *event) { const struct nvidia_cper_sec *err; - char timestamp[64]; uint32_t reg_data_len; + char timestamp[64]; + int pos = 1; if (event->length < sizeof(struct nvidia_cper_sec)) { trace_seq_printf(s, "NVIDIA CPER section too small: %u bytes\n", @@ -578,47 +559,44 @@ static int nvidia_ns_decode(struct ras_events *ras, if (ev_decoder->stmt_dec_record) { reg_data_len = event->length - sizeof(struct nvidia_cper_sec); - sqlite3_bind_text(ev_decoder->stmt_dec_record, 1, timestamp, -1, SQLITE_TRANSIENT); - sqlite3_bind_text(ev_decoder->stmt_dec_record, 2, err->signature, sizeof(err->signature), SQLITE_TRANSIENT); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 3, err->error_type); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 4, err->error_instance); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 5, err->severity); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 6, err->socket); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 7, err->number_regs); - sqlite3_bind_int64(ev_decoder->stmt_dec_record, 8, err->instance_base); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)timestamp, -1); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)err->signature, sizeof(err->signature)); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, err->error_type, -1); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, err->error_instance, -1); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, err->severity, -1); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, err->socket, -1); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, err->number_regs, -1); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, err->instance_base, -1); if (reg_data_len > 0) { const uint8_t *reg_data = (const uint8_t *)err + sizeof(struct nvidia_cper_sec); - sqlite3_bind_blob(ev_decoder->stmt_dec_record, 9, - reg_data, reg_data_len, SQLITE_TRANSIENT); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)reg_data, reg_data_len); } else { - sqlite3_bind_null(ev_decoder->stmt_dec_record, 9); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)NULL, -1); } - sqlite3_bind_blob(ev_decoder->stmt_dec_record, 10, - event->error, event->length, SQLITE_TRANSIENT); - - nvidia_store_vendor_record(ev_decoder, "NVIDIA"); + db_bind(&nvidia_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)event->error, event->length); + db_eval_stmt(ev_decoder->stmt_dec_record, "NVIDIA"); } return 0; } static const struct db_fields nvidia_vera_ns_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "signature", .type = "TEXT" }, - { .name = "event_type", .type = "INTEGER" }, - { .name = "event_sub_type", .type = "INTEGER" }, - { .name = "event_link_id", .type = "INTEGER" }, - { .name = "source_device_type", .type = "INTEGER" }, - { .name = "event_context_count", .type = "INTEGER" }, - { .name = "socket", .type = "INTEGER" }, - { .name = "architecture", .type = "INTEGER" }, - { .name = "chip_serial_number", .type = "BLOB" }, - { .name = "instance_base", .type = "INTEGER" }, - { .name = "raw_data", .type = "BLOB" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP}, + { .name = "signature", .type = DB_TYPE_TEXT }, + { .name = "event_type", .type = DB_TYPE_INT32 }, + { .name = "event_sub_type", .type = DB_TYPE_INT32 }, + { .name = "event_link_id", .type = DB_TYPE_INT64 }, + { .name = "source_device_type", .type = DB_TYPE_INT32 }, + { .name = "event_context_count", .type = DB_TYPE_INT32 }, + { .name = "socket", .type = DB_TYPE_INT32 }, + { .name = "architecture", .type = DB_TYPE_INT64 }, + { .name = "chip_serial_number", .type = DB_TYPE_BLOB }, + { .name = "instance_base", .type = DB_TYPE_INT64 }, + { .name = "raw_data", .type = DB_TYPE_BLOB }, }; static const struct db_table_descriptor nvidia_vera_ns_table = { @@ -641,7 +619,7 @@ static int nvidia_vera_ns_decode(struct ras_events *ras, { struct nvidia_vera_decoded decoded; char timestamp[64]; - int rc; + int rc, pos = 1; unsigned int i; if (event->length < sizeof(struct nvidia_vera_event_sec) + @@ -683,34 +661,30 @@ static int nvidia_vera_ns_decode(struct ras_events *ras, nvidia_vera_print_context(s, &decoded.contexts[i], i); if (ev_decoder->stmt_dec_record) { - sqlite3_bind_text(ev_decoder->stmt_dec_record, 1, timestamp, -1, SQLITE_TRANSIENT); - sqlite3_bind_text(ev_decoder->stmt_dec_record, 2, decoded.signature, - sizeof(decoded.signature) - 1, SQLITE_TRANSIENT); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 3, decoded.event_type); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 4, decoded.event_sub_type); - sqlite3_bind_int64(ev_decoder->stmt_dec_record, 5, decoded.event_link_id); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 6, decoded.source_device_type); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 7, decoded.event_context_count); - sqlite3_bind_int(ev_decoder->stmt_dec_record, 8, decoded.socket); - sqlite3_bind_int64(ev_decoder->stmt_dec_record, 9, decoded.architecture); - sqlite3_bind_blob(ev_decoder->stmt_dec_record, 10, - decoded.chip_serial_number, - sizeof(decoded.chip_serial_number), SQLITE_TRANSIENT); - sqlite3_bind_int64(ev_decoder->stmt_dec_record, 11, decoded.instance_base); - sqlite3_bind_blob(ev_decoder->stmt_dec_record, 12, - event->error, event->length, SQLITE_TRANSIENT); - - nvidia_store_vendor_record(ev_decoder, "NVIDIA Vera"); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)timestamp, -1); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.signature, sizeof(decoded.signature) - 1); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.event_type, 4); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.event_sub_type, 4); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.event_link_id, 4); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.source_device_type, 4); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.event_context_count, 4); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.socket, 4); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.architecture, 4); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.chip_serial_number, sizeof(decoded.chip_serial_number)); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)decoded.instance_base, 4); + db_bind(&nvidia_vera_ns_table, ev_decoder->stmt_dec_record, pos++, (uint64_t)event->error, event->length); + + db_eval_stmt(ev_decoder->stmt_dec_record, "NVIDIA Vera"); } return 0; } -#endif /* HAVE_SQLITE3 */ +#endif /* HAVE_DB */ struct ras_ns_ev_decoder nvidia_ns_ev_decoder = { .sec_type = NVIDIA_GRACE_SEC_TYPE_UUID, -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB .add_table = nvidia_ns_add_table, .decode = nvidia_ns_decode, #endif @@ -718,7 +692,7 @@ struct ras_ns_ev_decoder nvidia_ns_ev_decoder = { static struct ras_ns_ev_decoder nvidia_vera_ns_ev_decoder = { .sec_type = NVIDIA_VERA_SEC_TYPE_UUID, -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB .add_table = nvidia_vera_ns_add_table, .decode = nvidia_vera_ns_decode, #endif @@ -729,3 +703,14 @@ static void __attribute__((constructor)) nvidia_init(void) register_ns_ev_decoder(&nvidia_ns_ev_decoder); register_ns_ev_decoder(&nvidia_vera_ns_ev_decoder); } + +#if defined(HAVE_DB) && defined(HAVE_UNITTEST) +struct db_table_descriptor_list nvidia_table_descriptors(void) +{ + static const struct db_table_descriptor * const tables[] = { + &nvidia_ns_table, &nvidia_vera_ns_table, + }; + + return (struct db_table_descriptor_list) { tables, ARRAY_SIZE(tables) }; +} +#endif diff --git a/non-standard-nvidia.h b/events-arch-arm/non-standard-nvidia.h similarity index 98% rename from non-standard-nvidia.h rename to events-arch-arm/non-standard-nvidia.h index 47456f94..c7e3dff5 100644 --- a/non-standard-nvidia.h +++ b/events-arch-arm/non-standard-nvidia.h @@ -9,7 +9,7 @@ #include -#include "types.h" +#include "core/types.h" struct ras_ns_ev_decoder; diff --git a/non-standard-yitian.c b/events-arch-arm/non-standard-yitian.c similarity index 78% rename from non-standard-yitian.c rename to events-arch-arm/non-standard-yitian.c index d5100947..ca7cc710 100644 --- a/non-standard-yitian.c +++ b/events-arch-arm/non-standard-yitian.c @@ -9,11 +9,11 @@ #include #include -#include "non-standard-yitian.h" -#include "ras-logger.h" -#include "ras-non-standard-handler.h" -#include "ras-report.h" -#include "types.h" +#include "events-arch-arm/non-standard-yitian.h" +#include "core/ras-logger.h" +#include "events-arch-arm/ras-non-standard-handler.h" +#include "modules/ras-report.h" +#include "core/types.h" static const char * const yitian_ddr_payload_err_reg_name[] = { "Error Type:", @@ -68,12 +68,12 @@ static const struct yitian_ras_type_info yitian_payload_error_type[] = { } }; -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB static const struct db_fields yitian_ddr_payload_fields[] = { - { .name = "id", .type = "INTEGER PRIMARY KEY" }, - { .name = "timestamp", .type = "TEXT" }, - { .name = "address", .type = "INTEGER" }, - { .name = "regs_dump", .type = "TEXT" }, + { .name = "id", .type = DB_TYPE_SERIAL, .is_pk = true }, + { .name = "timestamp", .type = DB_TYPE_TIMESTAMP}, + { .name = "address", .type = DB_TYPE_INT64 }, + { .name = "regs_dump", .type = DB_TYPE_TEXT }, }; static const struct db_table_descriptor yitian_ddr_payload_section_tab = { @@ -85,26 +85,16 @@ static const struct db_table_descriptor yitian_ddr_payload_section_tab = { int record_yitian_ddr_reg_dump_event(struct ras_ns_ev_decoder *ev_decoder, struct ras_yitian_ddr_payload_event *ev) { - int rc; - struct sqlite3_stmt *stmt = ev_decoder->stmt_dec_record; - - log(TERM, LOG_INFO, "yitian_ddr_reg_dump_event store: %p\n", stmt); - - sqlite3_bind_text(stmt, 1, ev->timestamp, -1, NULL); - sqlite3_bind_int64(stmt, 2, ev->address); - sqlite3_bind_text(stmt, 3, ev->reg_msg, -1, NULL); - - rc = sqlite3_step(stmt); - if (rc != SQLITE_DONE) - log(TERM, LOG_ERR, - "Failed to do yitian_ddr_reg_dump_event step on sqlite: error = %d\n", rc); - rc = sqlite3_reset(stmt); - if (rc != SQLITE_OK) - log(TERM, LOG_ERR, - "Failed reset yitian_ddr_reg_dump_event on sqlite: error = %d\n", rc); - log(TERM, LOG_INFO, "register inserted at db\n"); - - return rc; + int pos = 1; + + log(TERM, LOG_INFO, "yitian_ddr_reg_dump_event store: %p\n", + ev_decoder->stmt_dec_record); + + db_bind(&yitian_ddr_payload_section_tab, ev_decoder->stmt_dec_record, pos++, (uint64_t)ev->timestamp, -1); + db_bind(&yitian_ddr_payload_section_tab, ev_decoder->stmt_dec_record, pos++, ev->address, -1); + db_bind(&yitian_ddr_payload_section_tab, ev_decoder->stmt_dec_record, pos++, (uint64_t)ev->reg_msg, -1); + + return db_eval_stmt(ev_decoder->stmt_dec_record, "yitian_ddr_reg_dump_event"); } #endif @@ -198,7 +188,7 @@ void decode_yitian_ddr_payload_err_regs(struct ras_ns_ev_decoder *ev_decoder, end = NULL; trace_seq_printf(s, "%s\n", buf); -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB record_yitian_ddr_reg_dump_event(ev_decoder, &ev); #endif } @@ -206,10 +196,10 @@ void decode_yitian_ddr_payload_err_regs(struct ras_ns_ev_decoder *ev_decoder, static int add_yitian_common_table(struct ras_events *ras, struct ras_ns_ev_decoder *ev_decoder) { -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB if (ras->record_events && !ev_decoder->stmt_dec_record) { - if (ras_mc_add_vendor_table(ras, &ev_decoder->stmt_dec_record, - &yitian_ddr_payload_section_tab) != SQLITE_OK) { + if (db_create_table_prep_stmt(ras, &ev_decoder->stmt_dec_record, + &yitian_ddr_payload_section_tab) != 0) { log(TERM, LOG_WARNING, "Failed to create sql yitian_ddr_payload_section_tab\n"); return -1; @@ -253,3 +243,14 @@ static void __attribute__((constructor)) yitian_ns_init(void) for (i = 0; i < ARRAY_SIZE(yitian_ns_oem_decoder); i++) register_ns_ev_decoder(&yitian_ns_oem_decoder[i]); } + +#if defined(HAVE_DB) && defined(HAVE_UNITTEST) +struct db_table_descriptor_list yitian_table_descriptors(void) +{ + static const struct db_table_descriptor * const tables[] = { + &yitian_ddr_payload_section_tab, + }; + + return (struct db_table_descriptor_list) { tables, ARRAY_SIZE(tables) }; +} +#endif diff --git a/non-standard-yitian.h b/events-arch-arm/non-standard-yitian.h similarity index 98% rename from non-standard-yitian.h rename to events-arch-arm/non-standard-yitian.h index 082935a8..834ac975 100644 --- a/non-standard-yitian.h +++ b/events-arch-arm/non-standard-yitian.h @@ -7,7 +7,7 @@ #ifndef __NON_STANDARD_YITIAN_H #define __NON_STANDARD_YITIAN_H -#include "ras-events.h" +#include "core/ras-events.h" #include "traceevent/event-parse.h" struct ras_ns_ev_decoder; diff --git a/ras-arm-handler.c b/events-arch-arm/ras-arm-handler.c similarity index 98% rename from ras-arm-handler.c rename to events-arch-arm/ras-arm-handler.c index 226feb38..6591768c 100644 --- a/ras-arm-handler.c +++ b/events-arch-arm/ras-arm-handler.c @@ -10,13 +10,13 @@ #include #include -#include "non-standard-ampere.h" -#include "ras-arm-handler.h" -#include "ras-cpu-isolation.h" -#include "ras-logger.h" -#include "ras-non-standard-handler.h" -#include "ras-report.h" -#include "types.h" +#include "events-arch-arm/non-standard-ampere.h" +#include "events-arch-arm/ras-arm-handler.h" +#include "modules/ras-cpu-isolation.h" +#include "core/ras-logger.h" +#include "events-arch-arm/ras-non-standard-handler.h" +#include "modules/ras-report.h" +#include "core/types.h" #define ARM_ERR_VALID_ERROR_COUNT BIT(0) #define ARM_ERR_VALID_FLAGS BIT(1) @@ -597,8 +597,8 @@ int ras_arm_event_handler(struct trace_seq *s, } /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_arm_record(ras, &ev); +#ifdef HAVE_DB + db_arm_record(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT diff --git a/ras-arm-handler.h b/events-arch-arm/ras-arm-handler.h similarity index 96% rename from ras-arm-handler.h rename to events-arch-arm/ras-arm-handler.h index a46c4970..3e905be9 100644 --- a/ras-arm-handler.h +++ b/events-arch-arm/ras-arm-handler.h @@ -9,7 +9,7 @@ #include -#include "ras-events.h" +#include "core/ras-events.h" /* * ARM Processor Error Information Structure, According to diff --git a/ras-non-standard-handler.c b/events-arch-arm/ras-non-standard-handler.c similarity index 94% rename from ras-non-standard-handler.c rename to events-arch-arm/ras-non-standard-handler.c index 8577d97c..73eeb8a2 100644 --- a/ras-non-standard-handler.c +++ b/events-arch-arm/ras-non-standard-handler.c @@ -11,10 +11,10 @@ #include #include -#include "ras-logger.h" -#include "ras-non-standard-handler.h" -#include "ras-report.h" -#include "types.h" +#include "core/ras-logger.h" +#include "events-arch-arm/ras-non-standard-handler.h" +#include "modules/ras-report.h" +#include "core/types.h" static struct ras_ns_ev_decoder *ras_ns_ev_dec_list; @@ -57,7 +57,7 @@ int register_ns_ev_decoder(struct ras_ns_ev_decoder *ns_ev_decoder) return -1; ns_ev_decoder->next = NULL; -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB ns_ev_decoder->stmt_dec_record = NULL; #endif if (!ras_ns_ev_dec_list) { @@ -78,7 +78,7 @@ int ras_ns_add_vendor_tables(struct ras_events *ras) struct ras_ns_ev_decoder *ns_ev_decoder; int error = 0; -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB if (!ras) return -1; @@ -124,7 +124,7 @@ static int find_ns_ev_decoder(const char *sec_type, struct ras_ns_ev_decoder **p void ras_ns_finalize_vendor_tables(void) { -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB struct ras_ns_ev_decoder *ns_ev_decoder = ras_ns_ev_dec_list; if (!ras_ns_ev_dec_list) @@ -139,7 +139,7 @@ void ras_ns_finalize_vendor_tables(void) while (ns_ev_decoder) { if (ns_ev_decoder->stmt_dec_record) { - ras_mc_finalize_vendor_table(ns_ev_decoder->stmt_dec_record); + db_finalize(ns_ev_decoder->stmt_dec_record); ns_ev_decoder->stmt_dec_record = NULL; } ns_ev_decoder = ns_ev_decoder->next; @@ -149,7 +149,7 @@ void ras_ns_finalize_vendor_tables(void) static void unregister_ns_ev_decoder(void) { -#ifdef HAVE_SQLITE3 +#ifdef HAVE_DB if (!ras_ns_ev_dec_list) return; ras_ns_ev_dec_list->ref_count = 1; @@ -261,8 +261,8 @@ int ras_non_standard_event_handler(struct trace_seq *s, } /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_non_standard_record(ras, &ev); +#ifdef HAVE_DB + db_non_standard_record(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT diff --git a/ras-non-standard-handler.h b/events-arch-arm/ras-non-standard-handler.h similarity index 87% rename from ras-non-standard-handler.h rename to events-arch-arm/ras-non-standard-handler.h index fbaf2aa5..589a2d15 100644 --- a/ras-non-standard-handler.h +++ b/events-arch-arm/ras-non-standard-handler.h @@ -9,12 +9,8 @@ #include -#include "ras-events.h" -#include "ras-record.h" - -#ifdef HAVE_SQLITE3 -#include -#endif +#include "core/ras-events.h" +#include "db/ras-record.h" struct ras_ns_ev_decoder { struct ras_ns_ev_decoder *next; @@ -23,8 +19,8 @@ struct ras_ns_ev_decoder { int (*add_table)(struct ras_events *ras, struct ras_ns_ev_decoder *ev_decoder); int (*decode)(struct ras_events *ras, struct ras_ns_ev_decoder *ev_decoder, struct trace_seq *s, struct ras_non_standard_event *event); -#ifdef HAVE_SQLITE3 - struct sqlite3_stmt *stmt_dec_record; +#ifdef HAVE_DB + struct ras_stmt *stmt_dec_record; #endif }; diff --git a/mce-amd-k8.c b/events-arch-x86/mce-amd-k8.c similarity index 99% rename from mce-amd-k8.c rename to events-arch-x86/mce-amd-k8.c index 37890f3b..a689c059 100644 --- a/mce-amd-k8.c +++ b/events-arch-x86/mce-amd-k8.c @@ -9,8 +9,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" #define K8_MCE_THRESHOLD_BASE (MCE_EXTENDED_BANK + 1) /* MCE_AMD */ #define K8_MCE_THRESHOLD_TOP (K8_MCE_THRESHOLD_BASE + 6 * 9) diff --git a/mce-amd-smca.c b/events-arch-x86/mce-amd-smca.c similarity index 99% rename from mce-amd-smca.c rename to events-arch-x86/mce-amd-smca.c index a024e9c3..2b3832a3 100644 --- a/mce-amd-smca.c +++ b/events-arch-x86/mce-amd-smca.c @@ -6,8 +6,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* MCA_STATUS REGISTER FOR FAMILY 17H *********************** Higher 32-bits ***************************** diff --git a/mce-amd.c b/events-arch-x86/mce-amd.c similarity index 98% rename from mce-amd.c rename to events-arch-x86/mce-amd.c index 1519d0d2..406538de 100644 --- a/mce-amd.c +++ b/events-arch-x86/mce-amd.c @@ -6,7 +6,7 @@ #include #include -#include "ras-mce-handler.h" +#include "events-arch-x86/ras-mce-handler.h" /* Error Code Types */ #define TLB_ERROR(x) (((x) & 0xFFF0) == 0x0010) diff --git a/mce-intel-broadwell-de.c b/events-arch-x86/mce-intel-broadwell-de.c similarity index 98% rename from mce-intel-broadwell-de.c rename to events-arch-x86/mce-intel-broadwell-de.c index 1d01a5b8..1b84ba6e 100644 --- a/mce-intel-broadwell-de.c +++ b/events-arch-x86/mce-intel-broadwell-de.c @@ -7,8 +7,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* See IA32 SDM Vol3B Table 16-24 */ diff --git a/mce-intel-broadwell-epex.c b/events-arch-x86/mce-intel-broadwell-epex.c similarity index 98% rename from mce-intel-broadwell-epex.c rename to events-arch-x86/mce-intel-broadwell-epex.c index c4cc89a7..2aa58e79 100644 --- a/mce-intel-broadwell-epex.c +++ b/events-arch-x86/mce-intel-broadwell-epex.c @@ -8,8 +8,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* See IA32 SDM Vol3B Table 16-20 */ diff --git a/mce-intel-diamond.c b/events-arch-x86/mce-intel-diamond.c similarity index 99% rename from mce-intel-diamond.c rename to events-arch-x86/mce-intel-diamond.c index 910c84eb..3abe841e 100644 --- a/mce-intel-diamond.c +++ b/events-arch-x86/mce-intel-diamond.c @@ -12,8 +12,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" static char *cbb_punit_0[] = { [0x01] = "CR4_MCE_CLEAR: MCE when CR4.MCE is clear", diff --git a/mce-intel-dunnington.c b/events-arch-x86/mce-intel-dunnington.c similarity index 97% rename from mce-intel-dunnington.c rename to events-arch-x86/mce-intel-dunnington.c index 915dbe48..7c076122 100644 --- a/mce-intel-dunnington.c +++ b/events-arch-x86/mce-intel-dunnington.c @@ -8,8 +8,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* Follows Intel IA32 SDM 3b Appendix E.2.1 ++ */ diff --git a/mce-intel-granite.c b/events-arch-x86/mce-intel-granite.c similarity index 99% rename from mce-intel-granite.c rename to events-arch-x86/mce-intel-granite.c index b78a7bff..18fbcfd6 100644 --- a/mce-intel-granite.c +++ b/events-arch-x86/mce-intel-granite.c @@ -13,8 +13,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" static char *upi_2[] = { [0x00] = "UC Phy Initialization Failure (NumInit)", diff --git a/mce-intel-haswell.c b/events-arch-x86/mce-intel-haswell.c similarity index 98% rename from mce-intel-haswell.c rename to events-arch-x86/mce-intel-haswell.c index f5c26126..b064b66d 100644 --- a/mce-intel-haswell.c +++ b/events-arch-x86/mce-intel-haswell.c @@ -8,8 +8,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* See IA32 SDM Vol3B Table 16-20 */ diff --git a/mce-intel-i10nm.c b/events-arch-x86/mce-intel-i10nm.c similarity index 99% rename from mce-intel-i10nm.c rename to events-arch-x86/mce-intel-i10nm.c index e692d981..f500449d 100644 --- a/mce-intel-i10nm.c +++ b/events-arch-x86/mce-intel-i10nm.c @@ -12,8 +12,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" static char *pcu_1[] = { [0x0D] = "MCA_LLC_BIST_ACTIVE_TIMEOUT", diff --git a/mce-intel-ivb.c b/events-arch-x86/mce-intel-ivb.c similarity index 97% rename from mce-intel-ivb.c rename to events-arch-x86/mce-intel-ivb.c index 2aace89f..6b431b62 100644 --- a/mce-intel-ivb.c +++ b/events-arch-x86/mce-intel-ivb.c @@ -8,8 +8,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* See IA32 SDM Vol3B Table 16-17 */ diff --git a/mce-intel-knl.c b/events-arch-x86/mce-intel-knl.c similarity index 97% rename from mce-intel-knl.c rename to events-arch-x86/mce-intel-knl.c index c6366522..52cdf1a5 100644 --- a/mce-intel-knl.c +++ b/events-arch-x86/mce-intel-knl.c @@ -3,8 +3,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" static struct field memctrl_mc7[] = { SBITFIELD(16, "CA Parity error"), diff --git a/mce-intel-nehalem.c b/events-arch-x86/mce-intel-nehalem.c similarity index 98% rename from mce-intel-nehalem.c rename to events-arch-x86/mce-intel-nehalem.c index 227feae2..6b379203 100644 --- a/mce-intel-nehalem.c +++ b/events-arch-x86/mce-intel-nehalem.c @@ -8,8 +8,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* See IA32 SDM Vol3B Appendix E.3.2 ff */ diff --git a/mce-intel-p4-p6.c b/events-arch-x86/mce-intel-p4-p6.c similarity index 98% rename from mce-intel-p4-p6.c rename to events-arch-x86/mce-intel-p4-p6.c index 277c344d..84aa0898 100644 --- a/mce-intel-p4-p6.c +++ b/events-arch-x86/mce-intel-p4-p6.c @@ -8,8 +8,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* Decode P4 and P6 family (p6old and Core2) model specific errors */ diff --git a/mce-intel-sb.c b/events-arch-x86/mce-intel-sb.c similarity index 97% rename from mce-intel-sb.c rename to events-arch-x86/mce-intel-sb.c index 2d3f260c..97ac6874 100644 --- a/mce-intel-sb.c +++ b/events-arch-x86/mce-intel-sb.c @@ -8,8 +8,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* See IA32 SDM Vol3B Table 16.4.1 */ diff --git a/mce-intel-skylake-xeon.c b/events-arch-x86/mce-intel-skylake-xeon.c similarity index 99% rename from mce-intel-skylake-xeon.c rename to events-arch-x86/mce-intel-skylake-xeon.c index 417cec20..d01dcc26 100644 --- a/mce-intel-skylake-xeon.c +++ b/events-arch-x86/mce-intel-skylake-xeon.c @@ -8,8 +8,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* See IA32 SDM Vol3B Table 16-27 */ diff --git a/mce-intel-tulsa.c b/events-arch-x86/mce-intel-tulsa.c similarity index 98% rename from mce-intel-tulsa.c rename to events-arch-x86/mce-intel-tulsa.c index cbe774a8..22f8d9b1 100644 --- a/mce-intel-tulsa.c +++ b/events-arch-x86/mce-intel-tulsa.c @@ -8,8 +8,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* See IA32 SDM Vol3B Appendix E.4.1 ff */ diff --git a/mce-intel.c b/events-arch-x86/mce-intel.c similarity index 99% rename from mce-intel.c rename to events-arch-x86/mce-intel.c index 877a6b3b..911edf24 100644 --- a/mce-intel.c +++ b/events-arch-x86/mce-intel.c @@ -15,9 +15,9 @@ #include #include -#include "bitfield.h" -#include "ras-logger.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "core/ras-logger.h" +#include "events-arch-x86/ras-mce-handler.h" #define MCE_THERMAL_BANK (MCE_EXTENDED_BANK + 0) #define MCE_TIMEOUT_BANK (MCE_EXTENDED_BANK + 90) diff --git a/mce-zhaoxin-kh50000.c b/events-arch-x86/mce-zhaoxin-kh50000.c similarity index 99% rename from mce-zhaoxin-kh50000.c rename to events-arch-x86/mce-zhaoxin-kh50000.c index d06ec37a..f8c981b3 100644 --- a/mce-zhaoxin-kh50000.c +++ b/events-arch-x86/mce-zhaoxin-kh50000.c @@ -7,8 +7,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" /* Zhaoxin KH-50000 CPU Error Bank */ #define MCE_CPU_BANK 0x0 diff --git a/mce-zhaoxin.c b/events-arch-x86/mce-zhaoxin.c similarity index 97% rename from mce-zhaoxin.c rename to events-arch-x86/mce-zhaoxin.c index 5472ff2d..5cd8ce1f 100644 --- a/mce-zhaoxin.c +++ b/events-arch-x86/mce-zhaoxin.c @@ -7,8 +7,8 @@ #include #include -#include "bitfield.h" -#include "ras-mce-handler.h" +#include "core/bitfield.h" +#include "events-arch-x86/ras-mce-handler.h" #define MCG_TES_P BIT_ULL(11) /* Yellow bit cache threshold supported */ diff --git a/ras-erst.c b/events-arch-x86/ras-erst.c similarity index 94% rename from ras-erst.c rename to events-arch-x86/ras-erst.c index c024d604..c6a08db0 100644 --- a/ras-erst.c +++ b/events-arch-x86/ras-erst.c @@ -9,12 +9,12 @@ #include #include -#include "ras-events.h" -#include "ras-erst.h" -#include "ras-logger.h" -#include "ras-mce-handler.h" -#include "ras-record.h" -#include "types.h" +#include "core/ras-events.h" +#include "events-arch-x86/ras-erst.h" +#include "core/ras-logger.h" +#include "events-arch-x86/ras-mce-handler.h" +#include "db/ras-record.h" +#include "core/types.h" struct mce { uint64_t status; /* Bank's MCi_STATUS MSR */ @@ -156,7 +156,7 @@ static void handle_erst_mce(void) dir = opendir(ERST_PATH); if (!dir) { - log(ALL, LOG_INFO, "Failed to open directory\n"); + log(ALL, LOG_INFO, "Failed to open %s directory\n", ERST_PATH); return; } diff --git a/ras-erst.h b/events-arch-x86/ras-erst.h similarity index 100% rename from ras-erst.h rename to events-arch-x86/ras-erst.h diff --git a/ras-mce-handler.c b/events-arch-x86/ras-mce-handler.c similarity index 98% rename from ras-mce-handler.c rename to events-arch-x86/ras-mce-handler.c index 0da2507a..439445d3 100644 --- a/ras-mce-handler.c +++ b/events-arch-x86/ras-mce-handler.c @@ -13,10 +13,10 @@ #include #include -#include "ras-logger.h" -#include "ras-mce-handler.h" -#include "ras-report.h" -#include "types.h" +#include "core/ras-logger.h" +#include "events-arch-x86/ras-mce-handler.h" +#include "modules/ras-report.h" +#include "core/types.h" /* * The code below were adapted from Andi Kleen/Intel/SUSE mcelog code, @@ -629,8 +629,8 @@ int ras_mce_event_handler(struct trace_seq *s, report_mce_event(ras, record, s, &e); -#ifdef HAVE_SQLITE3 - ras_store_mce_record(ras, &e); +#ifdef HAVE_DB + db_mce_record(ras, &e); #endif #ifdef HAVE_ABRT_REPORT diff --git a/ras-mce-handler.h b/events-arch-x86/ras-mce-handler.h similarity index 99% rename from ras-mce-handler.h rename to events-arch-x86/ras-mce-handler.h index 12fb11bd..4e432e4d 100644 --- a/ras-mce-handler.h +++ b/events-arch-x86/ras-mce-handler.h @@ -10,7 +10,7 @@ #include #include -#include "ras-events.h" +#include "core/ras-events.h" enum cputype { CPU_GENERIC, diff --git a/ras-cxl-handler.c b/events/ras-cxl-handler.c similarity index 98% rename from ras-cxl-handler.c rename to events/ras-cxl-handler.c index 2ed3f358..120ec6fe 100644 --- a/ras-cxl-handler.c +++ b/events/ras-cxl-handler.c @@ -11,12 +11,12 @@ #include #include -#include "ras-cxl-handler.h" -#include "ras-page-isolation.h" -#include "ras-logger.h" -#include "ras-record.h" -#include "ras-report.h" -#include "types.h" +#include "events/ras-cxl-handler.h" +#include "modules/ras-page-isolation.h" +#include "core/ras-logger.h" +#include "db/ras-record.h" +#include "modules/ras-report.h" +#include "core/types.h" /* Common Functions */ static void convert_timestamp(unsigned long long ts, char *ts_ptr, uint16_t size) @@ -257,8 +257,8 @@ int ras_cxl_poison_event_handler(struct trace_seq *s, return -1; /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_cxl_poison_event(ras, &ev); +#ifdef HAVE_DB + db_cxl_poison_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT @@ -410,7 +410,7 @@ int ras_cxl_aer_ue_event_handler(struct trace_seq *s, if (trace_seq_printf(s, "\n") <= 0) break; /* Convert header log data to the big-endian format because - * the SQLite database seems uses the big-endian storage. + * the SQL database seems uses the big-endian storage. */ ev.header_log[i] = htobe32(ev.header_log[i]); } @@ -418,8 +418,8 @@ int ras_cxl_aer_ue_event_handler(struct trace_seq *s, return -1; /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_cxl_aer_ue_event(ras, &ev); +#ifdef HAVE_DB + db_cxl_aer_ue_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT @@ -474,8 +474,8 @@ int ras_cxl_aer_ce_event_handler(struct trace_seq *s, return -1; /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_cxl_aer_ce_event(ras, &ev); +#ifdef HAVE_DB + db_cxl_aer_ce_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT @@ -572,8 +572,8 @@ int ras_cxl_overflow_event_handler(struct trace_seq *s, return -1; } /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_cxl_overflow_event(ras, &ev); +#ifdef HAVE_DB + db_cxl_overflow_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT @@ -786,8 +786,8 @@ int ras_cxl_generic_event_handler(struct trace_seq *s, } /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_cxl_generic_event(ras, &ev); +#ifdef HAVE_DB + db_cxl_generic_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT @@ -1031,8 +1031,8 @@ int ras_cxl_general_media_event_handler(struct trace_seq *s, } /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_cxl_general_media_event(ras, &ev); +#ifdef HAVE_DB + db_cxl_general_media_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT @@ -1268,8 +1268,8 @@ int ras_cxl_dram_event_handler(struct trace_seq *s, } /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_cxl_dram_event(ras, &ev); +#ifdef HAVE_DB + db_cxl_dram_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT @@ -1484,8 +1484,8 @@ int ras_cxl_memory_module_event_handler(struct trace_seq *s, } } /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_cxl_memory_module_event(ras, &ev); +#ifdef HAVE_DB + db_cxl_memory_module_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT diff --git a/ras-cxl-handler.h b/events/ras-cxl-handler.h similarity index 98% rename from ras-cxl-handler.h rename to events/ras-cxl-handler.h index 02f87a30..a87b552e 100644 --- a/ras-cxl-handler.h +++ b/events/ras-cxl-handler.h @@ -9,7 +9,7 @@ #include -#include "ras-events.h" +#include "core/ras-events.h" int ras_cxl_poison_event_handler(struct trace_seq *s, struct tep_record *record, diff --git a/ras-devlink-handler.c b/events/ras-devlink-handler.c similarity index 93% rename from ras-devlink-handler.c rename to events/ras-devlink-handler.c index 93eba915..8e4d5343 100644 --- a/ras-devlink-handler.c +++ b/events/ras-devlink-handler.c @@ -4,17 +4,16 @@ * Copyright (C) 2019 Cong Wang */ -#define _GNU_SOURCE #include #include #include #include #include -#include "ras-devlink-handler.h" -#include "ras-logger.h" -#include "ras-report.h" -#include "types.h" +#include "events/ras-devlink-handler.h" +#include "core/ras-logger.h" +#include "modules/ras-report.h" +#include "core/types.h" int ras_net_xmit_timeout_handler(struct trace_seq *s, struct tep_record *record, @@ -57,8 +56,8 @@ int ras_net_xmit_timeout_handler(struct trace_seq *s, return -1; /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_devlink_event(ras, &ev); +#ifdef HAVE_DB + db_devlink_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT @@ -130,8 +129,8 @@ int ras_devlink_event_handler(struct trace_seq *s, return -1; /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_devlink_event(ras, &ev); +#ifdef HAVE_DB + db_devlink_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT diff --git a/ras-devlink-handler.h b/events/ras-devlink-handler.h similarity index 94% rename from ras-devlink-handler.h rename to events/ras-devlink-handler.h index 47553da3..f3445cd9 100644 --- a/ras-devlink-handler.h +++ b/events/ras-devlink-handler.h @@ -9,7 +9,7 @@ #include -#include "ras-events.h" +#include "core/ras-events.h" int ras_net_xmit_timeout_handler(struct trace_seq *s, struct tep_record *record, diff --git a/ras-diskerror-handler.c b/events/ras-diskerror-handler.c similarity index 94% rename from ras-diskerror-handler.c rename to events/ras-diskerror-handler.c index 6044efaf..a73fd1a2 100644 --- a/ras-diskerror-handler.c +++ b/events/ras-diskerror-handler.c @@ -4,17 +4,16 @@ * Copyright (C) 2019 Cong Wang */ -#define _GNU_SOURCE #include #include #include #include #include -#include "ras-diskerror-handler.h" -#include "ras-logger.h" -#include "ras-report.h" -#include "types.h" +#include "events/ras-diskerror-handler.h" +#include "core/ras-logger.h" +#include "modules/ras-report.h" +#include "core/types.h" static const struct { int error; @@ -105,8 +104,8 @@ int ras_diskerror_event_handler(struct trace_seq *s, return -1; /* Insert data into the SGBD */ -#ifdef HAVE_SQLITE3 - ras_store_diskerror_event(ras, &ev); +#ifdef HAVE_DB + db_diskerror_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT diff --git a/ras-diskerror-handler.h b/events/ras-diskerror-handler.h similarity index 98% rename from ras-diskerror-handler.h rename to events/ras-diskerror-handler.h index 72856290..a7864cf4 100644 --- a/ras-diskerror-handler.h +++ b/events/ras-diskerror-handler.h @@ -9,7 +9,7 @@ #include -#include "ras-events.h" +#include "core/ras-events.h" /* * Defined in linux/kdev_t.h diff --git a/ras-memory-failure-handler.c b/events/ras-memory-failure-handler.c similarity index 95% rename from ras-memory-failure-handler.c rename to events/ras-memory-failure-handler.c index ead368b4..03ee9d6a 100644 --- a/ras-memory-failure-handler.c +++ b/events/ras-memory-failure-handler.c @@ -4,18 +4,17 @@ * Copyright (c) Huawei Technologies Co., Ltd. 2020. All rights reserved. */ -#define _GNU_SOURCE #include #include #include #include -#include "ras-logger.h" -#include "ras-memory-failure-handler.h" -#include "ras-poison-page-stat.h" -#include "ras-report.h" -#include "trigger.h" -#include "types.h" +#include "core/ras-logger.h" +#include "events/ras-memory-failure-handler.h" +#include "events/ras-poison-page-stat.h" +#include "modules/ras-report.h" +#include "core/trigger.h" +#include "core/types.h" /* Memory failure - various types of pages */ enum mf_action_page_type { @@ -214,9 +213,9 @@ int ras_memory_failure_event_handler(struct trace_seq *s, ras_poison_page_stat(); #endif - /* Store data into the SQLite DB */ -#ifdef HAVE_SQLITE3 - ras_store_mf_event(ras, &ev); + /* Store data into SQL DB */ +#ifdef HAVE_DB + db_mf_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT diff --git a/ras-memory-failure-handler.h b/events/ras-memory-failure-handler.h similarity index 94% rename from ras-memory-failure-handler.h rename to events/ras-memory-failure-handler.h index 85e2dd2e..07ea029f 100644 --- a/ras-memory-failure-handler.h +++ b/events/ras-memory-failure-handler.h @@ -9,7 +9,7 @@ #include -#include "ras-events.h" +#include "core/ras-events.h" extern unsigned long long poison_stat_threshold; diff --git a/ras-poison-page-stat.c b/events/ras-poison-page-stat.c similarity index 89% rename from ras-poison-page-stat.c rename to events/ras-poison-page-stat.c index bbedcc0e..2751d6d6 100644 --- a/ras-poison-page-stat.c +++ b/events/ras-poison-page-stat.c @@ -9,9 +9,9 @@ #include #include -#include "ras-logger.h" -#include "ras-poison-page-stat.h" -#include "types.h" +#include "core/ras-logger.h" +#include "events/ras-poison-page-stat.h" +#include "core/types.h" unsigned long long poison_stat_threshold; int ras_poison_page_stat(void) diff --git a/ras-poison-page-stat.h b/events/ras-poison-page-stat.h similarity index 100% rename from ras-poison-page-stat.h rename to events/ras-poison-page-stat.h diff --git a/ras-reri-handler.c b/events/ras-reri-handler.c old mode 100755 new mode 100644 similarity index 97% rename from ras-reri-handler.c rename to events/ras-reri-handler.c index 540d87df..79195e70 --- a/ras-reri-handler.c +++ b/events/ras-reri-handler.c @@ -14,12 +14,12 @@ #include #include -#include "ras-reri-handler.h" -#include "ras-cpu-isolation.h" -#include "ras-logger.h" -#include "ras-record.h" -#include "ras-report.h" -#include "types.h" +#include "events/ras-reri-handler.h" +#include "modules/ras-cpu-isolation.h" +#include "core/ras-logger.h" +#include "db/ras-record.h" +#include "modules/ras-report.h" +#include "core/types.h" #define RERI_GET_FIELD(val, offset, mask) (((val) >> (offset)) & (mask)) @@ -325,8 +325,8 @@ int ras_reri_event_handler(struct trace_seq *s, trace_seq_puts(s, "\n"); -#ifdef HAVE_SQLITE3 - ras_store_reri_event(ras, &ev); +#ifdef HAVE_DB + db_reri_event(ras, &ev); #endif #ifdef HAVE_CPU_FAULT_ISOLATION diff --git a/ras-reri-handler.h b/events/ras-reri-handler.h old mode 100755 new mode 100644 similarity index 99% rename from ras-reri-handler.h rename to events/ras-reri-handler.h index e1b8e342..8e941d84 --- a/ras-reri-handler.h +++ b/events/ras-reri-handler.h @@ -9,7 +9,7 @@ #define __RAS_RERI_HANDLER_H #include -#include "ras-events.h" +#include "core/ras-events.h" /* RERI Transaction Types */ #define RERI_TT_UNSPECIFIED 0 diff --git a/ras-signal-handler.c b/events/ras-signal-handler.c similarity index 95% rename from ras-signal-handler.c rename to events/ras-signal-handler.c index fb0bfd34..94f63b4e 100644 --- a/ras-signal-handler.c +++ b/events/ras-signal-handler.c @@ -16,15 +16,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#define _GNU_SOURCE #include #include #include #include -#include "ras-signal-handler.h" -#include "ras-report.h" -#include "types.h" +#include "events/ras-signal-handler.h" +#include "modules/ras-report.h" +#include "core/types.h" enum { TRACE_SIGNAL_DELIVERED, @@ -129,9 +128,9 @@ int ras_signal_event_handler(struct trace_seq *s, struct tep_record *record, report_ras_signal_event(s, &ev); - /* Store data into the SQLite DB */ -#ifdef HAVE_SQLITE3 - ras_store_signal_event(ras, &ev); + /* Store data into SQL DB */ +#ifdef HAVE_DB + db_signal_event(ras, &ev); #endif #ifdef HAVE_ABRT_REPORT diff --git a/ras-signal-handler.h b/events/ras-signal-handler.h similarity index 97% rename from ras-signal-handler.h rename to events/ras-signal-handler.h index 9740c618..d33c6afe 100644 --- a/ras-signal-handler.h +++ b/events/ras-signal-handler.h @@ -22,7 +22,7 @@ #include -#include "ras-events.h" +#include "core/ras-events.h" int ras_signal_event_handler(struct trace_seq *s, struct tep_record *record, struct tep_event *event, void *context); diff --git a/unified-sel.c b/events/unified-sel.c similarity index 96% rename from unified-sel.c rename to events/unified-sel.c index 06a2592e..4116b98a 100644 --- a/unified-sel.c +++ b/events/unified-sel.c @@ -7,10 +7,10 @@ #include #include #include -#include "ras-record.h" -#include "ras-logger.h" -#include "ras-report.h" -#include "unified-sel.h" +#include "db/ras-record.h" +#include "core/ras-logger.h" +#include "modules/ras-report.h" +#include "events/unified-sel.h" /* CPU Root Port Error ID corresponding to each status bit set */ static const char *cor_error_ids[32] = { diff --git a/unified-sel.h b/events/unified-sel.h similarity index 100% rename from unified-sel.h rename to events/unified-sel.h diff --git a/m4/.gitignore b/m4/.gitignore deleted file mode 100644 index 0f5f9045..00000000 --- a/m4/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -# Autoreconf adds those -libtool.m4 -lt~obsolete.m4 -ltoptions.m4 -ltsugar.m4 -ltversion.m4 diff --git a/m4/ac_define_dir.m4 b/m4/ac_define_dir.m4 deleted file mode 100644 index e15cea2c..00000000 --- a/m4/ac_define_dir.m4 +++ /dev/null @@ -1,34 +0,0 @@ -dnl @synopsis AC_DEFINE_DIR(VARNAME, DIR [, DESCRIPTION]) -dnl -dnl This macro sets VARNAME to the expansion of the DIR variable, -dnl taking care of fixing up ${prefix} and such. -dnl -dnl VARNAME is then offered as both an output variable and a C -dnl preprocessor symbol. -dnl -dnl Example: -dnl -dnl AC_DEFINE_DIR([DATADIR], [datadir], [Where data are placed to.]) -dnl -dnl @category Misc -dnl @author Stepan Kasal -dnl @author Andreas Schwab -dnl @author Guido U. Draheim -dnl @author Alexandre Oliva -dnl @version 2006-10-13 -dnl @license AllPermissive - -AC_DEFUN([AC_DEFINE_DIR], [ - prefix_NONE= - exec_prefix_NONE= - test "x$prefix" = xNONE && prefix_NONE=yes && prefix=$ac_default_prefix - test "x$exec_prefix" = xNONE && exec_prefix_NONE=yes && exec_prefix=$prefix -dnl In Autoconf 2.60, ${datadir} refers to ${datarootdir}, which in turn -dnl refers to ${prefix}. Thus we have to use `eval' twice. - eval ac_define_dir="\"[$]$2\"" - eval ac_define_dir="\"$ac_define_dir\"" - AC_SUBST($1, "$ac_define_dir") - AC_DEFINE_UNQUOTED($1, "$ac_define_dir", [$3]) - test "$prefix_NONE" && prefix=NONE - test "$exec_prefix_NONE" && exec_prefix=NONE -]) diff --git a/m4/x_ac_meta.m4 b/m4/x_ac_meta.m4 deleted file mode 100644 index dbe6ce3c..00000000 --- a/m4/x_ac_meta.m4 +++ /dev/null @@ -1,111 +0,0 @@ -##***************************************************************************** -## $Id: x_ac_meta.m4 416 2005-07-20 17:50:27Z dun $ -##***************************************************************************** -# AUTHOR: -# Chris Dunlap -# -# SYNOPSIS: -# X_AC_META -# -# DESCRIPTION: -# Read metadata from the META file. -##***************************************************************************** - -AC_DEFUN([X_AC_META], [ - AC_MSG_CHECKING([metadata]) - - META="$srcdir/META" - _x_ac_meta_got_file=no - if test -f "$META"; then - _x_ac_meta_got_file=yes - - META_NAME=_X_AC_META_GETVAL([(?:NAME|PROJECT|PACKAGE)]); - if test -n "$META_NAME"; then - AC_DEFINE_UNQUOTED([META_NAME], ["$META_NAME"], - [Define the project name.] - ) - AC_SUBST([META_NAME]) - fi - - META_VERSION=_X_AC_META_GETVAL([VERSION]); - if test -n "$META_VERSION"; then - AC_DEFINE_UNQUOTED([META_VERSION], ["$META_VERSION"], - [Define the project version.] - ) - AC_SUBST([META_VERSION]) - fi - - META_RELEASE=_X_AC_META_GETVAL([RELEASE]); - if test -n "$META_RELEASE"; then - AC_DEFINE_UNQUOTED([META_RELEASE], ["$META_RELEASE"], - [Define the project release.] - ) - AC_SUBST([META_RELEASE]) - fi - - if test -n "$META_NAME" -a -n "$META_VERSION"; then - META_ALIAS="$META_NAME-$META_VERSION" - test -n "$META_RELEASE" && META_ALIAS="$META_ALIAS-$META_RELEASE" - AC_DEFINE_UNQUOTED([META_ALIAS], ["$META_ALIAS"], - [Define the project alias string (name-ver or name-ver-rel).] - ) - AC_SUBST([META_ALIAS]) - fi - - META_DATE=_X_AC_META_GETVAL([DATE]); - if test -n "$META_DATE"; then - AC_DEFINE_UNQUOTED([META_DATE], ["$META_DATE"], - [Define the project release date.] - ) - AC_SUBST([META_DATE]) - fi - - META_AUTHOR=_X_AC_META_GETVAL([AUTHOR]); - if test -n "$META_AUTHOR"; then - AC_DEFINE_UNQUOTED([META_AUTHOR], ["$META_AUTHOR"], - [Define the project author.] - ) - AC_SUBST([META_AUTHOR]) - fi - - m4_pattern_allow([^LT_(CURRENT|REVISION|AGE)$]) - META_LT_CURRENT=_X_AC_META_GETVAL([LT_CURRENT]); - META_LT_REVISION=_X_AC_META_GETVAL([LT_REVISION]); - META_LT_AGE=_X_AC_META_GETVAL([LT_AGE]); - if test -n "$META_LT_CURRENT" \ - -o -n "$META_LT_REVISION" \ - -o -n "$META_LT_AGE"; then - test -n "$META_LT_CURRENT" || META_LT_CURRENT="0" - test -n "$META_LT_REVISION" || META_LT_REVISION="0" - test -n "$META_LT_AGE" || META_LT_AGE="0" - AC_DEFINE_UNQUOTED([META_LT_CURRENT], ["$META_LT_CURRENT"], - [Define the libtool library 'current' version information.] - ) - AC_DEFINE_UNQUOTED([META_LT_REVISION], ["$META_LT_REVISION"], - [Define the libtool library 'revision' version information.] - ) - AC_DEFINE_UNQUOTED([META_LT_AGE], ["$META_LT_AGE"], - [Define the libtool library 'age' version information.] - ) - AC_SUBST([META_LT_CURRENT]) - AC_SUBST([META_LT_REVISION]) - AC_SUBST([META_LT_AGE]) - fi - fi - - AC_MSG_RESULT([$_x_ac_meta_got_file]) - ] -) - -AC_DEFUN([_X_AC_META_GETVAL], - [`perl -n\ - -e "BEGIN { \\$key=shift @ARGV; }"\ - -e "next unless s/^\s*\\$key@<:@:=@:>@//i;"\ - -e "s/^((?:@<:@^'\"#@:>@*(?:(@<:@'\"@:>@)@<:@^\2@:>@*\2)*)*)#.*/\\@S|@1/;"\ - -e "s/^\s+//;"\ - -e "s/\s+$//;"\ - -e "s/^(@<:@'\"@:>@)(.*)\1/\\@S|@2/;"\ - -e "\\$val=\\$_;"\ - -e "END { print \\$val if defined \\$val; }"\ - '$1' $META`]dnl -) diff --git a/man/Makefile.am b/man/Makefile.am deleted file mode 100644 index f6c95218..00000000 --- a/man/Makefile.am +++ /dev/null @@ -1,4 +0,0 @@ -# SPDX-License-Identifier: GPL-2.0 - -man_MANS = ras-mc-ctl.8 rasdaemon.1 - diff --git a/man/ras-mc-ctl.8.in b/man/ras-mc-ctl.8.in index e9309c8d..9fa3990f 100644 --- a/man/ras-mc-ctl.8.in +++ b/man/ras-mc-ctl.8.in @@ -1,144 +1,111 @@ -.\"**************************************************************************** -.\" $Id$ -.\"**************************************************************************** -.\"SPDX-License-Identifier: GPL-2.0-or-later" -.\" -.\"Copyright (c) 2013 Mauro Carvalho Chehab -.\"This tool is a modification of the edac-ctl, written as part of the -.\"edac-utils: -.\" Copyright (C) 2006-2007 The Regents of the University of California. -.\" Produced at Lawrence Livermore National Laboratory. -.\" Written by Mark Grondona -.\" UCRL-CODE-230739. -.\" -.\" 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 2 of the License, or -.\" (at your option) any later version. -.\" -.\" This 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 program; if not, write to the Free Software Foundation, Inc., -.\" 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. -.\"**************************************************************************** - +." SPDX-License-Identifier: GPL-2.0-or-later .TH RAS-MC-CTL 8 "@META_DATE@" "@META_ALIAS@" "RAS memory controller admin utility" - .SH NAME -ras-mc-ctl \- RAS memory controller admin utility - +ras-mc-ctl \- inspect EDAC DIMM information and recorded RAS events .SH SYNOPSIS .B ras-mc-ctl -[\fIOPTION\fR]... - +[\fIGLOBAL OPTIONS\fR] \fBdimm\fR [\fIOPTIONS\fR] +.br +.B ras-mc-ctl +[\fIGLOBAL OPTIONS\fR] \fBdatabase\fR [\fIOPTIONS\fR] .SH DESCRIPTION - -The \fBras-mc-ctl\fR program is a \fBperl\fR(1) script which performs -some useful RAS administration tasks on EDAC (Error Detection and Correction) -drivers. - -.SH OPTIONS -.TP -.BI "--help" -Display a brief usage message. -.TP -.BI "--mainboard" -Print mainboard vendor and model for this hardware, if available. -The method used by \fBras-mc-ctl\fR to obtain the mainboard vendor -and model information for the current system is described below -in the \fIMAINBOARD CONFIGURATION\fR section. -.TP -.BI "--status" -Print the status of EDAC drivers (loaded or unloaded). -.TP -.BI "--quiet" -Be less verbose when executing an operation. -.TP -.BI "--register-labels" -Register motherboard DIMM labels into EDAC driver sysfs files. -This option uses the detected mainboard manufacturer and model -number in combination with a "labels database" found in any -of the files under @sysconfdir@/ras/dimm_labels.d/* or in the labels.db file -at @sysconfdir@/ras/dimm_labels.db. An entry for the current hardware must -exist in the labels database for this option to do anything. -.TP -.BI "--print-labels" -Display the configured labels for the current hardware, as -well as the current labels registered with EDAC. -.TP -.BI "--guess-labels" -Print DMI labels, when bank locator is available in the DMI table. -It helps to fill the labels database at @sysconfdir@/ras/dimm_labels.d/. -.TP -.BI "--labeldb="DB -Specify an alternate location for the labels database. -.TP -.BI "--delay="time -Specify a delay of \fBtime\fR seconds before registering DIMM labels. -Only meaninful if used together with --register-labels. -.TP -.BI "--layout" -Prints the memory layout as detected by the EDAC driver. Useful to check -if the EDAC driver is properly detecting the memory controller architecture. -.TP -.BI "--summary" -Presents a summary of the logged errors. -.TP -.BI "--errors" -Shows the errors stored at the error database. -.TP -.BI "--error-count" -Shows the corrected and uncorrected error counts using sysfs. -.TP -.BI "--vendor-errors-summary="platform-id -Pressents a summary of the vendor-specific logged errors. -.TP -.BI "--vendor-errors="platform-id -Shows the vendor-specific errors stored in the error database. -.TP -.BI "--vendor-platforms" -Shows the supported platforms with platform-ids for the vendor-specific errors. - -.SH MAINBOARD CONFIGURATION -.PP -The \fBras-mc-ctl\fR script uses the following method to determine the -current system's mainboard vendor and model information: - -.IP "1." 4 -If the config file @sysconfdir@/edac/mainboard exists, then it is -parsed by \fBras-mc-ctl\fR. The mainboard config file has the following -simple syntax: -.nf - - vendor = - model = - script =