diff --git a/sbd.spec b/sbd.spec index 0291598..4dd192f 100644 --- a/sbd.spec +++ b/sbd.spec @@ -1,341 +1,358 @@ # # spec file for package sbd # # Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. # Copyright (c) 2013 Lars Marowsky-Bree # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed # upon. The license for this file, and modifications and additions to the # file, is the same license as for the pristine package itself (unless the # license for the pristine package is not an Open Source License, in which # case the license is the MIT License). An "Open Source License" is a # license that conforms to the Open Source Definition (Version 1.9) # published by the Open Source Initiative. # Please submit bugfixes or comments via http://bugs.opensuse.org/ # %global longcommit 7bcdf69597042c31ea0b4a523e732d4bbb99b3a0 %global shortcommit %(echo %{longcommit}|cut -c1-8) %global modified %(echo %{longcommit}-|cut -f2 -d-) %global github_owner Clusterlabs %global commit_counter 0 %global build_counter 0 %global buildnum %(expr %{commit_counter} + %{build_counter}) %ifarch s390x s390 # minimum timeout on LPAR diag288 watchdog is 15s %global watchdog_timeout_default 15 %else %global watchdog_timeout_default 5 %endif # Be careful with sync_resource_startup_default # being enabled. This configuration has # to be in sync with configuration in pacemaker # where it is called sbd_sync - assure by e.g. # mutual rpm dependencies. %bcond_without sync_resource_startup_default # Syncing enabled per default will lead to # syncing enabled on upgrade without adaption # of the config. # Setting can still be overruled via sysconfig. # The setting in the config-template packaged # will follow the default if below is is left # empty. But it is possible to have the setting # in the config-template deviate from the default # by setting below to an explicit 'yes' or 'no'. %global sync_resource_startup_sysconfig "" +# Try finding and using libaio.so.x library name i.e. the one with the major +# version number such as libaio.so.1 +%global libaio_name %(readlink -f %{_libdir}/libaio.so | xargs basename | cut -d "." -f 1-3) + +%if "%{libaio_name}" != "" && "%{libaio_name}" != "libaio.so" +%global specify_libaio 1 +%endif + Name: sbd Summary: Storage-based death License: GPL-2.0-or-later Group: System Environment/Daemons Version: 1.5.2 Release: 99.%{buildnum}.%{shortcommit}.%{modified}git%{?dist} Url: https://github.com/%{github_owner}/%{name} Source0: https://github.com/%{github_owner}/%{name}/archive/%{longcommit}/%{name}-%{longcommit}.tar.gz BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: autoconf BuildRequires: automake BuildRequires: libuuid-devel BuildRequires: glib2-devel BuildRequires: libaio-devel BuildRequires: corosync-devel %if 0%{?suse_version} %if 0%{?suse_version} > 1500 BuildRequires: libpacemaker3-devel %else BuildRequires: libpacemaker-devel %endif %else BuildRequires: pacemaker-libs-devel %endif BuildRequires: libtool BuildRequires: libuuid-devel BuildRequires: libxml2-devel BuildRequires: pkgconfig BuildRequires: make Conflicts: fence-agents-sbd < 4.5.0 %if 0%{?rhel} > 0 ExclusiveArch: i686 x86_64 s390x aarch64 ppc64le %endif %if %{defined systemd_requires} %systemd_requires %endif %description This package contains the storage-based death functionality. Available rpmbuild rebuild options: --with(out) : sync_resource_startup_default %package tests Summary: Storage-based death environment for regression tests License: GPL-2.0-or-later Group: System Environment/Daemons +%if ! 0%{?specify_libaio} +# Requires libaio-devel for the generic symbolic link libaio.so +Requires: libaio-devel +%endif %description tests This package provides an environment + testscripts for regression-testing sbd. %prep ########################################################### %setup -q -n %{name}-%{longcommit} ########################################################### %build ./autogen.sh export CFLAGS="$RPM_OPT_FLAGS -Wall -Werror" + +%if 0%{?specify_libaio} +export CFLAGS="${CFLAGS} -DLIBAIO_NAME=%{libaio_name}" +%endif + %configure --with-watchdog-timeout-default=%{watchdog_timeout_default} \ --with-sync-resource-startup-default=%{?with_sync_resource_startup_default:yes}%{!?with_sync_resource_startup_default:no} \ --with-sync-resource-startup-sysconfig=%{sync_resource_startup_sysconfig} \ --with-runstatedir=%{_rundir} make %{?_smp_mflags} ########################################################### %install ########################################################### make DESTDIR=$RPM_BUILD_ROOT LIBDIR=%{_libdir} install rm -rf ${RPM_BUILD_ROOT}%{_libdir}/stonith install -D -m 0755 src/sbd.sh $RPM_BUILD_ROOT/usr/share/sbd/sbd.sh install -D -m 0755 tests/regressions.sh $RPM_BUILD_ROOT/usr/share/sbd/regressions.sh %if %{defined _unitdir} install -D -m 0644 src/sbd.service $RPM_BUILD_ROOT/%{_unitdir}/sbd.service install -D -m 0644 src/sbd_remote.service $RPM_BUILD_ROOT/%{_unitdir}/sbd_remote.service %endif mkdir -p ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig install -m 644 src/sbd.sysconfig ${RPM_BUILD_ROOT}%{_sysconfdir}/sysconfig/sbd # Don't package static libs find %{buildroot} -name '*.a' -type f -print0 | xargs -0 rm -f find %{buildroot} -name '*.la' -type f -print0 | xargs -0 rm -f %clean rm -rf %{buildroot} %if %{defined _unitdir} %post %systemd_post sbd.service %systemd_post sbd_remote.service %preun %systemd_preun sbd.service %systemd_preun sbd_remote.service %postun %systemd_postun sbd.service %systemd_postun sbd_remote.service %endif %files ########################################################### %defattr(-,root,root) %config(noreplace) %{_sysconfdir}/sysconfig/sbd %{_sbindir}/sbd %{_datadir}/sbd %{_datadir}/pkgconfig/sbd.pc %exclude %{_datadir}/sbd/regressions.sh %doc %{_mandir}/man8/sbd* %if %{defined _unitdir} %{_unitdir}/sbd.service %{_unitdir}/sbd_remote.service %endif %doc COPYING %files tests %defattr(-,root,root) %dir %{_datadir}/sbd %{_datadir}/sbd/regressions.sh %{_libdir}/libsbdtestbed* %changelog * Sun Jun 2 2024 - 1.5.2-99.0.7a3cd78b.git - remove commented setup-macro (applied in f41) * Thu Jan 5 2023 - 1.5.2-99.0.8ec8e011.git - fail startup if pacemaker integration is disabled while SBD_SYNC_RESOURCE_STARTUP is conflicting (+ hint to overcome) - improve logs - when logging state of SBD_PACEMAKER tell it is just that as this might still be overridden via cmdline options - log a warning if SBD_PACEMAKER is overridden by -P or -PP option - do not warn about startup syncing with pacemaker integration disabled - when watchdog-device is busy give a hint on who is hogging it - improve build environment - have --with-runstatedir overrule --runstatedir - use new package name for pacemaker devel on opensuse - make config location configurable for man-page-creation - reverse alloc/de-alloc order to make gcc-12 static analysis happy - improve test environment - have image-files in /dev/shm to assure they are in memory and sbd opening the files with O_SYNC doesn't trigger unnecessary syncs on a heavily loaded test-machine fallback to /tmp if /dev/shm doesn't exist - wrapping away libaio and usage of device-mapper for block-device simulation can now be passed into make via SBD_USE_DM & SBD_TRANSLATE_AIO - have variables that configure test-environment be printed out prior to running tests - finally assure we clean environment when interrupted by a signal (bash should have done it with just setting EXIT handler - but avoiding bashism might come handy one day) * Mon Nov 15 2021 - 1.5.1-99.0.7bcdf695.git - improve/fix cmdline handling - tell the actual watchdog device specified with -w - tolerate and strip any leading spaces of commandline option values - Sanitize numeric arguments - if start-delay enabled, not explicitly given and msgwait can't be read from disk (diskless) use 2 * watchdog-timeout - avoid using deprecated valloc for disk-io-buffers - avoid frequent alloc/free of aligned buffers to prevent fragmentation - fix memory-leak in one-time-allocations of sector-buffers - fix AIO-API usage: properly destroy io-context - improve/fix build environment - validate configure options for paths - remove unneeded complexity of configure.ac hierarchy - correctly derive package version from git (regression since 1.5.0) - make runstatedir configurable and derive from distribution * Tue Jun 8 2021 - 1.5.0-99.0.2a00ac70.git - default to resource-syncing with pacemaker in spec-file and configure.ac This default has to match between sbd and pacemaker and thus qualifies this release for a minor-version-bump - fix some regressions introduced by adding configurability previously - adapt description of startup/shutdown sync with pacemaker - make watchdog warning messages more understandable * Wed Dec 2 2020 - 1.4.2-99.1.bfeee963.git - improve build/CI-friendlyness - * travis: switch to F32 as build-host - switch to F32 & leap-15.2 - changes for mock-2.0 - turn off loop-devices & device-mapper on x86_64 targets because - of changes in GCE - * regressions.sh: get timeouts from disk-header to go with proper defaults - for architecture - * use configure for watchdog-default-timeout & others - * ship sbd.pc with basic sbd build information for downstream packages - to use - * add number of commits since version-tag to build-counter - add robustness against misconfiguration / improve documentation - * add environment section to man-page previously just available in - template-config - * inform the user to restart the sbd service after disk-initialization - * refuse to start if any of the configured device names is invalid - * add handshake to sync startup/shutdown with pacemakerd - Previously sbd just waited for the cib-connnection to show up/go away - which isn't robust at all. - The new feature needs new pacemakerd-api as counterpart. - Thus build checks for presence of pacemakerd-api. - To simplify downstream adoption behavior is configurable at runtime - via configure-file with a build-time-configurable default. - * refuse to start if qdevice-sync_timeout doesn't match watchdog-timeout - Needed in particular as qdevice-sync_timeout delays quorum-state-update - and has a default of 30s that doesn't match the 5s watchdog-timeout - default. - Fix: sbd-pacemaker: handle new no_quorum_demote + robustness against new - policies added - Fix: agent: correctly compare string values when calculating timeout - Fix: scheduling: overhaul the whole thing - * prevent possible lockup when format in proc changes - * properly get and handle scheduler policy & prio - * on SCHED_RR failing push to the max with SCHED_OTHER * Tue Nov 19 2019 - 1.4.1-99.1.aca7907c.git - improvements/clarifications in documentation - properly finalize cmap connection when disconnected from cluster - make handling of cib-connection loss more robust - silence some coverity findings - overhaul log for reasonable prios and details - if current slice doesn't have rt-budget move to root-slice - periodically ping corosync daemon for liveness - actually use crashdump timeout if configured - avoid deprecated names for g_main-loop-funcitons - conflict with fence-agents-sbd < 4.5.0 - rather require corosync-devel provided by most distributions - make devices on cmdline overrule those coming via SBD_DEVICE - make 15s timeout on s390 be used consistently - improve build/test for CI-friendlyness - * add autogen.sh - * enable/improve out-of-tree-building - * make tar generation smarter - * don't modify sbd.spec - * make distcheck-target work - * Add tests/regressions.sh to check-target - * use unique devmapper names for multiple tests in parallel - * consistently use serial test-harness for visible progress - * package tests into separate package (not packaged before) - * add preload-library to intercept reboots while testing - * add tests for sbd in daemon-mode & watchdog-dev-handling - * make tests work in non-privileged containers * Mon Jan 14 2019 - 1.4.0-0.1.2d595fdd.git - updated travis-CI (ppc64le-build, fedora29, remove need for alectolytic-build-container) - make watchdog-device-query easier to be handled by an SELinux-policy - configurable delay value for SBD_DELAY_START - use pacemaker's new pe api with constructors/destructors - make timeout-action executed by sbd configurable - init script for sysv systems - version bump to v1.4.0 to denote Pacemaker 2.0.0 compatibility * Fri Jun 29 2018 - 1.3.1-0.1.e102d9ed.git - removed unneeded python-devel build-requirement - changed legacy corosync-devel to corosynclib-devel * Fri Nov 3 2017 - 1.3.1-0.1.a180176c.git - Add commands to test/query watchdogs - Allow 2-node-operation with a single shared-disk - Overhaul of the command-line options & config-file - Proper handling of off instead of reboot - Refactored disk-servant for more robust communication with parent - Fix config for Debian + configurable location of config - Fixes in sbd.sh - multiple SBD devices and others * Sun Mar 27 2016 - 1.3.0-0.1.4ee36fa3.git - Changes since v1.2.0 like adding the possibility to have a watchdog-only setup without shared-block-devices legitimate a bump to v1.3.0. * Mon Oct 13 2014 - 1.2.1-0.4.3de531ed.git - Fixes for suitability to the el7 environment * Tue Sep 30 2014 - 1.2.1-0.3.8f912945.git - Only build on archs supported by the HA Add-on * Fri Aug 29 2014 - 1.2.1-0.2.8f912945.git - Remove some additional SUSE-isms * Fri Aug 29 2014 - 1.2.1-0.1.8f912945.git - Prepare for package review Resolves: rhbz#1134245 diff --git a/tests/sbd-testbed.c b/tests/sbd-testbed.c index 02844a7..3a4b4dc 100644 --- a/tests/sbd-testbed.c +++ b/tests/sbd-testbed.c @@ -1,745 +1,761 @@ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if __GLIBC_PREREQ(2,36) #include #else #include typedef gboolean (*GUnixFDSourceFunc) (gint fd, GIOCondition condition, gpointer user_data); static gboolean GIOFunc2GUnixFDSourceFunc(GIOChannel *source, GIOCondition condition, gpointer data) { return ((GUnixFDSourceFunc) data) ( g_io_channel_unix_get_fd(source), condition, NULL); } static guint g_unix_fd_add(gint fd, GIOCondition condition, GUnixFDSourceFunc function, gpointer user_data) { GIOChannel *chan = g_io_channel_unix_new (fd); if (chan == NULL) { return 0; } else { return g_io_add_watch(chan, condition, GIOFunc2GUnixFDSourceFunc, (gpointer) function); } } #endif +#define LIBAIO_DOQUOTE(name) #name +#define LIBAIO_QUOTE(name) LIBAIO_DOQUOTE(name) + +#define LIBAIO_DEFAULT LIBAIO_QUOTE(libaio.so) + +#ifndef LIBAIO_NAME + #define LIBAIO_QUOTED LIBAIO_DEFAULT +#else + #define LIBAIO_QUOTED LIBAIO_QUOTE(LIBAIO_NAME) +#endif + typedef int (*orig_open_f_type)(const char *pathname, int flags, ...); typedef int (*orig_ioctl_f_type)(int fd, unsigned long int request, ...); typedef ssize_t (*orig_write_f_type)(int fd, const void *buf, size_t count); typedef int (*orig_close_f_type)(int fd); typedef FILE *(*orig_fopen_f_type)(const char *pathname, const char *mode); typedef int (*orig_fclose_f_type)(FILE *fp); typedef int (*orig_io_setup_f_type)(int nr_events, io_context_t *ctx_idp); typedef int (*orig_io_destroy_f_type)(io_context_t ctx_id); typedef int (*orig_io_submit_f_type)(io_context_t ctx_id, long nr, struct iocb *ios[]); typedef int (*orig_io_getevents_f_type)(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout); typedef int (*orig_io_cancel_f_type)(io_context_t ctx_id, struct iocb *iocb, struct io_event *result); static int is_init = 0; static FILE *log_fp = NULL; static char *sbd_device[3] = {NULL, NULL, NULL}; static int sbd_device_fd[3] = {-1, -1, -1}; static FILE *sysrq_fp = NULL; static FILE *sysrq_trigger_fp = NULL; static char *watchdog_device = NULL; static int watchdog_device_fd = -1; static int watchdog_timeout = -1; static pid_t watchdog_pid = -1; static int watchdog_pipe[2] = {-1, -1}; static guint watchdog_source_id = 0; static int watchdog_timer_id = 0; static orig_open_f_type orig_open = NULL; static orig_ioctl_f_type orig_ioctl = NULL; static orig_write_f_type orig_write = NULL; static orig_close_f_type orig_close = NULL; static orig_fopen_f_type orig_fopen = NULL; static orig_fclose_f_type orig_fclose = NULL; static orig_io_setup_f_type orig_io_setup = NULL; static orig_io_destroy_f_type orig_io_destroy = NULL; static orig_io_submit_f_type orig_io_submit = NULL; static orig_io_getevents_f_type orig_io_getevents = NULL; static orig_io_cancel_f_type orig_io_cancel = NULL; /* fprintf is inlined as __fprintf_chk or * we have vfprintf. * For fscanf we have vfscanf. * For reboot we anyway don't want that to be * called in any case. */ static struct iocb *pending_iocb = NULL; struct io_context { int context_num; }; static struct io_context our_io_context = {.context_num = 1}; static int translate_aio = 0; static GMainLoop *mainloop = NULL; #if 0 static void watchdog_shutdown(int nsig) { if (watchdog_timer_id > 0) { fprintf(log_fp, "exiting with watchdog-timer armed\n"); } } #endif static void* dlsym_fatal(void *handle, const char *symbol) { void *rv = dlsym(handle, symbol); if (!rv) { fprintf(stderr, "Failed looking up symbol %s\n", symbol); exit(1); } return rv; } static void init (void) { void *handle; if (!is_init) { const char *value; int i; char *token, *str, *str_orig; + const char *libaio = LIBAIO_QUOTED; is_init = 1; orig_open = (orig_open_f_type)dlsym_fatal(RTLD_NEXT,"open"); orig_ioctl = (orig_ioctl_f_type)dlsym_fatal(RTLD_NEXT,"ioctl"); orig_close = (orig_close_f_type)dlsym_fatal(RTLD_NEXT,"close"); orig_write = (orig_write_f_type)dlsym_fatal(RTLD_NEXT,"write"); orig_fopen = (orig_fopen_f_type)dlsym_fatal(RTLD_NEXT,"fopen"); orig_fclose = (orig_fclose_f_type)dlsym_fatal(RTLD_NEXT,"fclose"); - handle = dlopen("libaio.so", RTLD_NOW); + if (libaio == NULL || libaio[0] == '\0') { + libaio = LIBAIO_DEFAULT; + } + + handle = dlopen(libaio, RTLD_NOW); if (!handle) { - fprintf(stderr, "Failed opening libaio.so.1\n"); + fprintf(stderr, "Failed opening %s (%s)\n", libaio, dlerror()); exit(1); } orig_io_setup = (orig_io_setup_f_type)dlsym_fatal(handle,"io_setup"); orig_io_destroy = (orig_io_destroy_f_type)dlsym_fatal(handle,"io_destroy"); orig_io_submit = (orig_io_submit_f_type)dlsym_fatal(handle,"io_submit"); orig_io_getevents = (orig_io_getevents_f_type)dlsym_fatal(handle,"io_getevents"); orig_io_cancel = (orig_io_cancel_f_type)dlsym_fatal(handle,"io_cancel"); dlclose(handle); value = getenv("SBD_PRELOAD_LOG"); if (value) { log_fp = fopen(value, "a"); } else { int fd = dup(fileno(stderr)); if (fd >= 0) { log_fp = fdopen(fd, "w"); } } if (log_fp == NULL) { fprintf(stderr, "couldn't open log-file\n"); } value = getenv("SBD_WATCHDOG_DEV"); if (value) { watchdog_device = strdup(value); } value = getenv("SBD_DEVICE"); if ((value) && (str = str_orig = strdup(value))) { for (i = 0; i < 3; i++, str = NULL) { token = strtok(str, ";"); if (token == NULL) { break; } sbd_device[i] = strdup(token); } free(str_orig); } value = getenv("SBD_TRANSLATE_AIO"); if ((value) && !strcmp(value, "yes")) { translate_aio = 1; } } } // ***** end - handling of watchdog & block-devices **** static gboolean watchdog_timeout_notify(gpointer data) { fprintf(log_fp, "watchdog fired after %ds - killing process group\n", watchdog_timeout); fclose(log_fp); log_fp = NULL; killpg(0, SIGKILL); exit(1); } static gboolean watchdog_dispatch_callback (gint fd, GIOCondition condition, gpointer user_data) { char buf[256]; int i = 0; if (condition & G_IO_HUP) { return FALSE; } if (watchdog_timer_id > 0) { g_source_remove(watchdog_timer_id); } watchdog_timer_id = 0; for (i = 0; i < sizeof(buf)-1; i++) { ssize_t len; do { len = read(watchdog_pipe[0], &buf[i], 1); } while ((len == -1) && (errno == EINTR)); if (len <= 0) { if (len == -1) { fprintf(log_fp, "Couldn't read from watchdog-pipe\n"); } buf[i] = '\0'; break; } if (buf[i] == '\n') { buf[i] = '\0'; break; } } buf[sizeof(buf)-1] = '\0'; if (sscanf(buf, "trigger %ds", &watchdog_timeout) == 1) { watchdog_timer_id = g_timeout_add(watchdog_timeout * 1000, watchdog_timeout_notify, NULL); } else if (strcmp(buf, "disarm") == 0) { // timer is stopped already } else { fprintf(log_fp, "unknown watchdog command\n"); } return TRUE; } static void watchdog_arm (void) { char buf[256]; if ((watchdog_timeout > 0) && (watchdog_pipe[1] >= 0)) { sprintf(buf, "trigger %ds\n", watchdog_timeout); if (write(watchdog_pipe[1], buf, strlen(buf)) != strlen(buf)) { fprintf(log_fp, "Failed tickling watchdog via pipe\n"); } } } static void watchdog_disarm (void) { char buf[256]; watchdog_timeout = -1; if (watchdog_pipe[1] >= 0) { sprintf(buf, "disarm\n"); if (write(watchdog_pipe[1], buf, strlen(buf)) != strlen(buf)) { fprintf(log_fp, "Failed disarming watchdog via pipe\n"); } } } int open(const char *pathname, int flags, ...) { int i, fd; int devnum = -1; int is_wd_dev = 0; va_list ap; init(); for (i=0; i < 3; i++) { if (sbd_device[i]) { if (strcmp(sbd_device[i], pathname) == 0) { devnum = i; flags &= ~O_DIRECT; break; } } } if (watchdog_device) { if (strcmp(watchdog_device, pathname) == 0) { is_wd_dev = 1; if (watchdog_pipe[1] == -1) { if (pipe(watchdog_pipe) == -1) { fprintf(log_fp, "Creating pipe for watchdog failed\n"); } else { int i; watchdog_pid = fork(); switch (watchdog_pid) { case -1: fprintf(log_fp, "Forking watchdog-child failed\n"); break; case 0: free(watchdog_device); watchdog_device = NULL; for (i = 0; i < 3; i++) { free(sbd_device[i]); sbd_device[i] = NULL; } close(watchdog_pipe[1]); if (fcntl(watchdog_pipe[0], F_SETFL, O_NONBLOCK) == -1) { // don't block on read for timer to be handled fprintf(log_fp, "Failed setting watchdog-pipe-read to non-blocking"); } mainloop = g_main_loop_new(NULL, FALSE); // mainloop_add_signal(SIGTERM, watchdog_shutdown); // mainloop_add_signal(SIGINT, watchdog_shutdown); watchdog_source_id = g_unix_fd_add(watchdog_pipe[0], G_IO_IN, watchdog_dispatch_callback, NULL); if (watchdog_source_id == 0) { fprintf(log_fp, "Failed creating source for watchdog-pipe\n"); exit(1); } g_main_loop_run(mainloop); g_main_loop_unref(mainloop); exit(0); default: close(watchdog_pipe[0]); if (fcntl(watchdog_pipe[1], F_SETFL, O_NONBLOCK) == -1) { fprintf(log_fp, "Failed setting watchdog-pipe-write to non-blocking"); } } } } pathname = "/dev/null"; } } va_start (ap, flags); fd = (flags & (O_CREAT #ifdef O_TMPFILE | O_TMPFILE #endif ))? orig_open(pathname, flags, va_arg(ap, mode_t)): orig_open(pathname, flags); va_end (ap); if (devnum >= 0) { sbd_device_fd[devnum] = fd; } else if (is_wd_dev) { watchdog_device_fd = fd; } return fd; } ssize_t write(int fd, const void *buf, size_t count) { init(); if ((fd == watchdog_device_fd) && (count >= 1)) { if (*(const char *)buf == 'V') { watchdog_disarm(); } else { watchdog_arm(); } } return orig_write(fd, buf, count); } int ioctl(int fd, unsigned long int request, ...) { int rv = -1; va_list ap; int i; init(); va_start(ap, request); switch (request) { case BLKSSZGET: for (i=0; i < 3; i++) { if (sbd_device_fd[i] == fd) { rv = 0; *(va_arg(ap, int *)) = 512; break; } if (i == 2) { rv = orig_ioctl(fd, request, va_arg(ap, int *)); } } break; case WDIOC_SETTIMEOUT: if (fd == watchdog_device_fd) { watchdog_timeout = *va_arg(ap, int *); watchdog_arm(); rv = 0; break; } rv = orig_ioctl(fd, request, va_arg(ap, int *)); break; case WDIOC_SETOPTIONS: if (fd == watchdog_device_fd) { int flags = *va_arg(ap, int *); if (flags & WDIOS_DISABLECARD) { watchdog_disarm(); } rv = 0; break; } rv = orig_ioctl(fd, request, va_arg(ap, int *)); break; case WDIOC_GETSUPPORT: rv = orig_ioctl(fd, request, va_arg(ap, struct watchdog_info *)); break; default: fprintf(log_fp, "ioctl using unknown request = 0x%08lx", request); rv = orig_ioctl(fd, request, va_arg(ap, void *)); } va_end(ap); return rv; } int close(int fd) { int i; init(); if (fd == watchdog_device_fd) { watchdog_device_fd = -1; } else { for (i = 0; i < 3; i++) { if (sbd_device_fd[i] == fd) { sbd_device_fd[i] = -1; break; } } } return orig_close(fd); } // ***** end - handling of watchdog & block-devices **** // ***** handling of sysrq, sysrq-trigger & reboot **** FILE * fopen(const char *pathname, const char *mode) { int is_sysrq = 0; int is_sysrq_trigger = 0; FILE *fp; init(); if ((strcmp("/proc/sys/kernel/sysrq", pathname) == 0) && strcmp("w", mode)) { pathname = "/dev/null"; is_sysrq = 1; } else if (strcmp("/proc/sysrq-trigger", pathname) == 0) { pathname = "/dev/null"; is_sysrq_trigger = 1; } fp = orig_fopen(pathname, mode); if (is_sysrq) { sysrq_fp = fp; } else if (is_sysrq_trigger) { sysrq_trigger_fp = fp; } return fp; } int fclose(FILE *fp) { init(); if (fp == sysrq_fp) { sysrq_fp = NULL; } else if (fp == sysrq_trigger_fp) { sysrq_trigger_fp = NULL; } return orig_fclose(fp); } #if defined(__USE_FORTIFY_LEVEL) && (__USE_FORTIFY_LEVEL > 1) int __fprintf_chk(FILE *stream, int flag, const char *format, ...) #else int fprintf(FILE *stream, const char *format, ...) #endif { va_list ap; int rv; init(); va_start (ap, format); if (stream == sysrq_trigger_fp) { char buf[256]; rv = vsnprintf(buf, sizeof(buf), format, ap); if (rv >= 1) { fprintf(log_fp, "sysrq-trigger ('%c') - %s\n", buf[0], (buf[0] == 'c')?"killing process group":"don't kill but wait for reboot-call"); if (buf[0] == 'c') { fclose(log_fp); log_fp = NULL; killpg(0, SIGKILL); exit(1); } } } else { rv = vfprintf(stream, format, ap); } va_end (ap); return rv; } int fscanf(FILE *stream, const char *format, ...) { va_list ap; int rv; init(); va_start (ap, format); rv = vfscanf(stream, format, ap); va_end (ap); return rv; } int reboot (int __howto) { fprintf(log_fp, "reboot (%s) - exiting inquisitor process\n", (__howto == RB_POWER_OFF)?"poweroff":"reboot"); fclose(log_fp); log_fp = NULL; killpg(0, SIGKILL); exit(1); } // ***** end - handling of sysrq, sysrq-trigger & reboot **** // ***** aio translate **** #if 0 struct iocb { void *data; unsigned key; short aio_lio_opcode; short aio_reqprio; int aio_fildes; }; static inline void io_prep_pread(struct iocb *iocb, int fd, void *buf, size_t count, long long offset) { memset(iocb, 0, sizeof(*iocb)); iocb->aio_fildes = fd; iocb->aio_lio_opcode = IO_CMD_PREAD; iocb->aio_reqprio = 0; iocb->u.c.buf = buf; iocb->u.c.nbytes = count; iocb->u.c.offset = offset; } static inline void io_prep_pwrite(struct iocb *iocb, int fd, void *buf, size_t count, long long offset) { memset(iocb, 0, sizeof(*iocb)); iocb->aio_fildes = fd; iocb->aio_lio_opcode = IO_CMD_PWRITE; iocb->aio_reqprio = 0; iocb->u.c.buf = buf; iocb->u.c.nbytes = count; iocb->u.c.offset = offset; } #endif int io_setup(int nr_events, io_context_t *ctx_idp) { init(); if (!translate_aio) { return orig_io_setup(nr_events, ctx_idp); } if (nr_events == 0) { return EINVAL; } if (nr_events > 1) { return EAGAIN; } if (ctx_idp == NULL) { return EFAULT; } *ctx_idp = &our_io_context; return 0; } int io_destroy(io_context_t ctx_id) { init(); if (!translate_aio) { return orig_io_destroy(ctx_id); } if (ctx_id != &our_io_context) { return EINVAL; } return 0; } int io_submit(io_context_t ctx_id, long nr, struct iocb *ios[]) { init(); if (!translate_aio) { return orig_io_submit(ctx_id, nr, ios); } if ((pending_iocb != NULL) || (nr > 1)) { return EAGAIN; } if ((nr == 1) && ((ios == NULL) || (ios[0] == NULL))) { return EFAULT; } if ((ctx_id != &our_io_context) || (nr < 0) || ((nr == 1) && (ios[0]->aio_lio_opcode != IO_CMD_PREAD) && (ios[0]->aio_lio_opcode != IO_CMD_PWRITE))) { return EINVAL; } if ((fcntl(ios[0]->aio_fildes, F_GETFD) == -1) && (errno == EBADF)) { return EBADF; } if (nr == 1) { pending_iocb = ios[0]; } return nr; } int io_getevents(io_context_t ctx_id, long min_nr, long nr, struct io_event *events, struct timespec *timeout) { init(); if (!translate_aio) { return orig_io_getevents(ctx_id, min_nr, nr, events, timeout); } if ((ctx_id != &our_io_context) || (min_nr != 1) || (nr != 1)) { return EINVAL; } if (pending_iocb == NULL) { return 0; } switch (pending_iocb->aio_lio_opcode) { case IO_CMD_PWRITE: events->res = pwrite(pending_iocb->aio_fildes, pending_iocb->u.c.buf, pending_iocb->u.c.nbytes, pending_iocb->u.c.offset); break; case IO_CMD_PREAD: events->res = pread(pending_iocb->aio_fildes, pending_iocb->u.c.buf, pending_iocb->u.c.nbytes, pending_iocb->u.c.offset); break; default: events->res = 0; } events->data = pending_iocb->data; events->obj = pending_iocb; events->res2 = 0; pending_iocb = NULL; return 1; } int io_cancel(io_context_t ctx_id, struct iocb *iocb, struct io_event *result) { init(); if (!translate_aio) { return orig_io_cancel(ctx_id, iocb, result); } if (ctx_id != &our_io_context) { return EINVAL; } if ((iocb == NULL) || (result == NULL)) { return EFAULT; } if (pending_iocb != iocb) { return EAGAIN; } result->data = iocb->data; result->obj = iocb; result->res = 0; result->res2 = 0; pending_iocb = NULL; return 0; } // ***** end - aio translate ****