diff options
author | Jean-Pierre Bogler <jean-pierre.bogler@continental-corporation.com> | 2013-10-29 09:30:57 +0100 |
---|---|---|
committer | Jean-Pierre Bogler <jean-pierre.bogler@continental-corporation.com> | 2013-10-29 09:30:57 +0100 |
commit | e8ec4787395986599cc2c816ac2bbe56d3c85764 (patch) | |
tree | 10ea50af26d25cf94da09cf9cf7c80094be94405 | |
download | node-health-monitor-1.3.3.tar.gz |
NodeHealthMonitor version 1.3.3 for initial OSS release1.3.3
47 files changed, 8709 insertions, 0 deletions
@@ -0,0 +1 @@ +Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> @@ -0,0 +1,373 @@ +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..094c1f4 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,32 @@ +23rd Oct 2013 Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * Bugfix for crash at startup. If a service failed before dbus connection was + obtained, a sgementation fault occured in "nhm_main_register_app_status". + * Fixed a bug in "nhm_main_is_process_running" found with Klocwork. + There was a possibility to dereference the uninitialized "error" variable. + * Corrected the systemd watchdog support. Cycle time is now retrieved from + WATCHDOG_USEC environment variable. + * Fixed some Klocwork comments + * Adapted the unit test + +14th Aug 2013 Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * Changed handling of restart_apps + +17th Jun 2013 Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * Introduced systemd observation. + NHM will use systemd dbus interface to recognize failing apps. + * Added internal trace abstraction + * Implemented registration for catching SIGTERM signal + +09th Jul 2013 Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * Call Init/DeInit of PCL to support version 6.0.0 + +15th May 2013 Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * Introduced dbus observation. Added new config. key, adapted source code. + Extended unit test to cover new functionality. + +02nd May 2013 Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * Adapted code to store "shutdown flag" via GENIVI Persistency, + instead of using the file "${datadir}/lib/shutdownflag". + +15th Mar 2013 Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * Initial revision diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..4de7f41 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,21 @@ +################################################################################ +# +# Author: Jean-Pierre.Bogler@continental-corporation.com +# +# Makefile template for the NodeHealthMonitor +# +# Process this file with automake to produce a Makefile.in. +# +# Copyright (C) 2013 Continental Automotive Systems, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# Date Author Reason +# 05th Feb. 2013 Jean-Pierre Bogler Initial revision +# +################################################################################ + +# Build trough subfolders. Make sure "gen" is called before "src" and "tst". +SUBDIRS = cfg gen inc mod src tst
\ No newline at end of file @@ -0,0 +1,38 @@ +1.3.3 +===== +* Two bugfixes for start up and error cases +* Improvement of systemd watchdog support + +1.3.2 +===== +* The handling of "restart_apps" has changed. Before this was a white list. + Only apps on the listed were allowed to restart the target. Now every app + is allowed to request a restart and only those on the list are blocked. + +1.3.1 +===== +* The NHM can now observe failing units via systemd. Furthermore, it catches the +* SIGTERM signal to properly shut down on systemd requests. + +1.2.1 +===== +* Adaption of NHM to the new interface of the persistence client library. + +1.2.0 +===== +* The NHM can now observe the D-Bus. Observed busses can be configured +* as "monitored_dbus" in the conf file. Observation is done by calling +* the "GetId" method of the org.freedesktop.DBus default bus memeber, +* every "ul_chk_interval". + +1.1.0 +===== +* The "shutdown flag" will now be stored via the GENIVI Persistency, +* instead of using the file "${datdir}/lib/shutdownflag" + +1.0.0 +===== +* First release of the NodeHealthMonitor (NHM) +* D-Bus interfaces: All currently specified dbus interfaces are provided +* Userland checks: NHM can check if: files are present, processes are running + and if processes return valid (see node-health-monitor.conf) @@ -0,0 +1,28 @@ +NodeHealthMonitor (NHM) README +================================================================================ + +This is the official source of the NodeHealthMonitor. At present, all +relevant documentation for this project is available in the GENIVI wiki on: + +https://collab.genivi.org/wiki/display/genivi/SysInfraEGLifecycleRequirements + + +License +------- + +For licensing info see the COPYING file, distributed along with this project. + + +Build Dependencies and Instructions +----------------------------------- + +The NodeHealthMonitor needs the following packages installed, to be compiled: + - automotive-dlt >= 2.2.0 + - glib-2.0 >= 2.30.0 + - node-state-manager >= 1.2.0.0 + - persistence_client_library + +Dependencies to "dbus-1" can be solved by passing "--with-dbussystemunitdir" +and "--with-dbusinterfacesdir" to the configure script. +Dependencies to "systemd" can be solved by passing "--with-systemdsystemunitdir" +to the configure script.
\ No newline at end of file diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 0000000..631cb9f --- /dev/null +++ b/autogen.sh @@ -0,0 +1,19 @@ +#!/bin/sh -e +# +# Author: Jean-Pierre.Bogler@continental-corporation.com +# +# Script to create necessary files/folders from a fresh git check out. +# +# Copyright (C) 2013 Continental Automotive Systems, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. +# +# Date Author Reason +# 05th Feb. 2013 Jean-Pierre Bogler Initial creation +# +############################################################################### + +autoreconf --verbose --install --force +./configure $@ diff --git a/cfg/Makefile.am b/cfg/Makefile.am new file mode 100644 index 0000000..dc95903 --- /dev/null +++ b/cfg/Makefile.am @@ -0,0 +1,34 @@ +################################################################################ +# +# Author: Jean-Pierre.Bogler@continental-corporation.com +# +# Makefile template for the node-health-monitor config files +# +# Process this file with automake to produce a Makefile.in. +# +# Copyright (C) 2013 Continental Automotive Systems, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# Date Author Reason +# 05th Feb. 2013 Jean-Pierre Bogler Initial revision +# +################################################################################ + +# Write the package config file of the NHM to it destination +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = node-health-monitor.pc + +# Write the initial config file of the NHM to the config destination +sysconf_DATA = node-health-monitor.conf + +# Write the systemd unit file of the NHM to the related systemd directory +systemdsystemunit_DATA = node-health-monitor.service + +# Write the dbus service file (start NHM on dbus demand) to related dbus path +dbussystemunit_DATA = org.genivi.NodeHealthMonitor.service + +# Add config file to distribution (*.in files were automatically added) +EXTRA_DIST = $(sysconf_DATA) diff --git a/cfg/node-health-monitor.conf b/cfg/node-health-monitor.conf new file mode 100644 index 0000000..39e50ee --- /dev/null +++ b/cfg/node-health-monitor.conf @@ -0,0 +1,50 @@ +################################################################################ +# +# This is the configuration file of the NodeHealthMonitor (NHM). +# All keys are optional. If a key is not configured or set to an +# invalid value, a NHM internal default value will be used. +# +################################################################################ + +[node] + +# Amount of life cycles that are stored by the NHM. Has to be a positive value. +# Set to 0 (NHM default), to only monitor current life cycle. +historic_lc_count = 5 + +# Max. amount of apps. in fail state. If the number of failed apps. exceeds this +# amount, a node restart will be requested. Has to be a positive value. +# Set to 0 (NHM default) to disable restart because of failed apps. +max_failed_apps = 8 + +# Semicolon separated list of apps. for which a restart will be rejected, when +# they call the dbus method 'RequestNodeRestart'. Leave empty (NHM default) to +# allow all apps to initiate restarts. +no_restart_apps = + +[userland] + +# Interval in s, in which NHM performs 'userland' checks. +# Always has to be a positive value. +# Set to 0 (NHM default) to disable userland checks. +ul_chk_interval = 0 + +# Semicolon separated list of files that are observed by the NHM. +# If a configured file can not be found, the NHM resets the system. +# Leave empty (NHM default) to disable restarts because of files. +monitored_files = + +# Semicolon separated list of programs that are observed by the NHM. +# If a configured program is not running, the NHM resets the system. +# Leave empty (NHM default) to disable restarts because of programs. +monitored_progs = + +# Semicolon separated list of processes that are observed by the NHM. +# If the process does not return with 0, the NHM resets the system. +# Leave empty (NHM default) to disable restarts because of processes. +monitored_procs = + +# Semicolon separated list of dbus addresses that are observed by +# the NHM (check if dbus is alive by pinging org.freedesktop.DBus). +# Leave empty to disable (default) restarts because of failed busses. +monitored_dbus =
\ No newline at end of file diff --git a/cfg/node-health-monitor.pc.in b/cfg/node-health-monitor.pc.in new file mode 100644 index 0000000..24dfe9b --- /dev/null +++ b/cfg/node-health-monitor.pc.in @@ -0,0 +1,14 @@ +# Package config file for node-health-monitor + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +dbusinterfacesdir=${pc_sysrootdir}@dbusinterfacesdir@ + +Name: node-health-monitor (NHM) +Description: Package information for the NHM. +URL: http://www.genivi.org +Version: @VERSION@ +Cflags: -I${includedir} diff --git a/cfg/node-health-monitor.service.in b/cfg/node-health-monitor.service.in new file mode 100644 index 0000000..a28ab39 --- /dev/null +++ b/cfg/node-health-monitor.service.in @@ -0,0 +1,15 @@ +# This file is for starting the NHM as a daemon with systemd + +[Unit] +Description=node-health-monitor to observe system health +Requires=nodestatemanager-daemon.service dlt-daemon.service +After=nodestatemanager-daemon.service dlt-daemon.service + +[Service] +Type=notify +ExecStart=@bindir@/node-health-monitor +TimeoutSec=300 +WatchdogSec=20 + +[Install] +WantedBy=basic.target diff --git a/cfg/org.genivi.NodeHealthMonitor.service.in b/cfg/org.genivi.NodeHealthMonitor.service.in new file mode 100644 index 0000000..5279a91 --- /dev/null +++ b/cfg/org.genivi.NodeHealthMonitor.service.in @@ -0,0 +1,6 @@ +# This file is for starting the NHM daemon when it is requested via dbus + +[D-BUS Service] +Name=org.genivi.NodeHealthMonitor +SystemdService=node-health-monitor.service +Exec=/bin/false diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..ee8facf --- /dev/null +++ b/configure.ac @@ -0,0 +1,85 @@ +################################################################################ +# +# Author: Jean-Pierre.Bogler@continental-corporation.com +# +# Configure template for the NodeHealthMonitor +# +# Process this file with autoconf to produce a configure script. +# +# Copyright (C) 2013 Continental Automotive Systems, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +################################################################################ + +# Initialize autoconf +AC_INIT([node-health-monitor], [1.3.3]) +AC_PREREQ([2.50]) +AC_COPYRIGHT([Copyright (c) 2013 Continental Automotive GmbH]) + +# Initialize automake +AM_INIT_AUTOMAKE([tar-ustar]) + +# Check for basic programs +AC_PROG_CC +AM_PROG_CC_C_O +AC_PROG_INSTALL + +# Check for basic headers +AC_CHECK_HEADERS([string.h]) + +# Check for basic types +AC_TYPE_SIZE_T + +# Check for basic functions +AC_CHECK_FUNCS([strtol]) + +# Check for required packages +PKG_CHECK_MODULES([DLT], [automotive-dlt >= 2.2.0 ]) +PKG_CHECK_MODULES([GIO], [gio-2.0 >= 2.30.0 ]) +PKG_CHECK_MODULES([GIO_UNIX], [gio-unix-2.0 >= 2.30.0 ]) +PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.30.0 ]) +PKG_CHECK_MODULES([GOBJECT], [gobject-2.0 >= 2.30.0 ]) +PKG_CHECK_MODULES([DBUS], [dbus-1 >= 1.4.10 ]) +PKG_CHECK_MODULES([SYSTEMD], [libsystemd-daemon >= 187 ]) +PKG_CHECK_MODULES([NSM], [node-state-manager >= 1.2.0.0]) +PKG_CHECK_MODULES([PCL], [persistence_client_library >= 0.6.0 ]) + +# Derive path for storing systemd service files (e. g. /lib/systemd/system) +AC_ARG_WITH([systemdsystemunitdir], + AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]), + [], + [with_systemdsystemunitdir=$(pkg-config --silence-errors --variable=systemdsystemunitdir systemd)]) +AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir]) + +# Derive path for storing 'dbus' service files (e. g. /usr/share/dbus-1/system-services) +AC_ARG_WITH([dbussystemunitdir], + AS_HELP_STRING([--with-dbussystemunitdir=DIR], [Directory for D-Bus system service files]), + [], + [with_dbussystemunitdir=$(pkg-config --silence-errors --variable=session_bus_services_dir dbus-1)]) +AC_SUBST([dbussystemunitdir], [$with_dbussystemunitdir]) + +# Derive path for storing 'dbus' interface files (e. g. /usr/share/dbus-1/interfaces) +AC_ARG_WITH([dbusinterfacesdir], + AS_HELP_STRING([--with-dbusinterfacesdir=DIR], [Directory for D-Bus interface files]), + [], + [with_dbusinterfacesdir=$(pkg-config --silence-errors --variable=interfaces_dir dbus-1)]) +AC_SUBST([dbusinterfacesdir], [$with_dbusinterfacesdir]) + +# Derive path of the NSM dbus xml models +AC_SUBST([nsmdbusinterfacesdir], [$(pkg-config --silence-errors --variable=dbusinterfacesdir node-state-manager)]) + +# Define configure output +AC_CONFIG_FILES([ Makefile + cfg/Makefile + gen/Makefile + inc/Makefile + mod/Makefile + src/Makefile + tst/Makefile + cfg/node-health-monitor.service + cfg/org.genivi.NodeHealthMonitor.service + cfg/node-health-monitor.pc ]) +AC_OUTPUT diff --git a/gen/Makefile.am b/gen/Makefile.am new file mode 100644 index 0000000..a5a4a42 --- /dev/null +++ b/gen/Makefile.am @@ -0,0 +1,51 @@ +################################################################################ +# +# Author: Jean-Pierre.Bogler@continental-corporation.com +# +# Makefile template for the node-health-monitor generated sources +# +# Process this file with automake to produce a Makefile.in. +# +# Copyright (C) 2013 Continental Automotive Systems, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# Date Author Reason +# 05th Feb. 2013 Jean-Pierre Bogler Initial revision +# +################################################################################ + +# List generated sources here to assert that they are available at built start +BUILT_SOURCES = nhm-dbus-info.c \ + nhm-dbus-info.h \ + nsm-dbus-lc-control.c \ + nsm-dbus-lc-control.h \ + nsm-dbus-consumer.c \ + nsm-dbus-consumer.h \ + nsm-dbus-lc-consumer.c \ + nsm-dbus-lc-consumer.h + +# Delete all generated files on 'make clean' +CLEANFILES = nhm-dbus-info.c \ + nhm-dbus-info.h \ + nsm-dbus-lc-control.c \ + nsm-dbus-lc-control.h \ + nsm-dbus-consumer.c \ + nsm-dbus-consumer.h \ + nsm-dbus-lc-consumer.c \ + nsm-dbus-lc-consumer.h + +# Targets to create generated sources during the build +nhm-dbus-info.c nhm-dbus-info.h: $(top_srcdir)/mod/org.genivi.NodeHealthMonitor.Info.xml + gdbus-codegen --interface org.genivi.NodeHealthMonitor. --c-namespace NhmDbus --generate-c-code nhm-dbus-info $(top_srcdir)/mod/org.genivi.NodeHealthMonitor.Info.xml + +nsm-dbus-lc-control.c nsm-dbus-lc-control.h: $(nsmdbusinterfacesdir)/org.genivi.NodeStateManager.LifecycleControl.xml + gdbus-codegen --interface org.genivi.NodeStateManager.Lifecycle --c-namespace NsmDbusLc --generate-c-code nsm-dbus-lc-control $(nsmdbusinterfacesdir)/org.genivi.NodeStateManager.LifecycleControl.xml + +nsm-dbus-consumer.c nsm-dbus-consumer.h: $(nsmdbusinterfacesdir)/org.genivi.NodeStateManager.Consumer.xml + gdbus-codegen --interface org.genivi.NodeStateManager. --c-namespace NsmDbus --generate-c-code nsm-dbus-consumer $(nsmdbusinterfacesdir)/org.genivi.NodeStateManager.Consumer.xml + +nsm-dbus-lc-consumer.c nsm-dbus-lc-consumer.h: $(nsmdbusinterfacesdir)/org.genivi.NodeStateManager.LifecycleConsumer.xml + gdbus-codegen --interface org.genivi.NodeStateManager.LifeCycle --c-namespace NsmDbusLc --generate-c-code nsm-dbus-lc-consumer $(nsmdbusinterfacesdir)/org.genivi.NodeStateManager.LifecycleConsumer.xml
\ No newline at end of file diff --git a/inc/Makefile.am b/inc/Makefile.am new file mode 100644 index 0000000..dae0e2c --- /dev/null +++ b/inc/Makefile.am @@ -0,0 +1,21 @@ +################################################################################ +# +# Author: Jean-Pierre.Bogler@continental-corporation.com +# +# Makefile template for the node-health-monitor +# +# Process this file with automake to produce a Makefile.in. +# +# Copyright (C) 2013 Continental Automotive Systems, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# Date Author Reason +# 05th Feb. 2013 Jean-Pierre Bogler Initial revision +# +################################################################################ + +# Export the header file of the NHM +include_HEADERS = NodeHealthMonitor.h
\ No newline at end of file diff --git a/inc/NodeHealthMonitor.h b/inc/NodeHealthMonitor.h new file mode 100644 index 0000000..e2c0e77 --- /dev/null +++ b/inc/NodeHealthMonitor.h @@ -0,0 +1,73 @@ +#ifndef NODEHEALTHMONITOR_H
+#define NODEHEALTHMONITOR_H
+
+/*******************************************************************************
+*
+* Author: Jean-Pierre.Bogler@continental-corporation.com
+*
+* Header file of the NodeHealthMonitor
+*
+* This header file defines the data types and settings that should be used to
+* communicate to the NHM over D-Bus.
+*
+* Copyright (C) 2013 Continental Automotive Systems, Inc.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public License,
+* v. 2.0. If a copy of the MPL was not distributed with this file, You can
+* obtain one at http://mozilla.org/MPL/2.0/.
+*
+* Date Author Reason
+* 05th Feb. 2013 Jean-Pierre Bogler Initial revision
+*
+*******************************************************************************/
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*
+ * NHM interface version. The lower significant byte is equal 0 for released version only.
+ */
+#define NODEHEALTHMONITOR_INTERFACE_VERSION 0x01000001UL
+
+/*****************************************************************************
+ HEADER FILE INCLUDES
+******************************************************************************/
+
+/*
+ * Module version. The lower significant byte is equal 0 for released version only.
+ */
+#define NHM_INTERFACE_VERSION 0x01000001U
+
+#define NHM_BUS_TYPE 2 /**< Defines bus type according to GBusType */
+#define NHM_BUS_NAME "org.genivi.NodeHealthMonitor" /**< The bus name of the Node Health Monitor */
+#define NHM_INFO_OBJECT "/org/genivi/NodeHealthMonitor" /**< D-Bus object path */
+
+/*****************************************************************************
+ TYPE
+******************************************************************************/
+
+/* This enum will be used to report the status of an application before/after or during a failure */
+typedef enum
+{
+ NhmAppStatus_Failed, /**< Used when an application has failed */
+ NhmAppStatus_Restarting, /**< Used when an application has failed but is in process of being restarted */
+ NhmAppStatus_Ok /**< Used when an application failed but has correctly been restarted */
+} NhmAppStatus_e;
+
+
+/* This enum will be used for indicating the status of method calls */
+typedef enum
+{
+ NhmErrorStatus_Ok, /**< This value will be used to state that the method worked as expected */
+ NhmErrorStatus_Error, /**< This value can be used to state that an error occurred handling the request */
+ NhmErrorStatus_UnknownApp, /**< This value will be set when the passed string does not correspond to a failed application */
+ NhmErrorStatus_RestartNotPossible /**< This value will be used when an application requests a node restart but it is not currently possible */
+} NhmErrorStatus_e;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* NODEHEALTHMONITOR_H */
diff --git a/mod/Makefile.am b/mod/Makefile.am new file mode 100644 index 0000000..421672c --- /dev/null +++ b/mod/Makefile.am @@ -0,0 +1,24 @@ +################################################################################ +# +# Author: Jean-Pierre.Bogler@continental-corporation.com +# +# Makefile template for the node-health-monitor dbus interface +# +# Process this file with automake to produce a Makefile.in. +# +# Copyright (C) 2013 Continental Automotive Systems, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +# Date Author Reason +# 05th Feb. 2013 Jean-Pierre Bogler Initial revision +# +################################################################################ + +# Export the dbus interface descrition of the NHM +dbusinterfaces_DATA = org.genivi.NodeHealthMonitor.Info.xml + +# XML model not automatically delivered in "dist", because there is no *.in file +EXTRA_DIST = $(dbusinterfaces_DATA)
\ No newline at end of file diff --git a/mod/org.genivi.NodeHealthMonitor.Info.xml b/mod/org.genivi.NodeHealthMonitor.Info.xml new file mode 100644 index 0000000..0797296 --- /dev/null +++ b/mod/org.genivi.NodeHealthMonitor.Info.xml @@ -0,0 +1,108 @@ +<!--
+*
+* Copyright (C) 2013 Continental Automotive Systems, Inc.
+*
+* Author: Jean-Pierre.Bogler@continental-corporation.com
+*
+* Describes the "Info" interface of the NodeHealthMonitor
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+*
+* Date Author Reason
+* 05th Feb. 2013 Jean-Pierre Bogler Initial creation
+*
+-->
+
+<node>
+ <!-- org.genivi.NodeHealthMonitor.Info:
+ This is a DBUS interface that is used to interact between interested
+ parties and the Node Health Monitor.
+ -->
+ <interface name="org.genivi.NodeHealthMonitor.Info">
+ <!-- RegisterAppStatus:
+ @AppName: Type='STRING'; Description='This is the unit name of the
+ application that has failed' + @AppStatus: Type='NhmAppStatus_e'; Description='This can be used to
+ specify the status of the application that has failed.
+ It will be based upon the enum NHM_ApplicationStatus_e' +
+ This method will be used by an NHM client to register that an
+ application has failed or recovered from a previous failure.
+ The Node Health Monitor will maintain an internal list of the
+ applications that are currently in a failed state.
+ Additionally it will maintain a count of the currently failed
+ applications that can be used to trigger a system restart if the
+ value gets too high.
+
+ The NHM will also call the NSM method SetAppHealthStatus which will
+ allow the NSM to disable any sessions that might have been enabled
+ by the failed application.
+ -->
+ <method name="RegisterAppStatus">
+ <arg name="AppName" type="s" direction="in" />
+ <arg name="AppStatus" type="i" direction="in" />
+ </method>
+
+ <!-- ReadStatistics:
+ @AppName: Type='STRING'; Description='This will be the name of the
+ application for which the calling application wants to know
+ the failure count for. If this value is an empty string the
+ NHM will return the failure statistics for the whole node' + @CurrentFailCount: Type='UINT32'; Description='This value will be the
+ number of failures that have occurred in this
+ lifecycle' + @TotalFailures: Type='UINT32'; Description='This will be the total
+ number of failures that have occurred in the past X
+ amount of lifecycles. The value of X will be
+ configurable at build time' + @TotalLifecycles: Type='UINT32'; Description='This value will be the
+ number of lifecycles that are being used for the
+ statistics collection (i.e. 5 failures in 8 LCs)' + @ErrorStatus: Type='NhmError_Status_e'; Description='This parameter
+ will be used as a return value' +
+ This method can be used to read the failure count of either a
+ particular application or of the Node itself
+ -->
+ <method name="ReadStatistics">
+ <arg name="AppName" type="s" direction="in" />
+ <arg name="CurrentFailCount" type="u" direction="out" />
+ <arg name="TotalFailures" type="u" direction="out" />
+ <arg name="TotalLifecycles" type="u" direction="out" />
+ <arg name="ErrorStatus" type="i" direction="out" />
+ </method>
+
+ <!-- RequestNodeRestart:
+ @AppName: Type='STRING'; Description='This is the unit name of the
+ application that has failed' + @ErrorStatus: Type='NhmError_Status_e'; Description='This parameter
+ will be used as a return value' +
+ This method can be used by an NHM client to request a node restart if
+ a critical application can not be recovered. The Node Health Monitor
+ will have the possibility to internally evaluate whether the failed
+ application is important enough to warrant the restarting of the node.
+
+ The NHM will then forward the request to the NSM who will evaluate
+ whether a restart is allowed at the current time.
+ -->
+ <method name="RequestNodeRestart">
+ <arg name="AppName" type="s" direction="in" />
+ <arg name="ErrorStatus" type="i" direction="out" />
+ </method>
+
+ <!-- AppHealthStatus:
+ @AppName: Type='STRING' + @AppStatus: Type='AppHealthStatus' +
+ This DBUS signal can be used by a client to be notified about
+ AppHealth status changes
+ -->
+ <signal name="AppHealthStatus">
+ <arg name="AppName" type="s" />
+ <arg name="AppStatus" type="i" />
+ </signal>
+ </interface>
+</node>
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..b6998c5 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,58 @@ +################################################################################ +# +# Author: Jean-Pierre.Bogler@continental-corporation.com +# +# Makefile template for the node-health-monitor +# +# Process this file with automake to produce a Makefile.in. +# +# Copyright (C) 2013 Continental Automotive Systems, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +################################################################################ + +# Program built by the Makefile +bin_PROGRAMS = node-health-monitor + +# Sources that belong to NHM +node_health_monitor_SOURCES = nhm-main.c \ + nhm-systemd.c \ + nhm-systemd.h \ + nhm-helper.c \ + nhm-helper.h \ + $(top_srcdir)/inc/NodeHealthMonitor.h + +# Generated sources that belong to the NHM, but don't have to be distributed +nodist_node_health_monitor_SOURCES = $(top_srcdir)/gen/nhm-dbus-info.c \ + $(top_srcdir)/gen/nhm-dbus-info.h \ + $(top_srcdir)/gen/nsm-dbus-lc-control.c \ + $(top_srcdir)/gen/nsm-dbus-lc-control.h \ + $(top_srcdir)/gen/nsm-dbus-consumer.c \ + $(top_srcdir)/gen/nsm-dbus-consumer.h \ + $(top_srcdir)/gen/nsm-dbus-lc-consumer.c \ + $(top_srcdir)/gen/nsm-dbus-lc-consumer.h + +# C flags to compile NHM +node_health_monitor_CFLAGS = -DCONFDIR=\"$(sysconfdir)/\" \ + -DDATADIR=\"$(localstatedir)/lib/\" \ + -I $(top_srcdir) \ + $(DLT_CFLAGS) \ + $(GIO_CFLAGS) \ + $(GIO_UNIX_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GOBJECT_CFLAGS) \ + $(SYSTEMD_CFLAGS) \ + $(NSM_CFLAGS) \ + $(PCL_CFLAGS) + +# Libraries to be linked in NHM +node_health_monitor_LDADD = $(DLT_LIBS) \ + $(GIO_LIBS) \ + $(GIO_UNIX_LIBS) \ + $(GLIB_LIBS) \ + $(GOBJECT_LIBS) \ + $(SYSTEMD_LIBS) \ + $(PCL_LIBS) diff --git a/src/nhm-helper.c b/src/nhm-helper.c new file mode 100644 index 0000000..dec3784 --- /dev/null +++ b/src/nhm-helper.c @@ -0,0 +1,80 @@ +/* NHM - NodeHealthMonitor + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + */ + +/** + * SECTION: nhm-helper + * @title: NodeHealthMonitor (NHM) helper functions + * @short_description: Functions commonly used by NHM + * + * The section implements common tasks of in NHM in separate functions. + */ + + +/****************************************************************************** +* +* Header includes +* +******************************************************************************/ + +/* Own header files */ +#include "nhm-helper.h" + +/* System header files */ +#include <dlt/dlt.h> /* DLT trace */ +#include <glib-2.0/glib.h> /* Use GTypes */ + + +/****************************************************************************** +* +* Exported global variables and constants +* +******************************************************************************/ + +/* Context for Log'n'Trace */ +DLT_DECLARE_CONTEXT(nhm_helper_trace_ctx); + + +/****************************************************************************** +* +* Interfaces. Exported functions. +* +******************************************************************************/ + +/** + * nhm_helper_str_in_strv: + * @str: String that is searched + * @strv: String array in which to search string + * @return: %TRUE: The string array contains the string. + * %FALSE: String is not in array. + * + * The function checks if a passed string is within the passed string array. + */ +gboolean +nhm_helper_str_in_strv(const gchar *str, + gchar *strv[]) +{ + gboolean retval = FALSE; + guint idx = 0; + + if(strv != NULL) + { + for(idx = 0; (idx < g_strv_length(strv)) && (retval == FALSE); idx++) + { + retval = (g_strcmp0(str, strv[idx]) == 0); + } + } + else + { + retval = FALSE; + } + + return retval; +} diff --git a/src/nhm-helper.h b/src/nhm-helper.h new file mode 100644 index 0000000..d20a08f --- /dev/null +++ b/src/nhm-helper.h @@ -0,0 +1,45 @@ +#ifndef NHM_HELPER_H +#define NHM_HELPER_H + +/* NHM - NodeHealthMonitor + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <dlt/dlt.h> /* DLT traces */ +#include <glib-2.0/glib.h> /* Use GTypes */ + + +/******************************************************************************* +* +* Exported variables +* +*******************************************************************************/ + +/* Export a global trace context that can be used everywhere in NHM */ +DLT_IMPORT_CONTEXT(nhm_helper_trace_ctx); + + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +gboolean nhm_helper_str_in_strv(const gchar *str, + gchar *strv[]); + + +#endif /* NHM_HELPER_H */ diff --git a/src/nhm-main.c b/src/nhm-main.c new file mode 100644 index 0000000..cdf4641 --- /dev/null +++ b/src/nhm-main.c @@ -0,0 +1,2394 @@ +/* NHM - NodeHealthMonitor + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the + * Mozilla Public License, v. 2.0. If a copy of the MPL + * was not distributed with this file, You can obtain + * one at http://mozilla.org/MPL/2.0/. + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + */ + +/** + * SECTION:nhm-main + * @title: NodeHealthMonitor (NHM) + * @short_description: Supervises the node's health + * + * The Node Health Monitor will usually be started by systemd and will interact + * with application plug-ins to inform it that a component has failed in the + * system. He will be responsible for: + * + * - providing an interface with which plug-ins can register failures + * - name of the failing service, used to identify and track failures + * - tracking failure statistics over multiple LCs for system and components + * - name of failing service used to identify/track component failures + * - NHM will maintain a count of the number of failures in the current + * life cycle as well as statistics on number of failures in last X life + * cycles (i.e. 3 failures in last 32 life cycles) + * - observe the life cycle accordingly to catch unexpected system restarts + * - provide an interface for plug-ins to read system/component error counts + * - provide an interface for plug-ins to request a node restart + * + * Additionally the Node Health Monitor will test a number of product defined + * criteria with the aim to ensure that userland is stable and functional. + * It will be able to validate that: + * + * - defined file is present + * - defined processes are still running + * - a user defined process can be executed with an expected result + * - communication on defined dbus (bus address) is possible + * + * If the NHM believes that there is an issue with user land + * then it will initiate a system restart. + */ + +/****************************************************************************** +* +* Header includes +* +******************************************************************************/ + +/* Own header files */ +#include "inc/NodeHealthMonitor.h" +#include "nhm-systemd.h" +#include "nhm-helper.h" + +/* System header files */ +#include <stdio.h> /* FILE, write, read */ +#include <string.h> /* Use strlen */ +#include <stdlib.h> /* Use strtol */ +#include <signal.h> /* Define SIGTERM */ +#include <errno.h> /* Use errno */ +#include <glib-unix.h> /* Catch SIGTERM */ +#include <gio/gio.h> /* GIO for dbus */ +#include <glib-2.0/glib.h> /* GLIB for lists, arrays, etc. */ +#include <dlt/dlt.h> /* DLT Log'n'Trace */ +#include <systemd/sd-daemon.h> /* systemd WDOG */ +#include <NodeStateTypes.h> /* NSM types for dbus comm. */ +#include <persistence_client_library.h> /* Init/DeInit PCL */ +#include <persistence_client_library_key.h> /* Access persistent data */ + + +/* Generated D-Bus interface header files */ +#include <gen/nhm-dbus-info.h> /* Own dbus info interface */ +#include <gen/nsm-dbus-consumer.h> /* Consumer interface of the NSM */ +#include <gen/nsm-dbus-lc-control.h> /* LC Control interface of the NSM */ +#include <gen/nsm-dbus-lc-consumer.h> /* LC Consumer interface of the NSM */ + + +/****************************************************************************** +* +* Constants, types and defines +* +******************************************************************************/ + +/* File to manage data */ +#define NHM_LC_DATA_FILE (DATADIR"lcdata") + +/* Persistence IDs to manage shutdown flag */ +#define NHM_SHUTDOWN_FLAG_LDBID 0xFF +#define NHM_SHUTDOWN_FLAG_NAME "PKV_NHM_SHUTDOWN_FLAG" + +/* File to load config from (flag 'CONFDIR' comes from Makefile) */ +#define NHM_CFG_FILE (CONFDIR"node-health-monitor.conf") + +/* Definitions for NSM connection */ +#define NHM_LC_CLIENT_OBJ "/org/genivi/NodeHealthMonitor/LifecycleClient" +#define NHM_LC_CLIENT_TIMEOUT 1000 + +/** + * NhmNodeState: + * @NHM_NODESTATE_NOTSET: Default value to init. variables. + * @NHM_NODESTATE_STARTED: NHM writes this value when it starts. + * @NHM_NODESTATE_SHUTDOWN: NHM writes this value when it is shut down. + * + * NhmNodeState is used to determine if the system has been shut down correctly. + */ +typedef enum +{ + NHM_NODESTATE_NOTSET, + NHM_NODESTATE_STARTED, + NHM_NODESTATE_SHUTDOWN +} NhmNodeState; + +/** + * NhmCurrentFailedApp: + * @name: Name of the failed app. + * + * Info for currently failed app, used to create list of currently failed apps + */ +typedef struct +{ + gchar *name; +} NhmCurrentFailedApp; + +/** + * NhmFailedApp: + * @name: Name of the failed app. + * @failcount: Number of times, the app. switched from running to failed. + * + * Info for a failed app, used to create list of failed apps in a LC. + */ +typedef struct +{ + gchar *name; + guint failcount; +} NhmFailedApp; + +/** + * NhmLcInfo: + * @start_state: State which was found in flag file, when NHM started. + * @failed_apps: List of failed apps in the LC. + * + * Info for a LC. Used to create an array with info. for multiple LCs. + */ +typedef struct +{ + NhmNodeState start_state; + GSList *failed_apps; +} NhmLcInfo; + +/** + * NhmMonitoredDbus: + * @bus_addr: Bus address of the observed dbus. + * @bus_conn: Connection to bus, created at startup. + * + * Used to create an array of monitored busses, based on the config. + */ +typedef struct +{ + gchar *bus_addr; + GDBusConnection *bus_conn; +} NhmCheckedDbus; + +/****************************************************************************** +* +* Prototypes for file local functions (see implementation for description) +* +******************************************************************************/ + +/* Functions to free occupied memory */ +static void nhm_main_free_lc_info (gpointer lc_info); +static void nhm_main_free_failed_app (gpointer failed_app); +static void nhm_main_free_current_failed_app (gpointer failed_app); +static void nhm_main_free_checked_dbus (gpointer checked_dbus); +static void nhm_main_free_nhm_objects (void); +static void nhm_main_free_nsm_objects (void); +static void nhm_main_free_config_objects (void); +static void nhm_main_free_check_objects (void); + +/* Functions to find apps. */ +static NhmFailedApp *nhm_main_find_failed_app (NhmLcInfo *lc_info, + const gchar *search_app); +static NhmCurrentFailedApp *nhm_main_find_current_failed_app (const gchar *search_app); + +/* Helper functions for dbus callbacks */ +static void nhm_main_check_failed_app_restart (void); +static NhmErrorStatus_e nhm_main_request_restart (NsmRestartReason_e restart_reason, + guint restart_type); +static void nhm_main_register_app_status (const gchar *name, + NhmAppStatus_e status); + +/* Callbacks for D-Bus interfaces */ +static gboolean nhm_main_read_statistics_cb (NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + const gchar *app_name, + gpointer user_data); +static gboolean nhm_main_register_app_status_cb (NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + const gchar *app_name, + gint app_status, + gpointer user_data); +static gboolean nhm_main_request_node_restart_cb (NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + const gchar *app_name, + gpointer user_data); +static gboolean nhm_main_lc_request_cb (NsmDbusLcConsumer *object, + GDBusMethodInvocation *invocation, + const guint shutdown_type, + const guint request_id, + gpointer user_data); +/* Watchdog and other callbacks */ +static void nhm_main_start_wdog (void); +static gboolean nhm_main_timer_wdog_cb (gpointer user_data); +static gboolean nhm_main_on_sigterm (gpointer user_data); + +/* Bus connection functions and callbacks */ +static gboolean nhm_main_connect_to_nsm (void); +static void nhm_main_bus_acquired_cb (GDBusConnection *connection, + const gchar *bus_name, + gpointer user_data); +static void nhm_main_name_acquired_cb (GDBusConnection *connection, + const gchar *bus_name, + gpointer user_data); +static void nhm_main_name_lost_cb (GDBusConnection *connection, + const gchar *bus_name, + gpointer user_data); + +/* Functions for userland checks */ +static gboolean nhm_does_file_exist (gchar *file_name); +static gboolean nhm_main_is_process_running (gchar *prog); +static gboolean nhm_main_is_process_ok (gchar *process); +static gboolean nhm_main_is_dbus_alive (NhmCheckedDbus *checked_dbus); +static gboolean nhm_main_timer_userland_check_cb (gpointer user_data); + +/* Functions to read and write run time data */ +static void nhm_main_write_data (void); +static void nhm_main_read_data (void); +static NhmNodeState nhm_main_read_shutdown_flag (void); +static gboolean nhm_main_write_shutdown_flag (NhmNodeState flagval); + +/* Functions to import and process configuration */ +static void nhm_main_load_config (void); +static guint nhm_main_config_load_uint (GKeyFile *file, + gchar *group, + gchar *key, + guint defval); +static gchar **nhm_main_config_load_string_array (GKeyFile *file, + gchar *group, + gchar *key, + gchar **defval); +static void nhm_main_prepare_checks (void); + + +/****************************************************************************** +* +* Local variables and constants +* +******************************************************************************/ + +/* Skeleton and proxy objects and connection for D-Bus */ +static GDBusConnection *nsmbusconn = NULL; +static NsmDbusConsumer *dbus_consumer_obj = NULL; +static NsmDbusLcControl *dbus_lc_control_obj = NULL; +static NhmDbusInfo *dbus_nhm_info_obj = NULL; +static NsmDbusLcConsumer *dbus_lc_consumer_obj = NULL; + +/* Variables to control the main loop */ +static gint mainreturn = 0; +static GMainLoop *mainloop = NULL; + +/* Run time data. Array for life cycles and list for the current LC */ +static GPtrArray *nodeinfo = NULL; +static GSList *current_failed_apps = NULL; + +/* Variables to handle configured checks */ +static GPtrArray *checked_dbusses = NULL; + +/* Variables to read the configuration */ +static gchar **no_restart_apps = NULL; +static guint max_lc_count = 0; +static guint max_failed_apps = 0; + +static guint ul_chk_interval = 0; +static gchar **monitored_files = NULL; +static gchar **monitored_procs = NULL; +static gchar **monitored_progs = NULL; +static gchar **monitored_dbus = NULL; + + +/****************************************************************************** +* +* Local (static) functions +* +******************************************************************************/ + +/** + * nhm_main_free_checked_dbus: + * @checked_dbus: Pointer to 'NhmCheckedDbus' object. + * + * Frees the memory occupied by a 'NhmCheckedDbus' object. + * It is used as 'free func' for the array 'checked_dbusses'. + * + */ +static void +nhm_main_free_checked_dbus(gpointer checked_dbus) +{ + NhmCheckedDbus *bus = (NhmCheckedDbus*) checked_dbus; + + g_free(bus->bus_addr); + + if(bus->bus_conn != NULL) + { + g_object_unref(bus->bus_conn); + } + + g_free(checked_dbus); +} + +/** + * nhm_main_free_current_failed_app: + * @failed_app: Pointer to 'NhmCurrentFailedApp' object. + * + * Frees the memory occupied by a 'NhmCurrentFailedApp' object. + * Can be used in 'g_slist_free_full' to free list of current failed apps. + * + */ +static void +nhm_main_free_current_failed_app(gpointer failed_app) +{ + g_free(((NhmCurrentFailedApp*) failed_app)->name); + g_free(failed_app); +} + + +/** + * nhm_main_free_failed_app: + * @failed_app: Pointer to 'NhmFailedApp' object. + * + * Frees the memory occupied by a 'NhmFailedApp' object. + * Can be used in 'g_slist_free_full' to free the list of failed apps. + */ +static void +nhm_main_free_failed_app(gpointer failed_app) +{ + g_free(((NhmFailedApp*) failed_app)->name); + g_free(failed_app); +} + + +/** + * nhm_main_free_lc_info: + * @lcinfo: Pointer to 'NhmLcInfo' object. + * + * Frees the memory occupied by a 'NhmLcInfo' object. + * It is used as 'free func' for the array 'nodeinfo'. + */ +static void +nhm_main_free_lc_info(gpointer lcinfo) +{ + g_slist_free_full(((NhmLcInfo*) lcinfo)->failed_apps, + &nhm_main_free_failed_app); + g_free(lcinfo); +} + + +/** + * nhm_main_find_failed_app: + * @lcinfo: Pointer to the life cycle in which the app. should be searched. + * @appname: Name of the app. that is searched for. + * + * The function searches in the failed app. list + * of the passed LC for an app. with the passed name. + * + * Return value: Ptr. to the app. info of searched app. + * %NULL if the app. is not found. + */ +static NhmFailedApp* +nhm_main_find_failed_app(NhmLcInfo *lcinfo, + const gchar *appname) +{ + GSList *list = NULL; + NhmFailedApp *app = NULL; + + /* Loop through the list of failed apps. until app is found or list ends */ + for(list = lcinfo->failed_apps; + (list != NULL) && (app == NULL); + list = g_slist_next(list)) + { + /* App. found, if the app. name of the stored object equals passed name */ + app = (g_strcmp0(((NhmFailedApp*) list->data)->name, appname) == 0) + ? (NhmFailedApp*) list->data : NULL; + } + + return app; +} + + +/** + * nhm_main_find_current_failed_app: + * @appname: Name of the app. that is searched for. + * + * Searches in the currently failed app. list for an app. with the passed name. + * + * Return value: Pointer to the current failed app. info. + * of the searched app. or %NULL if app. is not found. + */ +static NhmCurrentFailedApp* +nhm_main_find_current_failed_app(const gchar *appname) +{ + GSList *list = NULL; + NhmCurrentFailedApp *app = NULL; + + /* Loop through currently failed apps. until app is found or list ends */ + for(list = current_failed_apps; + (list != NULL) && (app == NULL); + list = g_slist_next(list)) + { + app = (g_strcmp0(((NhmCurrentFailedApp*) list->data)->name, appname) == 0) + ? (NhmCurrentFailedApp*) list->data : NULL; + } + + return app; +} + + +/** + * nhm_main_request_restart: + * @restart_reason: Reason for the restart request + * @restart_type: Type of the desired restart (NSM_SHUTDOWNTYPE_*) + * + * The function is called from 'nhm_main_check_failed_app_restart' + * and 'nhm_main_request_node_restart_cb' if a node restart should be + * requested at the NSM. + * + * Return value: + * + * NhmErrorStatus_Ok: NSM accepted the restart request. + * Restart should be ongoing. + * NhmErrorStatus_RestartNotPossible: NSM rejected the restart request. + * NhmErrorStatus_Error: Could not communicate to NSM via D-Bus. + */ +static NhmErrorStatus_e +nhm_main_request_restart(NsmRestartReason_e restart_reason, + guint restart_type) +{ + NhmErrorStatus_e retval = NhmErrorStatus_Error; + NsmErrorStatus_e nsm_retval = NsmErrorStatus_NotSet; + GError *error = NULL; + + /* Trace message and send restart request to NSM */ + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Sending restart request to NSM."); + DLT_STRING("RestartReason:"); DLT_INT(restart_reason); + DLT_STRING("RestartType:" ); DLT_UINT(restart_type )); + + (void) nsm_dbus_lc_control_call_request_node_restart_sync(dbus_lc_control_obj, + (gint) restart_reason, + restart_type, + (gint*) &nsm_retval, + NULL, + &error); + if(error == NULL) /* Evaluate the calls result. */ + { + if(nsm_retval == NsmErrorStatus_Ok) + { + retval = NhmErrorStatus_Ok; /* The NSM accepted the RestartRequest */ + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: NSM accepted the restart request.")); + } + else + { + retval = NhmErrorStatus_RestartNotPossible; /* The NSM rejected the RestartRequest */ + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: NSM rejected the restart request."); + DLT_STRING("Return value:"); DLT_INT(nsm_retval)); + } + } + else + { + /* Error: D-Bus communication failed. */ + retval = NhmErrorStatus_Error; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Sending restart request to NSM failed."); + DLT_STRING("Error: D-Bus communication to NSM failed."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + + return retval; +} + + +/** + * nhm_main_check_failed_app_restart: + * + * The function is called from 'nhm_main_register_app_status_cb' whenever + * an application failed. It determines the number of failed applications + * in the current LC. If the number is higher than the configured value, + * the function requests a node restart at the NSM. + */ +static void +nhm_main_check_failed_app_restart(void) +{ + guint failed_app_cnt = 0; + + /* If the failed app. observation is active */ + if(max_failed_apps != 0) + { + /* Get the amount of currently failed apps. and compare to the max. value */ + failed_app_cnt = (current_failed_apps != NULL) + ? g_slist_length(current_failed_apps) : 0; + + if(failed_app_cnt >= max_failed_apps) + { + /* The amount of failed applications is too high. Request a node restart. */ + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Amount of failed apps too high."); + DLT_STRING("FailCount:"); DLT_UINT(failed_app_cnt); + DLT_STRING("Limit:" ); DLT_UINT(max_failed_apps)); + + (void) nhm_main_request_restart(NsmRestartReason_ApplicationFailure, + NSM_SHUTDOWNTYPE_NORMAL); + } + } +} + + +/** + * nhm_main_read_statistics_cb: + * @object: Pointer to NhmDbusInfo object + * @invocation: Pointer to D-Bus invocation of this call + * @app_name: This will be the name of the application for which the calling + * application wants to know the failure count for. If this value + * is an empty string the NHM will return the failure statistics + * for the whole node. + * @user_data: Pointer to optional user data + * + * This function is called from dbus to read the failure count of either a + * particular app. or of the node itself. Returns the following values on dbus: + * + * CurrentFailCount: If there is an app. name: + * How many times the app has failed in the current lifecycle + * If app. name is empty: + * How many apps currently 'failed' in the current lifecycle + * + * TotalFailures: If there is an app. name: + * Number of times that app has failed in the last X LCs. + * If app. name is empty: + * Number of times node failed to shutdown in the last X LCs. + * + * TotalLifecycles: Number of lifecycles used to collect data. + * + * Return value: Always %TRUE. Method has been processed. + */ +static gboolean +nhm_main_read_statistics_cb(NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + const gchar *app_name, + gpointer user_data) +{ + guint lc_idx = 0; + NhmLcInfo *lc_info = NULL; + NhmFailedApp *app_info = NULL; + guint current_fail_cnt = 0; + guint total_failures = 0; + + /* Check if the node statistics should be retrieved (empty AppName) */ + if(strlen(app_name) == 0) + { + /* Node statistics requested. Store number of currently failed apps. */ + current_fail_cnt = (current_failed_apps != NULL) + ? g_slist_length(current_failed_apps) : 0; + + /* Loop through all life cycles and sum up failed shut downs */ + for(lc_idx = 0; (lc_idx < nodeinfo->len) && (lc_idx <= max_lc_count); lc_idx++) + { + lc_info = (NhmLcInfo*) g_ptr_array_index(nodeinfo, lc_idx); + total_failures += (lc_info->start_state != NHM_NODESTATE_SHUTDOWN) ? 1 : 0; + } + } + else + { + /* App. statistics requested. Get fail count for app. in current LC */ + lc_info = (NhmLcInfo*) g_ptr_array_index(nodeinfo, 0); + app_info = nhm_main_find_failed_app(lc_info, app_name); + current_fail_cnt = (app_info != NULL) ? app_info->failcount : 0; + + /* Init. total fail cnt with current fail cnt. Add fail cnt of previous LCs */ + total_failures = current_fail_cnt; + for(lc_idx = 1; (lc_idx < nodeinfo->len) && (lc_idx <= max_lc_count); lc_idx++) + { + lc_info = (NhmLcInfo*) g_ptr_array_index(nodeinfo, lc_idx); + app_info = nhm_main_find_failed_app(lc_info, app_name); + total_failures += (app_info != NULL) ? app_info->failcount : 0; + } + } + + /* Complete D-Bus call. Send return to D-Bus caller. */ + nhm_dbus_info_complete_read_statistics(object, + invocation, + current_fail_cnt, + total_failures, + lc_idx, + (gint) NhmErrorStatus_Ok); + + return TRUE; +} + + + +/** + * nhm_main_register_app_status: + * @name: This is the unit name of the application that has failed + * @status: This can be used to specify the status of the application that has failed. + * It will be based upon the enum NHM_ApplicationStatus_e. + * + * The function is called via the dbus interface or from the systemd + * observation when either a NHM client wants to register a failed app. + * or the state of a systemd unit changed. The NHM will maintain an internal + * list of the applications that are currently in a failed state. + * Additionally it will maintain a count of the currently failed applications + * that can be used to trigger a system restart if the value gets too high. + * The NHM will also call the NSM method SetAppHealthStatus which will allow + * the NSM to disable any sessions that might have been enabled by the failed + * application and send out the signal 'AppHealthStatus'. + */ +static void +nhm_main_register_app_status(const gchar *name, + NhmAppStatus_e status) +{ + GError *error = NULL; + NsmErrorStatus_e nsm_rval = NsmErrorStatus_NotSet; + NhmLcInfo *lc_info = NULL; + NhmFailedApp *app_info = NULL; + NhmCurrentFailedApp *app_on_list = NULL; + gboolean app_running = FALSE; + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Processing 'RegisterAppStatus' call"); + DLT_STRING("AppName:"); DLT_STRING(name), + DLT_STRING("Status:"); DLT_INT(status)); + + /* Forward the call to the NSM who will process it for its own purposes. */ + app_running = (status == NhmAppStatus_Ok); + (void) nsm_dbus_lc_control_call_set_app_health_status_sync(dbus_lc_control_obj, + name, + app_running, + (gint*) &nsm_rval, + NULL, + &error); + if(error != NULL) /* Check for D-Bus errors */ + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to forward app. status to NSM."); + DLT_STRING("Error: D-Bus communication to NSM failed."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + + /* Transparently emit 'AppStatus' signal */ + nhm_dbus_info_emit_app_health_status(dbus_nhm_info_obj, name, status); + + /* Start internal processing. Check if app. is on current failed list. */ + app_on_list = nhm_main_find_current_failed_app(name); + + if((app_on_list == NULL) && (status == NhmAppStatus_Failed)) + { + /* App. not on list and the new status is failed. Add it to the list! */ + app_on_list = g_new(NhmCurrentFailedApp, 1); + app_on_list->name = g_strdup(name); + current_failed_apps = g_slist_append(current_failed_apps, app_on_list); + + /* Try to get the app. in the list of failed apps. of the current LC */ + lc_info = (NhmLcInfo*) g_ptr_array_index(nodeinfo, 0); + app_info = nhm_main_find_failed_app(lc_info, name); + + if(app_info == NULL) + { + /* Failed app has not been on list. Init. error count with 1 and add it */ + app_info = g_new(NhmFailedApp, 1); + app_info->name = g_strdup(name); + app_info->failcount = 0; + lc_info->failed_apps = g_slist_append(lc_info->failed_apps, app_info); + } + + app_info->failcount++; /* increase fail count (either of old or new app.) */ + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Updated error count for application."); + DLT_STRING("AppName:"); DLT_STRING(app_info->name); + DLT_STRING("Fail count:"); DLT_UINT(app_info->failcount)); + + nhm_main_write_data(); + nhm_main_check_failed_app_restart(); + } + else + { + /* The app is on the list, but not failed anymore. Remove it! */ + if((app_on_list != NULL) && (status != NhmAppStatus_Failed)) + { + nhm_main_free_current_failed_app(app_on_list); + current_failed_apps = g_slist_remove(current_failed_apps, app_on_list); + } + } +} + + +/** + * nhm_main_register_app_status_cb: + * @object: Pointer to NhmDbusInfo object + * @invocation: Pointer to D-Bus invocation of this call + * @app_name: This is the unit name of the application that has failed. + * @app_status: This can be used to specify the status of the application + * that has failed. + * It will be based upon the enum NHM_ApplicationStatus_e. + * @user_data: Pointer to optional user data + * + * This function is called from dbus when a NHM client wants to register + * that an application has failed or recovered from a previous failure. + * + * Return value: Always %TRUE. Method has been processed. + */ +static gboolean +nhm_main_register_app_status_cb(NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + const gchar *app_name, + gint app_status, + gpointer user_data) +{ + + nhm_main_register_app_status(app_name, (NhmAppStatus_e) app_status); + nhm_dbus_info_complete_register_app_status(object, invocation); + + return TRUE; +} + + +/** + * nhm_main_request_node_restart_cb: + * @object: Pointer to NhmDbusInfo object + * @invocation: Pointer to D-Bus invocation of this call + * @app_name: This is the unit name of the application that has failed. + * @user_data: Pointer to optional user data + * + * This function is called from dbus when a NHM client wants to request a + * node restart if a critical application can not be recovered. The NHM + * will have the possibility to internally evaluate whether the failed + * application is important enough to warrant the restarting of the node. + * The NHM will then forward the request to the NSM who will evaluate + * whether a restart is allowed at the current time. + * + * Return value: Always %TRUE. Method has been processed. + */ +static gboolean +nhm_main_request_node_restart_cb(NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + const gchar *app_name, + gpointer user_data) +{ + NhmErrorStatus_e retval = NhmErrorStatus_Error; + + /* Check if the app. is on the black list "no_restart_apps" */ + if(nhm_helper_str_in_strv(app_name, no_restart_apps) == FALSE) + { + /* The app is not on the black list. Forward the request to the NSM. */ + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Restart request from app. accepted."); + DLT_STRING("AppName:"); DLT_STRING(app_name)); + + retval = nhm_main_request_restart(NsmRestartReason_ApplicationFailure, + NSM_SHUTDOWNTYPE_NORMAL); + } + else + { + /* The app is on the black list (no_restart_apps). Return an error. */ + retval = NhmErrorStatus_RestartNotPossible; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Restart request from app. rejected."); + DLT_STRING("AppName:"); DLT_STRING(app_name)); + } + + /* Complete D-Bus call. Send return to D-Bus caller. */ + nhm_dbus_info_complete_request_node_restart(object, + invocation, + (gint) retval); + + return TRUE; +} + + +/** + * nhm_does_file_exist: + * @file_name: The full path to a file + * + * Tests if a file exists. + * + * Return value: If the file exists %TRUE, otherwise %FALSE. + */ +static gboolean +nhm_does_file_exist(gchar* file_name) +{ + return g_file_test(file_name, G_FILE_TEST_EXISTS); +} + + +/** + * nhm_main_is_process_running: + * @process: Full path to the executable of the process + * + * The function checks if a process is running (process info in '/proc'). + * + * Return value: %TRUE, if process is currently running, + * otherwise %FALSE; + */ +static gboolean +nhm_main_is_process_running(gchar* prog) +{ + GDir *root_dir = NULL; + const gchar *proc_dir = NULL; + gchar *exe_link = NULL; + gchar *prog_name = NULL; + gboolean found_prog = FALSE; + GError *error = NULL; + + /* Open 'proc' directory in rootfs */ + root_dir = g_dir_open("/proc/", 0, &error); + + if(error == NULL) + { + /* Proc directory opened. Check every file/folder inside */ + for(proc_dir = g_dir_read_name(root_dir); + (proc_dir != NULL) && (found_prog == FALSE); + proc_dir = g_dir_read_name(root_dir)) + { + /* For every file/folder in 'proc' create path to exe link */ + exe_link = g_strconcat("/proc/", proc_dir, "/exe", NULL); + + /* Check if 'exe' link points to searched executable */ + prog_name = g_file_read_link(exe_link, NULL); + if(prog_name != NULL) + { + found_prog = (g_strcmp0(prog_name, prog) == 0); + g_free(prog_name); + } + + g_free(exe_link); + } + + g_dir_close(root_dir); + } + else + { + /* 'proc' directory could not be opened. Return an error. */ + found_prog = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Program check failed. Proc folder not readable."); + DLT_STRING("Error: Proc folder not readable."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + + return found_prog; +} + + +/** + * nhm_main_is_process_ok: + * @process: Full path to the executable of the process + * + * The function checks if a user defined process returns valid (0). + * + * Return value: %TRUE, if process is returned with 0, otherwise %FALSE; + */ +static gboolean +nhm_main_is_process_ok(gchar *process) +{ + gchar *argv[] = {process, NULL}; + GError *error = NULL; + gint proc_retval = 0; + gboolean proc_ok = FALSE; + + /* Start the process.*/ + (void) g_spawn_sync(NULL, + argv, + NULL, + G_SPAWN_STDOUT_TO_DEV_NULL|G_SPAWN_STDERR_TO_DEV_NULL, + NULL, + NULL, + NULL, + NULL, + &proc_retval, + &error); + + /* Check for errors of prg execution. */ + if(error == NULL) + { + /* Prog. executed. Check that return value is '0' */ + proc_ok = (proc_retval == 0); + } + else + { + /* Prog. execution failed. */ + proc_ok = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Process check failed."); + DLT_STRING("Error: Monitored process not started."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + + return proc_ok; +} + + +/** + * nhm_main_is_dbus_alive: + * @checked_dbus: Observed bus, created at startup. + * + * The function checks if a user defined dbus exists (bus address valid) + * and if there is response when calling "Ping" on org.freedesktop.DBus. + * + * Return value: %TRUE, if checks succeed, otherwise %FALSE; + */ +static gboolean +nhm_main_is_dbus_alive(NhmCheckedDbus *checked_dbus) +{ + GError *error = NULL; + GVariant *dbus_return = NULL; + gboolean retval = FALSE; + + /* Step 1: Check if connection already was opened. If not, open it */ + if(checked_dbus->bus_conn == NULL) + { + checked_dbus->bus_conn = g_dbus_connection_new_for_address_sync(checked_dbus->bus_addr, + G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT + | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, + NULL, + NULL, + &error); + if(error == NULL) + { + retval = TRUE; + g_dbus_connection_set_exit_on_close(checked_dbus->bus_conn, FALSE); + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: D-Bus observation failed."); + DLT_STRING("Error: Failed to connect to observed bus."); + DLT_STRING("Bus address:"); DLT_STRING(checked_dbus->bus_addr); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + else + { + retval = TRUE; + } + + /* Step 2: If there is an open conn., call method of default dbus object */ + if(retval == TRUE) + { + dbus_return = g_dbus_connection_call_sync(checked_dbus->bus_conn, + "org.freedesktop.DBus", + "/org/freedesktop/DBus", + "org.freedesktop.DBus", + "GetId", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if(error == NULL) + { + retval = TRUE; + g_variant_unref(dbus_return); + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: D-Bus observation failed."); + DLT_STRING("Error: Failed to call dbus method."); + DLT_STRING("Bus address:"); DLT_STRING(checked_dbus->bus_addr); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + + return retval; +} + + +/** + * nhm_main_start_wdog: + * + * The function reads the watchdog timeout value from the environment and starts + * a cyclic timer if a timeout is configured. + */ +static void +nhm_main_start_wdog(void) +{ + const gchar *wdog_str_us = NULL; + gchar *endptr = NULL; + guint64 wdog_us = 0; + guint wdog_ms = 0; + + wdog_str_us = g_getenv("WATCHDOG_USEC"); + + if(wdog_str_us != NULL) + { + errno = 0; + wdog_us = g_ascii_strtoull(wdog_str_us, &endptr, 10); + + if( (*endptr == '\0' ) /* Parsed to end of string */ + && (endptr != wdog_str_us) /* String was not empty */ + && (errno == 0 )) /* No error (overflow) set */ + { + wdog_us /= 2000; /* convert us to ms and get half timeout */ + wdog_ms = (wdog_us > G_MAXUINT) ? G_MAXUINT : (guint) wdog_us; + + (void) g_timeout_add(wdog_ms, &nhm_main_timer_wdog_cb, NULL); + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Started watchdog timer."); + DLT_STRING("Cycle:"); DLT_UINT(wdog_ms); DLT_STRING("ms")); + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Watchdog initialization failed."); + DLT_STRING("Error: Failed to parse WATCHDOG_USEC."); + DLT_STRING("Value:"); DLT_STRING(wdog_str_us)); + } + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_WARN, + DLT_STRING("NHM: Watchdog timeout not configured.")); + } +} + + +/** + * nhm_main_timer_wdog_cb: + * @user_data: Optional user data + * + * The function is a timer callback, used to trigger the watchdog periodically. + * + * Return value: Always %TRUE to keep timer for callback alive. + */ +static gboolean +nhm_main_timer_wdog_cb(gpointer user_data) +{ + (void) sd_notify(0, "WATCHDOG=1"); + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Triggered systemd WDOG.")); + + return TRUE; +} + + +/** + * nhm_main_timer_userland_check_cb: + * @user_data: Optional user data + * + * The function is a timer callback, called periodically to perform 'userland' + * checks. If a user land check fails, the function resets the system! + * + * Return value: Always %TRUE to keep timer for callback alive. + */ +static gboolean +nhm_main_timer_userland_check_cb(gpointer user_data) +{ + guint check_idx = 0; + gboolean ul_ok = TRUE; + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Userland check started.")); + + /* Check if monitored files exist */ + if(monitored_files != NULL) + { + for(check_idx = 0; + (check_idx < g_strv_length(monitored_files)) && (ul_ok == TRUE); + check_idx++) + { + ul_ok = nhm_does_file_exist(monitored_files[check_idx]); + } + + if(ul_ok == FALSE) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Userland check failed."); + DLT_STRING("Reason: Monitored file does not exist."); + DLT_STRING("File name:"); + DLT_STRING(monitored_files[check_idx - 1])); + } + } + + /* Check if monitored programs re running */ + if(ul_ok == TRUE) + { + if(monitored_progs != NULL) + { + for(check_idx = 0; + (check_idx < g_strv_length(monitored_progs)) && (ul_ok == TRUE); + check_idx++) + { + ul_ok = nhm_main_is_process_running(monitored_progs[check_idx]); + } + + if(ul_ok == FALSE) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Userland check failed."); + DLT_STRING("Reason: Monitored program not running."); + DLT_STRING("Prog name:"); + DLT_STRING(monitored_progs[check_idx - 1])); + } + } + } + + /* Check if monitored processes return valid */ + if(ul_ok == TRUE) + { + if(monitored_procs != NULL) + { + for(check_idx = 0; + (check_idx < g_strv_length(monitored_procs)) && (ul_ok == TRUE); + check_idx++) + { + ul_ok = nhm_main_is_process_ok(monitored_procs[check_idx]); + } + + if(ul_ok == FALSE) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Userland check failed."); + DLT_STRING("Reason: Monitored proc. returned invalid."); + DLT_STRING("Proc name:"); + DLT_STRING(monitored_procs[check_idx - 1])); + } + } + } + + /* Check if monitored dbusses are alive */ + if(ul_ok == TRUE) + { + if(checked_dbusses != NULL) + { + for(check_idx = 0; + (check_idx < checked_dbusses->len) && (ul_ok == TRUE); + check_idx++) + { + if(nhm_main_is_dbus_alive((NhmCheckedDbus*) + g_ptr_array_index(checked_dbusses, check_idx)) == FALSE) + { + ul_ok = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Userland check failed."); + DLT_STRING("Reason: Monitored dbus returned invalid."); + DLT_STRING("Bus name:"); + DLT_STRING(((NhmCheckedDbus*) + g_ptr_array_index(checked_dbusses, check_idx))->bus_addr)); + } + } + } + } + + /* Print outcome of userland check */ + if(ul_ok == TRUE) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Userland check successfully finished.")); + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Userland check failed. Restarting system.")); + } + + return TRUE; +} + + +/** + * nhm_main_lc_request_cb: + * @object: NSM LifecycleConsumer object + * @invocation: Invocation object of dbus + * @shutdown_type: Type of the shut down (NSM_SHUTDOWN_TYPE_*) + * @request_id: ID of shut down request. Used for async. completion call + * @user_data: Optionally user data + * + * The function is a dbus callback, called by the NSM to shut down the system. + * Because NHM usually is the last 'shutdown client', write the shut down flag. + * + * Return value: Always %TRUE to inform dbus that call has been processed. + */ +static gboolean +nhm_main_lc_request_cb(NsmDbusLcConsumer *object, + GDBusMethodInvocation *invocation, + const guint shutdown_type, + const guint request_id, + gpointer user_data) +{ + NsmErrorStatus_e error = NsmErrorStatus_NotSet; + + if(shutdown_type != NSM_SHUTDOWNTYPE_RUNUP) + { + error = (nhm_main_write_shutdown_flag(NHM_NODESTATE_SHUTDOWN) == TRUE) + ? NsmErrorStatus_Ok : NsmErrorStatus_Error; + } + else + { + error = (nhm_main_write_shutdown_flag(NHM_NODESTATE_STARTED) == TRUE) + ? NsmErrorStatus_Ok : NsmErrorStatus_Error; + } + + /* Inform NSM that shut down request was successfully processed */ + nsm_dbus_lc_consumer_complete_lifecycle_request(object, + invocation, + (gint) error); + + return TRUE; +} + + +/** + * nhm_main_bus_acquired_cb: + * @connection: Connection, which was acquired + * @bus_name: Bus name + * @user_data: Optionally user data + * + * The function is called when a connection to the D-Bus could be established. + */ +static void +nhm_main_bus_acquired_cb(GDBusConnection *connection, + const gchar *bus_name, + gpointer user_data) +{ + GError *error = NULL; + NhmLcInfo *lc_info = NULL; + + /* "Protect" NHM from exit when conn. fails. Important to monitor dbus */ + g_dbus_connection_set_exit_on_close(connection, FALSE); + + /* The first array element always has to be the current LC. Create it! */ + nodeinfo = g_ptr_array_new_with_free_func(&nhm_main_free_lc_info); + lc_info = g_new(NhmLcInfo, 1); + + /* Load shutdown flag. Indicates if last LC was regular shut down */ + lc_info->start_state = nhm_main_read_shutdown_flag(); + lc_info->failed_apps = NULL; + g_ptr_array_add(nodeinfo, (gpointer) lc_info); + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Previous shutdown was"); + DLT_STRING( (lc_info->start_state == NHM_NODESTATE_SHUTDOWN) + ? "complete" : "incomplete")); + + /* Read data of prev. LCs. They are added to 'nodeinfo' after current LC */ + nhm_main_read_data(); + + /* Create skeleton object, register signals and export interfaces */ + dbus_nhm_info_obj = nhm_dbus_info_skeleton_new(); + + (void) g_signal_connect(dbus_nhm_info_obj, + "handle-register-app-status", + G_CALLBACK(nhm_main_register_app_status_cb), + NULL); + + (void) g_signal_connect(dbus_nhm_info_obj, + "handle-read-statistics", + G_CALLBACK(nhm_main_read_statistics_cb), + NULL); + + (void) g_signal_connect(dbus_nhm_info_obj, + "handle-request-node-restart", + G_CALLBACK(nhm_main_request_node_restart_cb), + NULL); + + (void) g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(dbus_nhm_info_obj), + connection, + NHM_INFO_OBJECT, + &error); + if(error != NULL) + { + /* Critical error: The interface could not be exported. Stop the NHM. */ + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Bus acquired actions failed."); + DLT_STRING("Error: Could not export D-Bus object."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + + mainreturn = EXIT_FAILURE; + g_main_loop_quit(mainloop); + } +} + + +/** + * nhm_main_name_acquired_cb: + * @connection: Connection over which the bus name was acquired + * @app_name: Acquired bus name + * @user_data: Optionally user data + * + * The function is called when the "bus name" could be acquired on the D-Bus. + */ +static void +nhm_main_name_acquired_cb(GDBusConnection *connection, + const gchar *app_name, + gpointer user_data) +{ + /* The NHM is now completely functional. Reset the shutdown flag */ + (void) nhm_main_write_shutdown_flag(NHM_NODESTATE_STARTED); + + /* Write initial state of current LC (no apps failed) and last prev. LCs*/ + nhm_main_write_data(); + + /* If a user land check is configured, install the timer */ + if(ul_chk_interval != 0) + { + g_timeout_add_seconds(ul_chk_interval, + &nhm_main_timer_userland_check_cb, + NULL); + } + + if(nhm_systemd_connect(&nhm_main_register_app_status) == FALSE) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_WARN, + DLT_STRING("NHM: Systemd observation could not be started.")); + } + + /* Inform systemd that we started up and start timer for systemd WDOG */ + (void) sd_notify (0, "READY=1"); + nhm_main_start_wdog(); + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Successfully obtained D-Bus name.")); +} + + +/** + * nhm_main_name_lost_cb: + * @connection: Connection. If it is NULL, no D-Bus connection could be + * established. Otherwise the bus name was lost. + * @param app_name: Bus name + * @param user_data: Optionally user data + * + * The function is called if either no connection to D-Bus could be established + * or the bus name could not be acquired. + */ +static void +nhm_main_name_lost_cb(GDBusConnection *connection, + const gchar *app_name, + gpointer user_data) +{ + /* If the connection pointer is NULL connection has been lost */ + if(connection == NULL) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: D-Bus connection failed.")); + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: D-Bus name not obtained or lost.")); + } + + mainreturn = EXIT_FAILURE; + g_main_loop_quit(mainloop); /* Cancel loop in all cases */ +} + + +/** + * nhm_main_convert_version_string: + * @version_string: String containing the package version. The @version_string + * can consist of up to four positive numbers <= 255, seperated + * by dots (e.g. "1.21.3.4"). + * + * The function will convert a version string (four positive numbers <= 255, + * seperated by dots) to a 32 Bit value. + * + * Return value: Numeric value representing the version number. + */ +static guint32 +nhm_main_convert_version_string(const gchar *version_string) +{ + gchar** version_split = NULL; + guint version_idx = 0; + guint32 version = 0; + + version_split = g_strsplit(version_string, ".", 4); + + for(version_idx = 0; version_idx < g_strv_length(version_split); version_idx++) + { + version |= (strtol(version_split[version_idx], NULL, 10) + << (24 -(8 * version_idx))); + } + + g_strfreev(version_split); + + return version; +} + + +/** + * nhm_main_write_data: + * + * The function writes the information about the previous life cycles to a + * file in a binary format. The content of the file is structured as follows: + * + * Ver. | # of Lc | state | # of apps | # app chars | app name | app fails + * 4 Byte | 4 Byte | 4 Byte | 4 Byte | 4 Byte | # app chars | 4 Byte + * | # app chars | app name | app fails + * | 4 Byte | # app chars | 4 Byte + * ... + * | state | # of apps | # app chars | app name | app fails + * | 4 Byte | 4 Byte | 4 Byte | # app chars | 4 Byte + * | # app chars | app name | app fails + * | 4 Byte | # app chars | 4 Byte + * ... + * + * At the start of the file, the version of the NHM is stored. The version is + * followed by the number of stored life cycles. For each life cycle, the first + * information is the shutdown state. After that, the number of failed apps. in + * the life cycle is stored. For each failed app., the app. name is stored + * (str. length and string) and the fail count. + */ +static void +nhm_main_write_data(void) +{ + FILE *file = NULL; + guint lc_idx = 0; + NhmLcInfo *lc_info = NULL; + GSList *app_list = NULL; + NhmFailedApp *app_info = NULL; + guint lc_list_size = 0; + guint app_list_size = 0; + guint app_name_len = 0; + guint nhm_version = 0; + + file = fopen(NHM_LC_DATA_FILE, "w"); /* Open file to store data */ + + if(file != NULL) + { + /* Store the NHM version */ + nhm_version = nhm_main_convert_version_string(VERSION); + fwrite((void*) &nhm_version, sizeof(nhm_version), 1, file); + + /* Store # of LCs (amount required by config. or at least what we have) */ + lc_list_size = MIN(nodeinfo->len, max_lc_count); + fwrite((void*) &lc_list_size, sizeof(lc_list_size), 1, file); + + for(lc_idx = 0; lc_idx < lc_list_size; lc_idx++) + { + /* For every LC, store it's info. Start with the 'shutdown state'. */ + lc_info = (NhmLcInfo*) g_ptr_array_index(nodeinfo, lc_idx); + fwrite((void*) &(lc_info->start_state), sizeof(lc_info->start_state), 1, file); + + /* Store the number of failed apps. that occured in this life cycle */ + app_list = lc_info->failed_apps; + app_list_size = (app_list != NULL) ? g_slist_length(app_list) : 0; + fwrite((void*) &app_list_size, sizeof(app_list_size), 1, file); + + for(app_list = lc_info->failed_apps; app_list != NULL; app_list = g_slist_next(app_list)) + { + /* For every app store app. name (length and string) and fail count */ + app_info = (NhmFailedApp*) app_list->data; + app_name_len = strlen((char*) app_info->name) + 1; + fwrite((void*) &app_name_len, sizeof(app_name_len), 1, file); + fwrite((void*) app_info->name, app_name_len, 1, file); + fwrite((void*) &(app_info->failcount), sizeof(app_info->failcount), 1, file); + } + } + + fclose(file); /* close the file */ + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Write LcData failed."); + DLT_STRING("Error: Failed to open file."); + DLT_STRING("File:"); DLT_STRING(NHM_LC_DATA_FILE)); + } +} + + +/** + * nhm_main_read_data: + * + * The function reads the information about the previous life cycles from a + * binary file. For the structure of the file see 'nhm_main_write_data'. + * For each LC a 'NhmLcInfo' structure is allocated. For every app. in each + * life cycle, a 'NHM__tstAppInfo' structure and storage to store the app. + * name are allocated. Remember to free this memory! + */ +static void +nhm_main_read_data(void) +{ + FILE *file = NULL; + guint lc_idx = 0; + NhmLcInfo *lc_Info = NULL; + GSList *app_list = NULL; + NhmFailedApp *app_info = NULL; + guint lc_list_size = 0; + guint app_idx = 0; + guint app_list_size = 0; + guint app_name_len = 0; + guint nhm_version = 0; + + file = fopen(NHM_LC_DATA_FILE, "r"); /* Open file to read data */ + + if(file != NULL) + { + /* Read NHM version */ + fread(&nhm_version, 4, 1, file); + + /* Read # of LCs. Load configured amount or at least the stored ones */ + fread((void*) &lc_list_size, sizeof(lc_list_size), 1, file); + lc_list_size = MIN(lc_list_size, max_lc_count); + + for(lc_idx = 0; lc_idx < lc_list_size; lc_idx++) + { + /* Create a new LC. Read its 'shutdown' flag */ + lc_Info = g_new(NhmLcInfo, 1); + fread((void*) &(lc_Info->start_state), sizeof(lc_Info->start_state), 1, file); + + /* Create a new app. list for the LC. Read number of stored apps. */ + app_list = NULL; + fread((void*) &app_list_size, sizeof(app_list_size), 1, file); + + for(app_idx = 0; app_idx < app_list_size; app_idx++) + { + /* For each stored app. Create a new app. info */ + app_info = g_new(NhmFailedApp, 1); + + /* Read the app. name length, allocate storage for string and read it */ + fread((void*) &app_name_len, sizeof(app_name_len), 1, file); + + app_info->name = g_new(gchar, app_name_len); + fread((void*) app_info->name, app_name_len, 1, file); + + /* Read the apps. fail count */ + fread((void*) &(app_info->failcount), sizeof(app_info->failcount), 1, file); + + /* Append the new app. info to the app. list */ + app_list = g_slist_append(app_list, app_info); + } + + /* Assign the recently read app. list to LC and store new LC in array. */ + lc_Info->failed_apps = app_list; + g_ptr_array_add(nodeinfo, lc_Info); + } + + fclose(file); /* Close the file */ + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Read LcData failed."); + DLT_STRING("Error: Failed to open file."); + DLT_STRING("File:"); DLT_STRING(NHM_LC_DATA_FILE)); + } +} + + +/** + * nhm_main_write_shutdown_flag: + * @node_state: Value that should be written to the shutdown flag + * + * The function writes the persistent shut down flag + */ +static gboolean +nhm_main_write_shutdown_flag(NhmNodeState node_state) +{ + int persval = 0; + gboolean retval = FALSE; + + persval = pclKeyWriteData(NHM_SHUTDOWN_FLAG_LDBID, + NHM_SHUTDOWN_FLAG_NAME, + 0, + 0, + (unsigned char*) &node_state, + sizeof(node_state)); + + if(persval == sizeof(node_state)) + { + retval = TRUE; + } + else + { + /* Error: Did not write expected amount of bytes or got an error (< 0) */ + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to write 'shutdown flag'."); + DLT_STRING("Error: Unexpected return from PCL."); + DLT_STRING("Database ID:"); DLT_INT(NHM_SHUTDOWN_FLAG_LDBID); + DLT_STRING("Key:"); DLT_STRING(NHM_SHUTDOWN_FLAG_NAME); + DLT_STRING("User:"); DLT_INT(0); + DLT_STRING("Seat:"); DLT_INT(0); + DLT_STRING("Return:"); DLT_INT(persval)); + } + + return retval; +} + + +/** + * nhm_main_read_shutdown_flag: + * + * The function reads the persistent shut down flag. + * + * Return value: Value read from shut down flag file. + */ +static NhmNodeState +nhm_main_read_shutdown_flag(void) +{ + NhmNodeState retval = NHM_NODESTATE_NOTSET; + int persval = 0; + + persval = pclKeyReadData(NHM_SHUTDOWN_FLAG_LDBID, + NHM_SHUTDOWN_FLAG_NAME, + 0, + 0, + (unsigned char*) &retval, + sizeof(retval)); + + if(persval != sizeof(retval)) + { + /* Error: Did not read expected amount of bytes or got an error (< 0) */ + retval = NHM_NODESTATE_NOTSET; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to read 'shutdown flag'."); + DLT_STRING("Error: Unexpected return from PCL."); + DLT_STRING("Database ID:"); DLT_INT(NHM_SHUTDOWN_FLAG_LDBID); + DLT_STRING("Key:"); DLT_STRING(NHM_SHUTDOWN_FLAG_NAME); + DLT_STRING("User:"); DLT_INT(0); + DLT_STRING("Seat:"); DLT_INT(0); + DLT_STRING("Return:"); DLT_INT(persval)); + } + + return retval; +} + + +/** + * nhm_main_config_load_uint: + * @file: Pointer to key file. + * @group: Group name, in which key resists + * @key: Key name + * @defval: Default return, if value can't be read. + * + * The function loads an unsigned integer from the given file, group and key. + * If the key is not accessible or the read value is negative, the default + * value is returned. + * + * Return value: Unsigned integer loaded from config file or default value. + */ +static guint +nhm_main_config_load_uint(GKeyFile *file, + gchar *group, + gchar *key, + guint defval) +{ + GError *error = NULL; + gint retval = 0; + + /* Load value from key */ + retval = g_key_file_get_integer(file, group, key, &error); + + if(error == NULL) + { + /* Value from config could be read. Check if it is negative. */ + if(retval >= 0) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Loaded config value."); + DLT_STRING("Group:"); DLT_STRING(group); + DLT_STRING("Key:"); DLT_STRING(key); + DLT_STRING("Value:"); DLT_INT(retval)); + } + else + { + /* Error. A negative number has been read. Use default value. */ + retval = (gint) defval; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to load config value."); + DLT_STRING("Error: Value out of range."); + DLT_STRING("Group:"); DLT_STRING(group); + DLT_STRING("Key:"); DLT_STRING(key)); + } + } + else + { + /* Error. Failed to load the value. Print error and use default value. */ + retval = (gint) defval; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to load config value."); + DLT_STRING("Error: Could not get integer."); + DLT_STRING("Group:"); DLT_STRING(group); + DLT_STRING("Key:"); DLT_STRING(key); + DLT_STRING("Reason:"); DLT_STRING(error->message )); + g_error_free(error); + } + + return (guint) retval; +} + + +/** + * nhm_main_config_load_string_array: + * @file: Pointer to key file. + * @group: Group name, in which key resists + * @key: Key name + * @defval: Default return, if value can't be read. May be NULL. + * + * The function loads a string list from the given file, group and key. + * If the key is not accessible, the default value is returned. In all + * cases, the returned string array has to be freed with 'g_strfreev'. + * + * Return value: Ptr. to a string array. Has to be freed with 'g_strfreev'. + */ +static gchar** +nhm_main_config_load_string_array(GKeyFile *file, + gchar *group, + gchar *key, + gchar **defval) +{ + /* Function local variables */ + GError *error = NULL; + gchar **retval = NULL; + gsize list_size = 0; + gchar *loaded_list = NULL; + + /* Load value from key */ + retval = g_key_file_get_string_list(file, group, key, &list_size, &error); + + if(error == NULL) + { + loaded_list = g_strjoinv(";", retval); + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Loaded config value."); + DLT_STRING("Group:"); DLT_STRING(group); + DLT_STRING("Key:"); DLT_STRING(key); + DLT_STRING("Value:"); DLT_STRING(loaded_list)); + } + else + { + /* Error. Failed to load the value. Print error and use default value. */ + retval = g_strdupv(defval); + loaded_list = g_strjoinv(";", retval); + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to load config value."); + DLT_STRING("Error: Could not get string."); + DLT_STRING("Group:"); DLT_STRING(group); + DLT_STRING("Key:"); DLT_STRING(key); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + + if(strlen(loaded_list) == 0) + { + g_strfreev(retval); + retval = NULL; + } + + g_free(loaded_list); + + return retval; +} + + +/** + * nhm_main_load_config: + * + * The function loads the configuration. + * If a value is not accessable, default values are used. + */ +static void +nhm_main_load_config(void) +{ + GKeyFile *file = NULL; + GError *error = NULL; + + /* Variables to configure default values on error */ + gchar *def_no_restart_apps[] = {"", NULL}; + gchar *def_monitored_files[] = {"", NULL}; + gchar *def_monitored_progs[] = {"", NULL}; + gchar *def_monitored_procs[] = {"", NULL}; + gchar *def_monitored_dbus[] = {"", NULL}; + + /* Open the key file */ + file = g_key_file_new(); + + (void) g_key_file_load_from_file(file, NHM_CFG_FILE, G_KEY_FILE_NONE, &error); + + if(error == NULL) + { + /* Key file could be opened. Load config values */ + max_lc_count = nhm_main_config_load_uint (file, + "node", + "historic_lc_count", + 0); + max_failed_apps = nhm_main_config_load_uint (file, + "node", + "max_failed_apps", + 0); + no_restart_apps = nhm_main_config_load_string_array(file, + "node", + "no_restart_apps", + def_no_restart_apps); + ul_chk_interval = nhm_main_config_load_uint (file, + "userland", + "ul_chk_interval", + 0); + monitored_files = nhm_main_config_load_string_array(file, + "userland", + "monitored_files", + def_monitored_files); + monitored_progs = nhm_main_config_load_string_array(file, + "userland", + "monitored_progs", + def_monitored_progs); + monitored_procs = nhm_main_config_load_string_array(file, + "userland", + "monitored_procs", + def_monitored_procs); + monitored_dbus = nhm_main_config_load_string_array(file, + "userland", + "monitored_dbus", + def_monitored_dbus); + } + else + { + /* Error. Key file could not be opened. Use default values for settings. */ + max_lc_count = 0; + max_failed_apps = 0; + no_restart_apps = NULL; + ul_chk_interval = 0; + monitored_files = NULL; + monitored_progs = NULL; + monitored_procs = NULL; + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to open configuration."); + DLT_STRING("Error: Loading key file failed."); + DLT_STRING("File:"); DLT_STRING(NHM_CFG_FILE); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + + g_key_file_free(file); +} + + +/** + * nhm_main_prepare_checks: + * + * Create variables to be able to run checks. + */ +static void +nhm_main_prepare_checks(void) +{ + guint32 bus_idx = 0; + NhmCheckedDbus *checked_dbus = NULL; + + if(monitored_dbus != NULL) + { + /* Create new array with free function */ + checked_dbusses = + g_ptr_array_new_with_free_func(&nhm_main_free_checked_dbus); + + for(bus_idx = 0; bus_idx < g_strv_length(monitored_dbus); bus_idx++) + { + checked_dbus = g_new(NhmCheckedDbus, 1); + checked_dbus->bus_addr = g_strdup(monitored_dbus[bus_idx]); + checked_dbus->bus_conn = NULL; + + g_ptr_array_add(checked_dbusses, (gpointer) checked_dbus); + } + } +} + +/** + * nhm_main_connect_to_nsm: + * + * The function "connects" the NHM, to the NSM. + * Therefore, the following things are done: + * + * 1. Bus connection to the NSM's bus is obtained + * 2. "LifecycleControl" proxy is created + * 3. "NodeStateConsumer" proxy is created + * 4. "LifecycleConsumer" skeleton is created and exported. + * 5. The NHM registers as shut down client at the NSM. + * + * Return value: %TRUE: All points above succeeded. NHM is connected to NSM. + * %FALSE: The NHM could not connect to the NSM. + */ +static gboolean +nhm_main_connect_to_nsm(void) +{ + GError *error = NULL; + const gchar *bus_name = NULL; + NsmErrorStatus_e nsm_retval = NsmErrorStatus_NotSet; + gboolean retval = FALSE; + + /* Step 1: Connect to dbus of the NSM */ + nsmbusconn = g_bus_get_sync((GBusType) NSM_BUS_TYPE, NULL, &error); + + if(error == NULL) + { + retval = TRUE; + + /* "Protect" NHM from exit when conn. fails. Important to monitor dbus */ + g_dbus_connection_set_exit_on_close(nsmbusconn, FALSE); + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to connect to NSM."); + DLT_STRING("Error: Get connection failed."); + DLT_STRING("Bus type:"); DLT_INT(NSM_BUS_TYPE); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + + /* Step 2: Create life cycle control proxy to call 'RequestNodeRestart'. */ + if(retval == TRUE) + { + dbus_lc_control_obj = + nsm_dbus_lc_control_proxy_new_sync(nsmbusconn, + G_DBUS_PROXY_FLAGS_NONE, + NSM_BUS_NAME, + NSM_LIFECYCLE_OBJECT, + NULL, + &error); + if(error == NULL) + { + retval = TRUE; + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to connect to NSM."); + DLT_STRING("Error: Could not create LcControl proxy."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + + /* Step 3: Create node state consumer proxy to register as LC client. */ + if(retval == TRUE) + { + dbus_consumer_obj = + nsm_dbus_consumer_proxy_new_sync(nsmbusconn, + G_DBUS_PROXY_FLAGS_NONE, + NSM_BUS_NAME, + NSM_CONSUMER_OBJECT, + NULL, + &error); + if(error == NULL) + { + retval = TRUE; + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to connect to NSM."); + DLT_STRING("Error: Could not create Consumer proxy."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + + /* Step 4: Create and export life cycle client interface. */ + if(retval == TRUE) + { + dbus_lc_consumer_obj = nsm_dbus_lc_consumer_skeleton_new(); + + (void) g_dbus_interface_skeleton_export( + G_DBUS_INTERFACE_SKELETON(dbus_lc_consumer_obj), + nsmbusconn, + NHM_LC_CLIENT_OBJ, + &error); + if(error == NULL) + { + retval = TRUE; + + (void) g_signal_connect(dbus_lc_consumer_obj, + "handle-lifecycle-request", + G_CALLBACK(nhm_main_lc_request_cb), + NULL); + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to connect to NSM."); + DLT_STRING("Error: Could not export LC consumer object."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + + /* Step 5: Register as life cycle client. */ + if(retval == TRUE) + { + bus_name = g_dbus_connection_get_unique_name(nsmbusconn); + + (void) nsm_dbus_consumer_call_register_shutdown_client_sync( + dbus_consumer_obj, + bus_name, + NHM_LC_CLIENT_OBJ, + NSM_SHUTDOWNTYPE_FAST + | NSM_SHUTDOWNTYPE_NORMAL, + NHM_LC_CLIENT_TIMEOUT, + (gint*) &nsm_retval, + NULL, + &error); + if(error == NULL) + { + if(nsm_retval == NsmErrorStatus_Ok) + { + retval = TRUE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Successfully connected to NSM")); + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to connect to NSM."); + DLT_STRING("Error: Unexpected return from NSM."); + DLT_STRING("Return:"); DLT_INT(nsm_retval)); + } + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to connect to NSM."); + DLT_STRING("Error: Could not call NSM client registration."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + + return retval; +} + + +/** + * nhm_main_free_nhm_objects: + * + * Destroy all objects that could have been created during mainloop run. + */ +static void +nhm_main_free_nhm_objects(void) +{ + /* Free the skeleton object (if there was one) */ + if(dbus_nhm_info_obj != NULL) + { + g_object_unref(dbus_nhm_info_obj); + dbus_nhm_info_obj = NULL; + } + + /* Free the list of currently failed apps */ + g_slist_free_full(current_failed_apps, &nhm_main_free_current_failed_app); + current_failed_apps = NULL; + + /* Free the array of life cycle info */ + if(nodeinfo != NULL) + { + g_ptr_array_unref(nodeinfo); + nodeinfo = NULL; + } +} + + +/** + * nhm_main_free_nsm_objects: + * + * Tries to destroy all objects that could have been created + * in 'nhm_main_connect_to_nsm'. + */ +static void +nhm_main_free_nsm_objects(void) +{ + /* Free NSM bus connection */ + if(nsmbusconn != NULL) + { + g_object_unref(nsmbusconn); + nsmbusconn = NULL; + } + + /* Free LifecycleControl proxy */ + if(dbus_lc_control_obj != NULL) + { + g_object_unref(dbus_lc_control_obj); + dbus_lc_control_obj = NULL; + } + + /* Free NodeStateConsumer proxy */ + if(dbus_consumer_obj != NULL) + { + g_object_unref(dbus_consumer_obj); + dbus_consumer_obj = NULL; + } + + /* Free LifecycleConsumerSkeleton */ + if(dbus_lc_consumer_obj != NULL) + { + g_object_unref(dbus_lc_consumer_obj); + dbus_lc_consumer_obj = NULL; + } +} + + +/** + * nhm_main_free_config_objects: + * + * Destroys all objects that have been created when loading the config. + */ +static void +nhm_main_free_config_objects(void) +{ + /* g_strfreev can hanlde NULL on its own */ + g_strfreev(no_restart_apps); + no_restart_apps = NULL; + + g_strfreev(monitored_files); + monitored_files = NULL; + + g_strfreev(monitored_progs); + monitored_progs = NULL; + + g_strfreev(monitored_procs); + monitored_procs = NULL; + + g_strfreev(monitored_dbus); + monitored_dbus = NULL; +} + + +/** + * nhm_main_free_check_objects: + * + * Destroys all objects that have been created for checks. + */ +static void +nhm_main_free_check_objects(void) +{ + if(checked_dbusses != NULL) + { + g_ptr_array_unref(checked_dbusses); + } +} + + +/** + * nhm_main_init: + * + * Initializes the file local variables used by the NHM. + */ +static void +nhm_main_init(void) +{ + /* main control */ + mainreturn = EXIT_FAILURE; + mainloop = NULL; + + /* dbus connection */ + nsmbusconn = NULL; + dbus_nhm_info_obj = NULL; + dbus_lc_consumer_obj = NULL; + dbus_lc_control_obj = NULL; + dbus_consumer_obj = NULL; + + /* run time data */ + nodeinfo = NULL; + current_failed_apps = NULL; + checked_dbusses = NULL; + + /* config stuff */ + max_lc_count = 0; + max_failed_apps = 0; + no_restart_apps = NULL; + + ul_chk_interval = 0; + monitored_files = NULL; + monitored_procs = NULL; + monitored_procs = NULL; + monitored_dbus = NULL; +} + + +/** + * nhm_main_on_sigterm: + * @user_data: Optional userdata, configured when signal was registered. + * + * Callback when the SIGTERM signal arrives. + */ +static gboolean +nhm_main_on_sigterm(gpointer user_data) +{ + mainreturn = EXIT_SUCCESS; + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Received SIGTERM. Going to shut down")); + + g_main_loop_quit(mainloop); + + return TRUE; +} + + +/****************************************************************************** +* +* Interfaces. Exported functions. See Header for detailed description. +* +******************************************************************************/ + +/** + * + * Main function of the executable. Starts the NHM, connects to D-Bus, + * publishes the interface and waits for calls. + * + * @return EXIT_SUCCESS: The executable ended without errors. + * EXIT_FAILURE: There was an error. + */ +int +main(void) +{ + int pcl_ret = 0; + + /* Register NHM for DLT */ + DLT_REGISTER_APP("NHM", "Node Health Monitor"); + DLT_REGISTER_CONTEXT(nhm_helper_trace_ctx, "016", "Context for the NHM"); + + /* Print first msg. to show that NHM is going to start */ + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: NodeHealthMonitor started."), + DLT_STRING("Version:"), DLT_STRING(VERSION )); + + /* Initialize glib for using "g" types */ + g_type_init(); + + /* Initialize components variables */ + nhm_main_init(); + + /* Initialize the PCL */ + pcl_ret = pclInitLibrary("node-health-monitor", + PCL_SHUTDOWN_TYPE_FAST | PCL_SHUTDOWN_TYPE_NORMAL); + + if(pcl_ret < 0) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_WARN, + DLT_STRING("NHM: PCL could not be initialized."); + DLT_STRING("Return:"); DLT_INT(pcl_ret)); + } + + /* Load config and prepare checks. Default config used in case of errors */ + nhm_main_load_config(); + nhm_main_prepare_checks(); + + /* Connect to NSM, before offering services. Don't start if it doesn't work */ + if(nhm_main_connect_to_nsm() == TRUE) + { + mainloop = g_main_loop_new(NULL, FALSE); + + (void) g_bus_own_name((GBusType) NHM_BUS_TYPE, + NHM_BUS_NAME, + G_BUS_NAME_OWNER_FLAGS_NONE, + &nhm_main_bus_acquired_cb, + &nhm_main_name_acquired_cb, + &nhm_main_name_lost_cb, + NULL, + NULL); + + /* Add source to catch SIGTERM signal */ + g_unix_signal_add(SIGTERM, &nhm_main_on_sigterm, NULL); + + /* Blocking function, returns in case of an error or if app. shuts down */ + g_main_loop_run(mainloop); + + /* Disconnect from systemd observation */ + nhm_systemd_disconnect(); + + /* Free objects created during main loop run */ + nhm_main_free_nhm_objects(); + + /* Free resources of the main loop */ + g_main_loop_unref(mainloop); + } + else + { + mainreturn = EXIT_FAILURE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to start NodeHealthMonitor."); + DLT_STRING("Error:"); DLT_STRING("Could not connect to NSM")); + } + + /* Free objects created by NSM connection */ + nhm_main_free_nsm_objects(); + + /* Free objects used by checks */ + nhm_main_free_check_objects(); + + /* Free objects created by config. load */ + nhm_main_free_config_objects(); + + /* Deinitialize the PCL */ + pcl_ret = pclDeinitLibrary(); + + if(pcl_ret < 0) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_WARN, + DLT_STRING("NHM: PCL could not be deinitialized."), + DLT_STRING("Return:"); DLT_INT(pcl_ret)); + } + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: NodeHealthMonitor stopped.")); + + /* Unregister NSM from DLT */ + DLT_UNREGISTER_CONTEXT(nhm_helper_trace_ctx); + DLT_UNREGISTER_APP(); + + return mainreturn; +} diff --git a/src/nhm-systemd.c b/src/nhm-systemd.c new file mode 100644 index 0000000..1170631 --- /dev/null +++ b/src/nhm-systemd.c @@ -0,0 +1,930 @@ +/* NHM - NodeHealthMonitor + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + */ + +/** + * SECTION:nhm-systemd + * @title: NodeHealthMonitor (NHM) systemd observation + * @short_description: Use systemd to check for failed units + * + * This section is for the observation of systemd. The code will monitor the + * "ActiveState" of unit objects on their dbus interface. Based on the + * transitions of the "ActiveState", failing units can be identified. + */ + + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +/* System header files */ +#include <stdio.h> /* NULL */ +#include <gio/gio.h> /* Use gdbus */ +#include <dlt/dlt.h> /* DLT traces */ + +/* Component header files */ +#include "nhm-systemd.h" /* Own header */ +#include "nhm-helper.h" /* NHM helper functions */ + + +/******************************************************************************* +* +* Constants, types and defines +* +*******************************************************************************/ + +#define NHM_SYSTEMD_BUS_NAME "org.freedesktop.systemd1" +#define NHM_SYSTEMD_MNGR_IF "org.freedesktop.systemd1.Manager" +#define NHM_SYSTEMD_UNIT_IF "org.freedesktop.systemd1.Unit" +#define NHM_SYSTEMD_PROP_IF "org.freedesktop.DBus.Properties" +#define NHM_SYSTEMD_OBJ_PATH "/org/freedesktop/systemd1" + + +/** + * NhmActiveState: + * @NHM_ACTIVE_STATE_UNKNOWN: Init. val. and to handle systemd updates + * @NHM_ACTIVE_STATE_ACTIVE: Unit state is active + * @NHM_ACTIVE_STATE_RELOADING: Unit state is reloading + * @NHM_ACTIVE_STATE_INACTIVE: Unit is inactive + * @NHM_ACTIVE_STATE_FAILED: Unit is in a failed state + * @NHM_ACTIVE_STATE_ACTIVATING: Unit is currently being activated + * @NHM_ACTIVE_STATE_DEACTIVATING: Unit is currently being deactivated + * @NHM_ACTIVE_STATE_LAST: Last value of enumeration + * + * The enumeration is used to convert string values, which systemd delivers for + * the ActiveState, to numeric values. + */ +typedef enum +{ + NHM_ACTIVE_STATE_UNKNOWN, + NHM_ACTIVE_STATE_ACTIVE, + NHM_ACTIVE_STATE_RELOADING, + NHM_ACTIVE_STATE_INACTIVE, + NHM_ACTIVE_STATE_FAILED, + NHM_ACTIVE_STATE_ACTIVATING, + NHM_ACTIVE_STATE_DEACTIVATING, + NHM_ACTIVE_STATE_LAST +} NhmActiveState; + + +/** + * NhmSystemdUnit: + * @name: Name of the unit + * @path: Path to find unit on dbus + * @active_state: Active state of the unit + * @sig_sub_id: Subscription ID for PropertiesChanged signal + * + * The structure is used to create a list of observed units. + */ +typedef struct +{ + gchar *name; + gchar *path; + NhmActiveState active_state; + guint sig_sub_id; +} NhmSystemdUnit; + + +/** + * NhmSystemdAppStatusChange: + * @do_callback: Defines if 'app_status' should be send + * @next_status: Status to which app changed. + * + * The structure is used in 'nhm_systemd_active_state_map' to define the new + * app_status after a transition and whether a callback should be made. + */ +typedef struct +{ + gboolean do_callback; + NhmAppStatus_e next_status; +} NhmSystemdAppStatusChange; + + +/* Array defines new 'app_status' after a transition of the 'active_state' */ +static const +NhmSystemdAppStatusChange +nhm_systemd_active_state_map[NHM_ACTIVE_STATE_LAST][NHM_ACTIVE_STATE_LAST] = +{ + /* NHM_ACTIVE_STATE_UNKNOWN -> New state */ + /* NHM_ACTIVE_STATE_UNKNOWN */ {{ FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVE */ { TRUE, NhmAppStatus_Ok }, + /* NHM_ACTIVE_STATE_RELOADING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_INACTIVE */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_FAILED */ { TRUE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVATING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_DEACTIVATING */ { FALSE, NhmAppStatus_Failed }}, + + /* NHM_ACTIVE_STATE_ACTIVE -> New state */ + /* NHM_ACTIVE_STATE_UNKNOWN */ {{ FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVE */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_RELOADING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_INACTIVE */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_FAILED */ { TRUE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVATING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_DEACTIVATING */ { FALSE, NhmAppStatus_Failed }}, + + /* NHM_ACTIVE_STATE_RELOADING -> New state */ + /* NHM_ACTIVE_STATE_UNKNOWN */ {{ FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVE */ { TRUE, NhmAppStatus_Ok }, + /* NHM_ACTIVE_STATE_RELOADING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_INACTIVE */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_FAILED */ { TRUE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVATING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_DEACTIVATING */ { FALSE, NhmAppStatus_Failed }}, + + /* NHM_ACTIVE_STATE_INACTIVE -> New state */ + /* NHM_ACTIVE_STATE_UNKNOWN */ {{ FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVE */ { TRUE, NhmAppStatus_Ok }, + /* NHM_ACTIVE_STATE_RELOADING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_INACTIVE */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_FAILED */ { TRUE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVATING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_DEACTIVATING */ { FALSE, NhmAppStatus_Failed }}, + + /* NHM_ACTIVE_STATE_FAILED -> New state */ + /* NHM_ACTIVE_STATE_UNKNOWN */ {{ FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVE */ { TRUE, NhmAppStatus_Ok }, + /* NHM_ACTIVE_STATE_RELOADING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_INACTIVE */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_FAILED */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVATING */ { TRUE, NhmAppStatus_Restarting }, + /* NHM_ACTIVE_STATE_DEACTIVATING */ { FALSE, NhmAppStatus_Failed }}, + + /* NHM_ACTIVE_STATE_ACTIVATING -> New state */ + /* NHM_ACTIVE_STATE_UNKNOWN */ {{ FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVE */ { TRUE, NhmAppStatus_Ok }, + /* NHM_ACTIVE_STATE_RELOADING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_INACTIVE */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_FAILED */ { TRUE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVATING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_DEACTIVATING */ { FALSE, NhmAppStatus_Failed }}, + + /* NHM_ACTIVE_STATE_DEACTIVATING -> New state */ + /* NHM_ACTIVE_STATE_UNKNOWN */ {{ FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVE */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_RELOADING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_INACTIVE */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_FAILED */ { TRUE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_ACTIVATING */ { FALSE, NhmAppStatus_Failed }, + /* NHM_ACTIVE_STATE_DEACTIVATING */ { FALSE, NhmAppStatus_Failed }} +}; + + +/******************************************************************************* +* +* Prototypes for file local functions (see implementation for description) +* +*******************************************************************************/ + +/* Helper functions */ +static NhmActiveState nhm_systemd_active_state_string_to_enum (const gchar *string); +static void nhm_systemd_unit_active_state_changed (NhmSystemdUnit *unit, + NhmActiveState new_state); +static gint nhm_systemd_find_unit_by_name (gconstpointer u1, + gconstpointer u2); +static void nhm_systemd_free_unit (gpointer unit); + +static NhmActiveState nhm_systemd_unit_get_active_state (NhmSystemdUnit *unit); + +/* Signal registration functions */ +static guint nhm_systemd_subscribe_properties_changed (const NhmSystemdUnit *unit); + +/* Signal handler functions */ +static void nhm_systemd_unit_active_state_changed (NhmSystemdUnit *unit, + NhmActiveState new_state); +static void nhm_systemd_unit_properties_changed (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data); +static void nhm_systemd_unit_added (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data); +static void nhm_systemd_unit_removed (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data); +static void nhm_systemd_unit_properties_changed (GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data); + + +/******************************************************************************* +* +* Local variables and constants +* +*******************************************************************************/ + +/* Bus connection and callback set on observation start */ +static NhmSystemdAppStatusCb nhm_systemd_app_status_cb = NULL; +static GDBusConnection *nhm_systemd_conn = NULL; + +/* List of units known by us (based on NhmSystemdUnit) */ +static GSList *nhm_systemd_observed_units = NULL; + +/* Signals registered at systemd */ +static guint nhm_systemd_unit_add_sig_id = 0; +static guint nhm_systemd_unit_rem_sig_id = 0; +static gboolean nhm_systemd_events_subscribed = FALSE; + + +/******************************************************************************* +* +* Local (static) functions +* +*******************************************************************************/ + + +/** + * nhm_systemd_active_state_string_to_enum: + * @string: String representing 'active_state' of a systemd unit + * @return: Enumerated equivalent for 'active_state' string. + * + * The function converts the passed 'active_state' string to the equivalent + * enumerated value. If the string isn't a known ActiveState, + * 'NHM_ACTIVE_STATE_UNKNOWN' is returned. + */ +static NhmActiveState +nhm_systemd_active_state_string_to_enum(const gchar *string) +{ + NhmActiveState state = NHM_ACTIVE_STATE_UNKNOWN; + + if(g_strcmp0(string, "active") == 0) + { + state = NHM_ACTIVE_STATE_ACTIVE; + } + else if(g_strcmp0(string, "inactive") == 0) + { + state = NHM_ACTIVE_STATE_INACTIVE; + } + else if(g_strcmp0(string, "activating") == 0) + { + state = NHM_ACTIVE_STATE_ACTIVATING; + } + else if(g_strcmp0(string, "deactivating") == 0) + { + state = NHM_ACTIVE_STATE_DEACTIVATING; + } + else if(g_strcmp0(string, "failed") == 0) + { + state = NHM_ACTIVE_STATE_FAILED; + } + else if(g_strcmp0(string, "reloading") == 0) + { + state = NHM_ACTIVE_STATE_RELOADING; + } + else + { + state = NHM_ACTIVE_STATE_UNKNOWN; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to convert 'ActiveState'."); + DLT_STRING("Error: Unknown string."); + DLT_STRING("String:"); DLT_STRING(string)); + } + + return state; +} + + +/** + * nhm_systemd_subscribe_properties_changed: + * @unit: Unit for which properties changed should be processed + * @return: Subscription ID. Necessary to unsubscribe. + * + * The function registers for the PropertiesChanged signal of the passed unit. + */ +static guint +nhm_systemd_subscribe_properties_changed(const NhmSystemdUnit *unit) +{ + guint rval = 0; + + rval = + g_dbus_connection_signal_subscribe(nhm_systemd_conn, + NHM_SYSTEMD_BUS_NAME, + NHM_SYSTEMD_PROP_IF, + "PropertiesChanged", + unit->path, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + &nhm_systemd_unit_properties_changed, + (gpointer) unit, + NULL); + return rval; +} + + +/** + * nhm_systemd_find_unit_by_name: + * @u1: Pointer to unit item from list. + * @u2: Pointer to searched unit item. + * @return: 0, if unit names equal. + * + * The function is used by 'custom finds' to find a unit based on it name. + */ +static gint +nhm_systemd_find_unit_by_name(gconstpointer u1, gconstpointer u2) +{ + return g_strcmp0(((NhmSystemdUnit*) u1)->name, + ((NhmSystemdUnit*) u2)->name); +} + + +/** + * nhm_systemd_free_unit: + * @unit: Pointer to unit item. + * + * The function frees the memory occupied by a unit object and its members. + * It also unregisters for the PropertiesChnaged signal of the unit. + */ +static void +nhm_systemd_free_unit(gpointer unit) +{ + NhmSystemdUnit *u = (NhmSystemdUnit*) unit; + + g_free(u->name); + g_free(u->path); + + g_dbus_connection_signal_unsubscribe(nhm_systemd_conn, u->sig_sub_id); + + g_free(u); +} + + +/** + * nhm_systemd_unit_active_state_changed: + * @unit: Pointer to unit item, whose 'ActiveState' changed. + * @new_state: New 'ActiveState' of the unit. + * + * The function is called when the 'ActiveState' property of a unit changed. + */ +static void +nhm_systemd_unit_active_state_changed(NhmSystemdUnit *unit, + NhmActiveState new_state) +{ + const NhmSystemdAppStatusChange *status_change = NULL; + + status_change = &nhm_systemd_active_state_map[unit->active_state][new_state]; + + if(status_change->do_callback == TRUE) + { + nhm_systemd_app_status_cb(unit->name, status_change->next_status); + } + + unit->active_state = new_state; +} + + +/** + * nhm_systemd_unit_get_active_state: + * @unit: Pointer to unit item, whose 'ActiveState' property should be read. + * @return: ActiveState read from unit properties and converted to the + * equivalent enumeration. + * + * The function is called to retrieve value of the 'ActiveState' property of a + * unit. + */ +static NhmActiveState +nhm_systemd_unit_get_active_state(NhmSystemdUnit *unit) +{ + GError *error = NULL; + GVariant *propval = NULL; + GVariant *child = NULL; + const gchar *state = NULL; + NhmActiveState retval = NHM_ACTIVE_STATE_UNKNOWN; + + propval = g_dbus_connection_call_sync(nhm_systemd_conn, + NHM_SYSTEMD_BUS_NAME, + unit->path, + NHM_SYSTEMD_PROP_IF, + "Get", + g_variant_new("(ss)", + NHM_SYSTEMD_UNIT_IF, + "ActiveState"), + (GVariantType*) "(v)", + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + + if(error == NULL) + { + child = g_variant_get_child_value(propval, 0); + state = g_variant_get_string(child, NULL); + retval = nhm_systemd_active_state_string_to_enum(state); + g_variant_unref(propval); + } + else + { + retval = NHM_ACTIVE_STATE_UNKNOWN; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to get unit property 'ActiveState'."); + DLT_STRING("Error: D-Bus communication failed."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + + return retval; +} + + +/** + * nhm_systemd_unit_added: + * @connection: Connection on which signal occurred. + * @sender_name: (Unique) Sender name of signal. + * @object_path: Object that send the signal. + * @interface_name: Interface from where signal comes from. + * @signal_name: Name of the signal. + * @parameters: Parameters of dbus signal. + * @user_data: Optional user data (not used) + * + * Called when the "UnitAdded" signal from org.freedesktop.systemd1 + * arrives. The new unit will be added to the internal unit list and + * its initial state will be retrieved. + */ +static void +nhm_systemd_unit_added(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + NhmSystemdUnit *unit = NULL; + const gchar *param_type = NULL; + GVariant *child = NULL; + NhmSystemdUnit search_unit; + GSList *list_item = NULL; + + param_type = g_variant_get_type_string(parameters); + + if(g_strcmp0(param_type, "(so)") == 0) + { + child = g_variant_get_child_value(parameters, 0); + search_unit.name = (gchar*) g_variant_get_string(child, NULL); + + if(g_str_has_suffix(search_unit.name, ".service") == TRUE) + { + list_item = g_slist_find_custom(nhm_systemd_observed_units, + &search_unit, + &nhm_systemd_find_unit_by_name); + if(list_item == NULL) + { + unit = g_new(NhmSystemdUnit, 1); + unit->name = g_strdup(search_unit.name); + + child = g_variant_get_child_value(parameters, 1); + unit->path = g_variant_dup_string(child, NULL); + + unit->active_state = nhm_systemd_unit_get_active_state(unit); + unit->sig_sub_id = nhm_systemd_subscribe_properties_changed(unit); + + nhm_systemd_observed_units = g_slist_prepend(nhm_systemd_observed_units, + unit); + + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Systemd unit added."); + DLT_STRING("Name:"); DLT_STRING(unit->name)); + } + } + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to process 'UnitAdded' signal."); + DLT_STRING("Error: Invalid parameter type."); + DLT_STRING("Type:"); DLT_STRING(param_type)); + } +} + + +/** + * nhm_systemd_unit_removed: + * @connection: Connection on which signal occurred. + * @sender_name: (Unique) Sender name of signal. + * @object_path: Object that send the signal. + * @interface_name: Interface from where signal comes from. + * @signal_name: Name of the signal. + * @parameters: Parameters of dbus signal. + * @user_data: Optional user data (not used) + * + * Called when the "UnitRemoved" signal from org.freedesktop.systemd1 + * arrives. The unit will be removed from the internal unit list. + */ +static void +nhm_systemd_unit_removed(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + GSList *list_item = NULL; + const gchar *param_type = NULL; + GVariant *child = NULL; + NhmSystemdUnit search_unit; + + param_type = g_variant_get_type_string(parameters); + + if(g_strcmp0(param_type, "(so)") == 0) + { + child = g_variant_get_child_value(parameters, 0); + search_unit.name = (gchar*) g_variant_get_string(child, NULL); + + if(g_str_has_suffix(search_unit.name, ".service") == TRUE) + { + list_item = g_slist_find_custom(nhm_systemd_observed_units, + &search_unit, + &nhm_systemd_find_unit_by_name); + if(list_item != NULL) + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_INFO, + DLT_STRING("NHM: Systemd unit removed."); + DLT_STRING("Name:"); DLT_STRING(search_unit.name)); + + nhm_systemd_free_unit(list_item->data); + nhm_systemd_observed_units = g_slist_remove(nhm_systemd_observed_units, + list_item->data); + } + } + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to process 'UnitRemoved' signal."); + DLT_STRING("Error: Invalid parameter type."); + DLT_STRING("Type:"); DLT_STRING(param_type)); + } +} + + +/** + * nhm_systemd_unit_properties_changed: + * @connection: Connection on which signal occurred. + * @sender_name: (Unique) Sender name of signal. + * @object_path: Object that send the signal. + * @interface_name: Interface from where signal comes from. + * @signal_name: Name of the signal. + * @parameters: Parameters of dbus signal. + * @user_data: User data. Pointer to unit for which properties changed + * signal had been registered. + * + * Called when the "PropertiesChanged" signal from the "Properties" interface + * of a systemd unit arrives. Depending on the changed property, the change + * will be processed further in the related sub functions. + */ +static void +nhm_systemd_unit_properties_changed(GDBusConnection *connection, + const gchar *sender_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *signal_name, + GVariant *parameters, + gpointer user_data) +{ + NhmSystemdUnit *unit = (NhmSystemdUnit*) user_data; + const gchar **inv_props = NULL; + NhmActiveState active_state = NHM_ACTIVE_STATE_UNKNOWN; + const gchar *param_type = NULL; + + param_type = g_variant_get_type_string(parameters); + + if(g_strcmp0(param_type, "(sa{sv}as)") == 0) + { + inv_props = g_variant_get_strv(g_variant_get_child_value(parameters, 2), + NULL); + + if(nhm_helper_str_in_strv("ActiveState", (gchar**) inv_props) == TRUE) + { + active_state = nhm_systemd_unit_get_active_state(unit); + + if(active_state != unit->active_state) + { + nhm_systemd_unit_active_state_changed(unit, active_state); + } + } + + g_free(inv_props); + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to process 'PropertiesChanged' signal."); + DLT_STRING("Error: Invalid parameter type."); + DLT_STRING("Type:"); DLT_STRING(param_type)); + } +} + + +/******************************************************************************* +* +* Interfaces. Exported functions. See Header for detailed description. +* +*******************************************************************************/ + +/** + * nhm_systemd_connect: + * @app_status_cb: Callback that should be called, if the "ActiveState" of + * a systemd Service changes between valid and invalid states. + * + * The NHM main process can start the systemd observation whith this function. + */ +gboolean +nhm_systemd_connect(NhmSystemdAppStatusCb app_status_cb) +{ + GVariantIter iter; + GError *error = NULL; + GVariant *manager_return = NULL; + GVariant *unit_array = NULL; + GVariant *unit = NULL; + gboolean retval = FALSE; + gchar *unit_name = NULL; + const gchar *active_state = NULL; + NhmSystemdUnit *new_unit = NULL; + + /* Initialize local variables */ + nhm_systemd_app_status_cb = NULL; + nhm_systemd_conn = NULL; + nhm_systemd_observed_units = NULL; + nhm_systemd_events_subscribed = FALSE; + nhm_systemd_unit_add_sig_id = 0; + nhm_systemd_unit_rem_sig_id = 0; + + /* Step 1: Save function to call if app status changes. */ + if(app_status_cb != NULL) + { + retval = TRUE; + nhm_systemd_app_status_cb = app_status_cb; + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to connect to systemd dbus."); + DLT_STRING("Error: Invalid callback passed.")); + } + + /* Step 2: Connect to the system bus */ + if(retval == TRUE) + { + nhm_systemd_conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + + if(error == NULL) + { + retval = TRUE; + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to connect to systemd dbus."); + DLT_STRING("Error: D-Bus connection failed."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + + /* Step 3: Register for signals, if units are removed/added */ + if(retval == TRUE) + { + nhm_systemd_unit_add_sig_id = + g_dbus_connection_signal_subscribe(nhm_systemd_conn, + NHM_SYSTEMD_BUS_NAME, + NHM_SYSTEMD_MNGR_IF, + "UnitNew", + NHM_SYSTEMD_OBJ_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + &nhm_systemd_unit_added, + NULL, + NULL); + + nhm_systemd_unit_rem_sig_id = + g_dbus_connection_signal_subscribe(nhm_systemd_conn, + NHM_SYSTEMD_BUS_NAME, + NHM_SYSTEMD_MNGR_IF, + "UnitRemoved", + NHM_SYSTEMD_OBJ_PATH, + NULL, + G_DBUS_SIGNAL_FLAGS_NONE, + &nhm_systemd_unit_removed, + NULL, + NULL); + } + + /* Step 4: Subscribe. Without, PropertiesChanged isn't send */ + if(retval == TRUE) + { + manager_return = g_dbus_connection_call_sync(nhm_systemd_conn, + NHM_SYSTEMD_BUS_NAME, + NHM_SYSTEMD_OBJ_PATH, + NHM_SYSTEMD_MNGR_IF, + "Subscribe", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if(error == NULL) + { + retval = TRUE; + nhm_systemd_events_subscribed = TRUE; + g_variant_unref(manager_return); + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to subscribe to systemd signals."); + DLT_STRING("Error: D-Bus connection failed."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + + /* Step 5: Retrieve all currently known service units from systemd. */ + if(retval == TRUE) + { + manager_return = + g_dbus_connection_call_sync(nhm_systemd_conn, + NHM_SYSTEMD_BUS_NAME, + NHM_SYSTEMD_OBJ_PATH, + NHM_SYSTEMD_MNGR_IF, + "ListUnits", + NULL, + (GVariantType*) "(a(ssssssouso))", + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + + if(error == NULL) + { + retval = TRUE; + + unit_array = g_variant_get_child_value(manager_return, 0); + g_variant_iter_init (&iter, unit_array); + + while((unit = g_variant_iter_next_value(&iter))) + { + /* Return for a unit is of type '(ssssssouso)' with member #: + * 0: Unit name. 3: Active state. 6: Object path */ + g_variant_get_child(unit, 0, "s", &unit_name); + + if(g_str_has_suffix(unit_name, ".service") == TRUE) + { + new_unit = g_new(NhmSystemdUnit, 1); + new_unit->name = unit_name; + + active_state = + g_variant_get_string(g_variant_get_child_value(unit, 3), NULL); + + new_unit->active_state = + nhm_systemd_active_state_string_to_enum(active_state); + + g_variant_get_child(unit, 6, "o", &new_unit->path); + + new_unit->sig_sub_id = + nhm_systemd_subscribe_properties_changed(new_unit); + + nhm_systemd_observed_units = + g_slist_append(nhm_systemd_observed_units, new_unit); + } + else + { + g_free(unit_name); + } + } + + g_variant_unref(manager_return); + } + else + { + retval = FALSE; + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to retrieve unit list from systemd."); + DLT_STRING("Error: D-Bus communication failed."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + + /* Step 6: If there was a problem, destroy what has been created */ + if(retval == FALSE) + { + nhm_systemd_disconnect(); + } + + return retval; +} + + +/** + * nhm_systemd_disconnect: + * + * The NHM main process should call this function, when systemd observation is + * no longer needed. + */ +void +nhm_systemd_disconnect(void) +{ + GVariant *manager_return = NULL; + GError *error = NULL; + + /* Reset callback */ + nhm_systemd_app_status_cb = NULL; + + /* Unsubscribe from systemd signals */ + if(nhm_systemd_events_subscribed == TRUE) + { + manager_return = + g_dbus_connection_call_sync(nhm_systemd_conn, + NHM_SYSTEMD_BUS_NAME, + NHM_SYSTEMD_OBJ_PATH, + NHM_SYSTEMD_MNGR_IF, + "Unsubscribe", + NULL, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if(error == NULL) + { + nhm_systemd_events_subscribed = FALSE; + g_variant_unref(manager_return); + } + else + { + DLT_LOG(nhm_helper_trace_ctx, + DLT_LOG_ERROR, + DLT_STRING("NHM: Failed to Unsubscribe from systemd."); + DLT_STRING("Error: D-Bus communication failed."); + DLT_STRING("Reason:"); DLT_STRING(error->message)); + g_error_free(error); + } + } + + /* Unregister unit add and remove signals */ + if(nhm_systemd_unit_add_sig_id != 0) + { + g_dbus_connection_signal_unsubscribe(nhm_systemd_conn, + nhm_systemd_unit_add_sig_id); + nhm_systemd_unit_add_sig_id = 0; + } + + if(nhm_systemd_unit_rem_sig_id != 0) + { + g_dbus_connection_signal_unsubscribe(nhm_systemd_conn, + nhm_systemd_unit_rem_sig_id); + nhm_systemd_unit_rem_sig_id = 0; + } + + /* Destroy list of units (incl. unregister prop. changed) */ + if(nhm_systemd_observed_units != NULL) + { + g_slist_free_full(nhm_systemd_observed_units, &nhm_systemd_free_unit); + nhm_systemd_observed_units = NULL; + } + + if(nhm_systemd_conn != NULL) + { + g_object_unref(nhm_systemd_conn); + nhm_systemd_conn = NULL; + } +} diff --git a/src/nhm-systemd.h b/src/nhm-systemd.h new file mode 100644 index 0000000..ef98688 --- /dev/null +++ b/src/nhm-systemd.h @@ -0,0 +1,47 @@ +#ifndef NHM_SYSTEMD +#define NHM_SYSTEMD + +/* NHM - NodeHealthMonitor + * + * Functions to observe system health with systemd + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> /* Use gtypes */ +#include "inc/NodeHealthMonitor.h" /* Use NHM app status defines */ + + +/******************************************************************************* +* +* Exported variables, constants and defines +* +*******************************************************************************/ + +typedef void (*NhmSystemdAppStatusCb)(const gchar *name, NhmAppStatus_e status); + + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +gboolean nhm_systemd_connect (NhmSystemdAppStatusCb app_status_cb); +void nhm_systemd_disconnect(void); + + +#endif /* NHM_SYSTEMD */ diff --git a/tst/Makefile.am b/tst/Makefile.am new file mode 100644 index 0000000..6e13eb8 --- /dev/null +++ b/tst/Makefile.am @@ -0,0 +1,104 @@ +################################################################################ +# +# Author: Jean-Pierre.Bogler@continental-corporation.com +# +# Makefile template for the NodeHealthMonitor unit test +# +# Process this file with automake to produce a Makefile.in. +# +# Copyright (C) 2013 Continental Automotive Systems, Inc. +# +# This Source Code Form is subject to the terms of the Mozilla Public License, +# v. 2.0. If a copy of the MPL was not distributed with this file, You can +# obtain one at http://mozilla.org/MPL/2.0/. +# +################################################################################ + + +# Create target for "make check" and test programs +check_PROGRAMS = nhm-main-test nhm-systemd-test + +# Sources for the NHM unit test +nhm_main_test_SOURCES = nhm-main-test.c \ + nhm-main-test.h \ + $(top_srcdir)/inc/NodeHealthMonitor.h \ + $(top_srcdir)/src/nhm-helper.c \ + $(top_srcdir)/src/nhm-helper.h \ + stubs/dlt/dlt-stub.c \ + stubs/dlt/dlt-stub.h \ + stubs/nhm/nhm-systemd-stub.c \ + stubs/nhm/nhm-systemd-stub.h \ + stubs/systemd/sd-daemon-stub.c \ + stubs/systemd/sd-daemon-stub.h \ + stubs/gio/gio-stub.c \ + stubs/gio/gio-stub.h \ + stubs/gen/nsm-dbus-lc-consumer-stub.c \ + stubs/gen/nsm-dbus-lc-consumer-stub.h \ + stubs/gen/nsm-dbus-consumer-stub.c \ + stubs/gen/nsm-dbus-consumer-stub.h \ + stubs/gen/nsm-dbus-lc-control-stub.c \ + stubs/gen/nsm-dbus-lc-control-stub.h \ + stubs/gen/nhm-dbus-info-stub.c \ + stubs/gen/nhm-dbus-info-stub.h \ + stubs/persistence/persistence_client_library_key-stub.c \ + stubs/persistence/persistence_client_library_key-stub.h + +# The unit test depends on the tested c file, but it should not be compiled in. +nhm_main_test_DEPENDENCIES = $(top_srcdir)/src/nhm-main.c + +# Sources for the NHM unit test that are compiled but not in distributed +nodist_nhm_main_test_SOURCES = $(top_srcdir)/gen/nhm-dbus-info.c \ + $(top_srcdir)/gen/nhm-dbus-info.h \ + $(top_srcdir)/gen/nsm-dbus-lc-control.c \ + $(top_srcdir)/gen/nsm-dbus-lc-control.h \ + $(top_srcdir)/gen/nsm-dbus-consumer.c \ + $(top_srcdir)/gen/nsm-dbus-consumer.h \ + $(top_srcdir)/gen/nsm-dbus-lc-consumer.c \ + $(top_srcdir)/gen/nsm-dbus-lc-consumer.h + +# Same C flags as real NHM, but use local directory for config and data +nhm_main_test_CFLAGS = -DCONFDIR=\"\" \ + -DDATADIR=\"\" \ + -I $(top_srcdir) \ + $(DLT_CFLAGS) \ + $(GIO_CFLAGS) \ + $(GIO_UNIX_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GOBJECT_CFLAGS) \ + $(SYSTEMD_CFLAGS) \ + $(NSM_CFLAGS) \ + $(PCL_CFLAGS) + +# Same libraries as real NHM +nhm_main_test_LDADD = $(GIO_LIBS) \ + $(GIO_UNIX_LIBS) \ + $(GLIB_LIBS) \ + $(GOBJECT_LIBS) + +############################# NHM systemd test ################################# + +nhm_systemd_test_SOURCES = nhm-systemd-test.c \ + nhm-systemd-test.h \ + $(top_srcdir)/src/nhm-systemd.h \ + $(top_srcdir)/src/nhm-helper.c \ + $(top_srcdir)/src/nhm-helper.h \ + stubs/dlt/dlt-stub.c \ + stubs/dlt/dlt-stub.h \ + stubs/gio/gio-stub.c \ + stubs/gio/gio-stub.h + +nhm_systemd_test_DEPENDENCIES = $(top_srcdir)/src/nhm-systemd.c + +nhm_systemd_test_CFLAGS = -I $(top_srcdir) \ + $(DLT_CFLAGS) \ + $(GIO_CFLAGS) \ + $(GIO_UNIX_CFLAGS) \ + $(GLIB_CFLAGS) \ + $(GOBJECT_CFLAGS) + +nhm_systemd_test_LDADD = $(GIO_LIBS) \ + $(GIO_UNIX_LIBS) \ + $(GLIB_LIBS) \ + $(GOBJECT_LIBS) + +TESTS = nhm-main-test nhm-systemd-test diff --git a/tst/nhm-main-test.c b/tst/nhm-main-test.c new file mode 100644 index 0000000..25a62ce --- /dev/null +++ b/tst/nhm-main-test.c @@ -0,0 +1,1110 @@ +/* NHM - NodeHealthMonitor + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + */ + +/** + * SECTION:nhm-unit-test + * @title: NodeHealthMonitor (NHM) unit test + * @short_description: Unit test for an automatic check of the NHM + * + * The unit test will stimulate the NHM and check for the expected reactions. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +/* Include glib to use gtypes */ +#include <glib-2.0/glib.h> +#include <stdlib.h> + +/* Include the stubbed main file of the NHM. Its functions will be tested! */ +#include "nhm-main-test.h" + + +/******************************************************************************* +* +* Local variables and constants +* +*******************************************************************************/ + +/* There are no local variables, define or constants */ + + +/******************************************************************************* +* +* Prototypes for file local functions (see implementation for description) +* +*******************************************************************************/ + +static gint nhm_test_main (void); +static gint nhm_test_load_config (void); +static gint nhm_test_connect_to_nsm (void); +static gint nhm_test_nhm_bus_callbacks (void); +static gint nhm_test_register_app_status (void); +static gint nhm_test_read_statistics (void); +static gint nhm_test_userland_check (void); +static gint nhm_test_watchdog (void); +static gint nhm_test_handle_lc_request (void); +static gint nhm_test_app_restart_request (void); +static gint nhm_test_is_dbus_alive (void); +static gint nhm_test_on_sigterm (void); + + +/******************************************************************************* +* +* Local (static) functions +* +*******************************************************************************/ + +/** + * nhm_test_handle_lc_request: + * + * Test reaction of NHM on LC request. + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint nhm_test_app_restart_request(void) +{ + gint retval = 0; + gchar* my_no_restart_apps[] = {"App1", "App2", NULL}; + + no_restart_apps = my_no_restart_apps; + + /* Check 1: Request from App3 (not on black list) */ + nsm_dbus_lc_control_call_request_node_restart_sync_stub_set_error = FALSE; + nsm_dbus_lc_control_call_request_node_restart_sync_stub_out_ErrorCode = NsmErrorStatus_Ok; + nhm_dbus_info_complete_request_node_restart_stub_ErrorStatus = NsmErrorStatus_NotSet; + nhm_main_request_node_restart_cb(NULL, NULL, "App3", NULL); + retval = ( nhm_dbus_info_complete_request_node_restart_stub_ErrorStatus + == NhmErrorStatus_Ok) ? 0 : -1; + + /* Check 2: Request from App1 (on black list) */ + if(retval == 0) + { + nhm_dbus_info_complete_request_node_restart_stub_ErrorStatus = NsmErrorStatus_NotSet; + nhm_main_request_node_restart_cb(NULL, NULL, "App1", NULL); + retval = ( nhm_dbus_info_complete_request_node_restart_stub_ErrorStatus + == NhmErrorStatus_RestartNotPossible) ? 0 : -1; + } + + no_restart_apps = NULL; + + return retval; +} + +/** + * nhm_test_handle_lc_request: + * + * Test reaction of NHM on LC request. + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint nhm_test_handle_lc_request(void) +{ + gint retval = 0; + + /* Check 1: Successful write of shutdown flag at "shutdown" request */ + pclKeyWriteData_stub_return = sizeof(NhmNodeState); + pclKeyWriteData_stub_WriteVal = 0; + nhm_main_lc_request_cb(NULL, NULL, NSM_SHUTDOWNTYPE_FAST, 0, NULL); + + /* Check that NHM wrote 'NHM_NODESTATE_SHUTDOWN' to persistence */ + if( ((NhmNodeState) pclKeyWriteData_stub_WriteVal + != NHM_NODESTATE_SHUTDOWN) + || ((NsmErrorStatus_e) nsm_dbus_lc_consumer_complete_lifecycle_request_stub_ErrorCode + != NsmErrorStatus_Ok)) + { + retval = -1; + } + + /* Check 2: Unsuccessful write of shutdown flag at "shutdown" request */ + if(retval == 0) + { + pclKeyWriteData_stub_return = -1; + pclKeyWriteData_stub_WriteVal = 0; + nhm_main_lc_request_cb(NULL, NULL, NSM_SHUTDOWNTYPE_NORMAL, 0, NULL); + + /* Check that NHM wrote 'NHM_NODESTATE_SHUTDOWN' to persistence */ + if( ((NhmNodeState) pclKeyWriteData_stub_WriteVal + != NHM_NODESTATE_SHUTDOWN) + || ((NsmErrorStatus_e) nsm_dbus_lc_consumer_complete_lifecycle_request_stub_ErrorCode + != NsmErrorStatus_Error)) + { + retval = -1; + } + } + + /* Check 3: Successful write of shutdown flag at "runup" request */ + if(retval == 0) + { + pclKeyWriteData_stub_return = sizeof(NhmNodeState); + pclKeyWriteData_stub_WriteVal = 0; + nhm_main_lc_request_cb(NULL, NULL, NSM_SHUTDOWNTYPE_RUNUP, 0, NULL); + + /* Check that NHM wrote 'NHM_NODESTATE_SHUTDOWN' to persistence */ + if( ((NhmNodeState) pclKeyWriteData_stub_WriteVal + != NHM_NODESTATE_STARTED) + || ((NsmErrorStatus_e) nsm_dbus_lc_consumer_complete_lifecycle_request_stub_ErrorCode + != NsmErrorStatus_Ok)) + { + retval = -1; + } + } + + /* Check 4: Unsuccessful write of shutdown flag at "runup" request */ + if(retval == 0) + { + pclKeyWriteData_stub_return = -1; + pclKeyWriteData_stub_WriteVal = 0; + nhm_main_lc_request_cb(NULL, NULL, NSM_SHUTDOWNTYPE_RUNUP, 0, NULL); + + /* Check that NHM wrote 'NHM_NODESTATE_SHUTDOWN' to persistence */ + if( ((NhmNodeState) pclKeyWriteData_stub_WriteVal + != NHM_NODESTATE_STARTED) + || ((NsmErrorStatus_e) nsm_dbus_lc_consumer_complete_lifecycle_request_stub_ErrorCode + != NsmErrorStatus_Error)) + { + retval = -1; + } + } + + return retval; +} + +/** + * nhm_test_watchdog: + * + * Tests the WDOG triggering of the NHM + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint nhm_test_watchdog(void) +{ + gint retval = 0; + + sd_notify_stub_called = FALSE; + nhm_main_timer_wdog_cb(NULL); + retval = (sd_notify_stub_called == TRUE) ? 0 : -1; + + return retval; +} + + +static gint nhm_test_is_dbus_alive(void) +{ + gint retval = 0; + NhmCheckedDbus *checked_dbus = g_new(NhmCheckedDbus, 1); + GdbusConnectionCallSyncStubCalls g_dbus_connection_call_sync_stub_calls[1]; + + /* Check 1: No conn. obtained. Conn. can't be obtained. Call fails. */ + checked_dbus->bus_addr = NULL; + checked_dbus->bus_conn = NULL; + g_dbus_connection_new_for_address_sync_stub_set_error = TRUE; + + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "GetId"; + g_dbus_connection_call_sync_stub_calls[0].rval = NULL; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + retval = nhm_main_is_dbus_alive(checked_dbus) == FALSE ? 0 : -1; + + /* Check 2: No conn. obtained. Conn. can be obtained. Call fails. */ + if(retval == 0) + { + checked_dbus->bus_addr = NULL; + checked_dbus->bus_conn = NULL; + g_dbus_connection_new_for_address_sync_stub_set_error = FALSE; + + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "GetId"; + g_dbus_connection_call_sync_stub_calls[0].rval = NULL; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + retval = nhm_main_is_dbus_alive(checked_dbus) == FALSE ? 0 : -1; + } + + /* Check 3: No conn. obtained. Conn. can be obtained. Call succeeds. */ + if(retval == 0) + { + checked_dbus->bus_addr = NULL; + checked_dbus->bus_conn = NULL; + g_dbus_connection_new_for_address_sync_stub_set_error = FALSE; + + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "GetId"; + g_dbus_connection_call_sync_stub_calls[0].rval = g_variant_new("()"); + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + retval = nhm_main_is_dbus_alive(checked_dbus) == TRUE ? 0 : -1; + } + + /* Check 4: Conn. obtained. Call succeeds. */ + if(retval == 0) + { + checked_dbus->bus_addr = NULL; + checked_dbus->bus_conn = g_object_new(G_TYPE_DBUS_CONNECTION, NULL); + + g_dbus_connection_new_for_address_sync_stub_set_error = FALSE; + + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "GetId"; + g_dbus_connection_call_sync_stub_calls[0].rval = g_variant_new("()"); + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + retval = nhm_main_is_dbus_alive(checked_dbus) == TRUE ? 0 : -1; + + g_object_unref(checked_dbus->bus_conn); + checked_dbus->bus_conn = NULL; + } + + /* Check 5: Conn. obtained. Call fails. */ + if(retval == 0) + { + checked_dbus->bus_addr = NULL; + checked_dbus->bus_conn = g_object_new(G_TYPE_DBUS_CONNECTION, NULL); + + g_dbus_connection_new_for_address_sync_stub_set_error = FALSE; + + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "GetId"; + g_dbus_connection_call_sync_stub_calls[0].rval = NULL; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + retval = nhm_main_is_dbus_alive(checked_dbus) == FALSE ? 0 : -1; + + g_object_unref(checked_dbus->bus_conn); + checked_dbus->bus_conn = NULL; + } + + nhm_main_free_checked_dbus(checked_dbus); + + return retval; +} + + +/** + * nhm_test_userland_check: + * + * Tests the userland check functionality of the NHM. + * + * Returns always 0, because NHM shows no reaction yet. + */ +static gint nhm_test_userland_check(void) +{ + gchar *my_monitored_files[] = {"missing_file", NULL}; + gchar *my_monitored_progs[] = {"invalid_prog", NULL}; + gchar *my_monitored_procs[] = {"/usr/bin/invalid_proc", NULL}; + NhmCheckedDbus my_checked_dbus = {NULL, NULL}; + + /* Check 1: No monitored files. No monitored progs. No monitored procs. No monitored dbus */ + monitored_files = NULL; + monitored_progs = NULL; + monitored_procs = NULL; + checked_dbusses = NULL; + + nhm_main_timer_userland_check_cb(NULL); + + nhm_main_free_check_objects(); + nhm_main_free_config_objects(); + + /* Check 2: No monitored files. No monitored progs. Monitored procs. nok. No monitored dbus. */ + monitored_files = NULL; + monitored_progs = NULL; + monitored_procs = g_strdupv(my_monitored_procs); + checked_dbusses = NULL; + + nhm_main_timer_userland_check_cb(NULL); + + nhm_main_free_check_objects(); + nhm_main_free_config_objects(); + + /* Check 3: No monitored files. No monitored progs. Monitored procs. ok. No monitored dbus. */ + monitored_files = NULL; + monitored_progs = NULL; + my_monitored_procs[0] = "valid_proc"; + monitored_procs = g_strdupv(my_monitored_procs); + checked_dbusses = NULL; + + nhm_main_timer_userland_check_cb(NULL); + + nhm_main_free_check_objects(); + nhm_main_free_config_objects(); + + /* Check 4: No monitored files. monitored progs nok. Monitored procs. ok. No monitored dbus. */ + monitored_files = NULL; + monitored_progs = g_strdupv(my_monitored_progs); + monitored_procs = g_strdupv(my_monitored_procs); + checked_dbusses = NULL; + nhm_main_timer_userland_check_cb(NULL); + + nhm_main_free_check_objects(); + nhm_main_free_config_objects(); + + /* Check 5: No monitored files. monitored progs ok. Monitored procs. ok. No monitored dbus. */ + monitored_files = NULL; + my_monitored_progs[0] = "/usr/bin/valid_prog1"; + monitored_progs = g_strdupv(my_monitored_progs); + monitored_procs = g_strdupv(my_monitored_procs); + checked_dbusses = NULL; + nhm_main_timer_userland_check_cb(NULL); + + nhm_main_free_check_objects(); + nhm_main_free_config_objects(); + + /* Check 6: monitored files nok. monitored progs ok. Monitored procs. ok. No monitored dbus. */ + monitored_files = g_strdupv(my_monitored_files); + monitored_progs = g_strdupv(my_monitored_progs); + monitored_procs = g_strdupv(my_monitored_procs); + checked_dbusses = NULL; + nhm_main_timer_userland_check_cb(NULL); + + nhm_main_free_check_objects(); + nhm_main_free_config_objects(); + + /* Check 7: monitored files ok. monitored progs ok. Monitored procs. ok. No monitored dbus. */ + my_monitored_files[0] = "valid_file"; + monitored_files = g_strdupv(my_monitored_files); + monitored_progs = g_strdupv(my_monitored_progs); + monitored_procs = g_strdupv(my_monitored_procs); + checked_dbusses = NULL; + nhm_main_timer_userland_check_cb(NULL); + + nhm_main_free_check_objects(); + nhm_main_free_config_objects(); + + /* Check 8: monitored files ok. monitored progs ok. Monitored procs. ok. Monitored dbus nok */ + monitored_files = g_strdupv(my_monitored_files); + monitored_progs = g_strdupv(my_monitored_progs); + monitored_procs = g_strdupv(my_monitored_procs); + checked_dbusses = g_ptr_array_new(); + + g_ptr_array_add(checked_dbusses, (gpointer) &my_checked_dbus); + g_dbus_connection_new_for_address_sync_stub_set_error = TRUE; + g_dbus_connection_new_for_address_sync_stub_set_error = TRUE; + nhm_main_timer_userland_check_cb(NULL); + + nhm_main_free_check_objects(); + nhm_main_free_config_objects(); + + /* Check 9: monitored files ok. monitored progs ok. Monitored procs. ok. Monitored dbus ok */ + monitored_files = g_strdupv(my_monitored_files); + monitored_progs = g_strdupv(my_monitored_progs); + monitored_procs = g_strdupv(my_monitored_procs); + checked_dbusses = g_ptr_array_new(); + + g_ptr_array_add(checked_dbusses, (gpointer) &my_checked_dbus); + g_dbus_connection_new_for_address_sync_stub_set_error = FALSE; + g_dbus_connection_new_for_address_sync_stub_set_error = FALSE; + nhm_main_timer_userland_check_cb(NULL); + + nhm_main_free_check_objects(); + nhm_main_free_config_objects(); + + return 0; +} + + +/** + * nhm_test_read_statistics: + * + * Tests the read statistics dbus interface of the NHM. + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint nhm_test_read_statistics(void) +{ + guint app_idx = 0; + NhmLcInfo *lc_info[3] = {0}; + NhmFailedApp *lc_apps[5] = {0}; + NhmCurrentFailedApp *current_failed_app[3] = {0}; + gint retval = 0; + + /* + * Create initial nodeinfo for the test: + * + * LC1: NHM_NODESTATE_SHUTDOWN. (App1, 3), (App2, 4), (App3, 5) + * LC2: NHM_NODESTATE_STARTED. (App1, 4), (App2, 5) + * LC3: NHM_NODESTATE_SHUTDOWN. NULL + */ + + /* Create five apps that will be assigned to the LCs */ + lc_apps[0] = g_new(NhmFailedApp, 1); + lc_apps[0]->name = g_strdup("App1"); + lc_apps[0]->failcount = 3; + + lc_apps[1] = g_new(NhmFailedApp, 1); + lc_apps[1]->name = g_strdup("App2"); + lc_apps[1]->failcount = 4; + + lc_apps[2] = g_new(NhmFailedApp, 1); + lc_apps[2]->name = g_strdup("App3"); + lc_apps[2]->failcount = 5; + + lc_apps[3] = g_new(NhmFailedApp, 1); + lc_apps[3]->name = g_strdup("App1"); + lc_apps[3]->failcount = 4; + + lc_apps[4] = g_new(NhmFailedApp, 1); + lc_apps[4]->name = g_strdup("App2"); + lc_apps[4]->failcount = 5; + + /* Create three LCs */ + lc_info[0] = g_new(NhmLcInfo, 1); + lc_info[0]->start_state = NHM_NODESTATE_SHUTDOWN; + lc_info[0]->failed_apps = NULL; + + lc_info[1] = g_new(NhmLcInfo, 1); + lc_info[1]->start_state = NHM_NODESTATE_STARTED; + lc_info[1]->failed_apps = NULL; + + lc_info[2] = g_new(NhmLcInfo, 1); + lc_info[2]->start_state = NHM_NODESTATE_SHUTDOWN; + lc_info[2]->failed_apps = NULL; + + /* Add lc_apps[0], lc_apps[1] and lc_apps[2] to list of LC1 */ + lc_info[0]->failed_apps = g_slist_append(lc_info[0]->failed_apps, lc_apps[0]); + lc_info[0]->failed_apps = g_slist_append(lc_info[0]->failed_apps, lc_apps[1]); + lc_info[0]->failed_apps = g_slist_append(lc_info[0]->failed_apps, lc_apps[2]); + + /* Add lc_apps[4] and lc_apps[5] to list of LC2*/ + lc_info[1]->failed_apps = g_slist_append(lc_info[1]->failed_apps, lc_apps[3]); + lc_info[1]->failed_apps = g_slist_append(lc_info[1]->failed_apps, lc_apps[4]); + + /* Create array and add LCs */ + nodeinfo = g_ptr_array_new_with_free_func(&nhm_main_free_lc_info); + g_ptr_array_add(nodeinfo, lc_info[0]); + g_ptr_array_add(nodeinfo, lc_info[1]); + g_ptr_array_add(nodeinfo, lc_info[2]); + + /* + * Create initial list of current failed apps: App1, App2, app3 + */ + current_failed_app[0] = g_new(NhmCurrentFailedApp, 1); + current_failed_app[0]->name = g_strdup("App1"); + + current_failed_app[1] = g_new(NhmCurrentFailedApp, 1); + current_failed_app[1]->name = g_strdup("App2"); + + current_failed_app[2] = g_new(NhmCurrentFailedApp, 1); + current_failed_app[2]->name = g_strdup("App3"); + + current_failed_apps = NULL; + for(app_idx = 0; app_idx < sizeof(current_failed_app)/sizeof(NhmCurrentFailedApp); app_idx++) + { + current_failed_apps = g_slist_append(current_failed_apps, current_failed_app[app_idx]); + } + + /* Check 1: Request info for "App1" for up to 5 LCs => 3 LCs are delivered */ + max_lc_count = 5; + + nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalFailures = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles = 0; + + nhm_main_read_statistics_cb(NULL, NULL, "App1", NULL); + + retval = ( (nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount == 3) + && (nhm_dbus_info_complete_read_statistics_stub_TotalFailures == 7) + && (nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles == 3)) ? 0 : -1; + + /* Check 2: Request info for "App1" for up to 1 LCs => 1 LC is delivered */ + if(retval == 0) + { + max_lc_count = 0; + + nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalFailures = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles = 0; + + nhm_main_read_statistics_cb(NULL, NULL, "App1", NULL); + + retval = ( (nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount == 3) + && (nhm_dbus_info_complete_read_statistics_stub_TotalFailures == 3) + && (nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles == 1)) ? 0 : -1; + } + + /* Check 3: Request node info for up to 5 LCs => 3 LCs are delivered */ + if(retval == 0) + { + max_lc_count = 5; + + nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalFailures = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles = 0; + + nhm_main_read_statistics_cb(NULL, NULL, "", NULL); + + retval = ( (nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount == 3) + && (nhm_dbus_info_complete_read_statistics_stub_TotalFailures == 1) + && (nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles == 3)) ? 0 : -1; + } + + /* Check 4: Request node info for up to 2 LCs => 2 LCs are delivered */ + if(retval == 0) + { + max_lc_count = 1; + + nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalFailures = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles = 0; + + nhm_main_read_statistics_cb(NULL, NULL, "", NULL); + + retval = ( (nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount == 3) + && (nhm_dbus_info_complete_read_statistics_stub_TotalFailures == 1) + && (nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles == 2)) ? 0 : -1; + } + + /* Check 5: Request app info for App4 for up to 2 LCs => 2 LCs are delivered */ + if(retval == 0) + { + max_lc_count = 1; + + nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalFailures = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles = 0; + + nhm_main_read_statistics_cb(NULL, NULL, "App4", NULL); + + retval = ( (nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount == 0) + && (nhm_dbus_info_complete_read_statistics_stub_TotalFailures == 0) + && (nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles == 2)) ? 0 : -1; + } + + /* Check 6: No current failed apps. Request node info for 2 LCs */ + if(retval == 0) + { + max_lc_count = 1; + + if(current_failed_apps != NULL) + { + g_slist_free_full(current_failed_apps, &nhm_main_free_current_failed_app); + current_failed_apps = NULL; + } + + nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalFailures = 0; + nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles = 0; + + nhm_main_read_statistics_cb(NULL, NULL, "", NULL); + + retval = ( (nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount == 0) + && (nhm_dbus_info_complete_read_statistics_stub_TotalFailures == 1) + && (nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles == 2)) ? 0 : -1; + } + + /* Clean up objects after test */ + if(current_failed_apps != NULL) + { + g_slist_free_full(current_failed_apps, &nhm_main_free_current_failed_app); + } + + g_ptr_array_unref(nodeinfo); + + return retval; +} + +/** + * nhm_test_register_app_status: + * + * Tests the register app status dbus interface of the NHM. + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint +nhm_test_register_app_status(void) +{ + gint retval = 0; + NhmLcInfo *initial_lc_info = g_new(NhmLcInfo, 1); + gchar *rmcmd = NULL; + + initial_lc_info->start_state = NHM_NODESTATE_SHUTDOWN; + initial_lc_info->failed_apps = NULL; + + nodeinfo = g_ptr_array_new_with_free_func(&nhm_main_free_lc_info); + g_ptr_array_add(nodeinfo, initial_lc_info); + current_failed_apps = NULL; + + /* Check 1: App1 fails. NSM nok => App1 in current_failed_apps */ + nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error = TRUE; + nhm_main_register_app_status_cb(NULL, NULL, "App1", NhmAppStatus_Failed, NULL); + retval = (nhm_main_find_current_failed_app("App1") != NULL) ? 0 : -1; + + /* Check 2: App2 fails. NSM ok => App2 in current_failed_apps */ + if(retval == 0) + { + nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error = FALSE; + nhm_main_register_app_status_cb(NULL, NULL, "App2", NhmAppStatus_Failed, NULL); + retval = (nhm_main_find_current_failed_app("App2") != NULL) ? 0 : -1; + } + + /* Check 3: App1 becomes valid. NSM ok => App1 not in current_failed_apps */ + if(retval == 0) + { + nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error = FALSE; + nhm_main_register_app_status_cb(NULL, NULL, "App1", NhmAppStatus_Ok, NULL); + retval = (nhm_main_find_current_failed_app("App1") == NULL) ? 0 : -1; + } + + /* Check 4: App2 becomes valid. NSM ok => App2 not in current_failed_apps */ + if(retval == 0) + { + nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error = FALSE; + nhm_main_register_app_status_cb(NULL, NULL, "App2", NhmAppStatus_Ok, NULL); + retval = (nhm_main_find_current_failed_app("App2") == NULL) ? 0 : -1; + } + + /* Check 5: App1 becomes valid. NSM ok => App1 not in current_failed_apps */ + if(retval == 0) + { + nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error = FALSE; + nhm_main_register_app_status_cb(NULL, NULL, "App1", NhmAppStatus_Ok, NULL); + retval = (nhm_main_find_current_failed_app("App1") == NULL) ? 0 : -1; + } + + /* Check 6: App1 fails. NSM ok => App1 in current_failed_apps */ + if(retval == 0) + { + nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error = FALSE; + nhm_main_register_app_status_cb(NULL, NULL, "App1", NhmAppStatus_Failed, NULL); + retval = (nhm_main_find_current_failed_app("App1") != NULL) ? 0 : -1; + } + + /* Check 7: App1 fails. NSM ok => App1 in current_failed_apps */ + if(retval == 0) + { + nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error = FALSE; + nhm_main_register_app_status_cb(NULL, NULL, "App1", NhmAppStatus_Failed, NULL); + retval = (nhm_main_find_current_failed_app("App1") != NULL) ? 0 : -1; + } + + /* Clean up objects created during the test */ + if(current_failed_apps != NULL) + { + g_slist_free_full(current_failed_apps, &nhm_main_free_current_failed_app); + } + + g_ptr_array_unref(nodeinfo); + + rmcmd = g_strdup_printf("rm %s", NHM_LC_DATA_FILE); + system(rmcmd); + g_free(rmcmd); + + return retval; +} + + +/** + * nhm_test_nhm_bus_callbacks: + * + * Tests the bus connection callbacks for the NHM dbus connection. + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint +nhm_test_nhm_bus_callbacks(void) +{ + gint retval = 0; + GDBusConnection *busconn = NULL; + + /* Check 1: BusAcquired. Interface export ok => Mainloop should not be quit */ + busconn = g_object_new(G_TYPE_DBUS_CONNECTION, NULL); + g_main_loop_quit_stub_called = FALSE; + g_dbus_interface_skeleton_export_stub_set_error = FALSE; + nhm_main_bus_acquired_cb(busconn, NULL, NULL); + retval = (g_main_loop_quit_stub_called == FALSE) ? 0 : -1; + nhm_main_free_nhm_objects(); + g_object_unref(busconn); + + /* Check 2: BusAcquired. IF export fails => Mainloop should quit */ + if(retval == 0) + { + busconn = g_object_new(G_TYPE_DBUS_CONNECTION, NULL); + g_main_loop_quit_stub_called = FALSE; + g_dbus_interface_skeleton_export_stub_set_error = TRUE; + nhm_main_bus_acquired_cb(busconn, NULL, NULL); + retval = (g_main_loop_quit_stub_called == TRUE) ? 0 : -1; + nhm_main_free_nhm_objects(); + g_object_unref(busconn); + } + + /* Check 3: NameAcquired. No UL checks => No timer scheduled */ + if(retval == 0) + { + nodeinfo = g_ptr_array_new_with_free_func(&nhm_main_free_lc_info); + ul_chk_interval = 0; + + g_timeout_add_seconds_called = FALSE; + g_timeout_add_seconds_called_interval = 0; + + nhm_main_name_acquired_cb(NULL, NULL, NULL); + + retval = (g_timeout_add_seconds_called == FALSE) ? 0 : -1; + g_ptr_array_unref(nodeinfo); + } + + /* Check 4: NameAcquired. UL check enabled => Timer is scheduled */ + if(retval == 0) + { + nodeinfo = g_ptr_array_new_with_free_func(&nhm_main_free_lc_info); + ul_chk_interval = 10000; + + g_timeout_add_seconds_called = FALSE; + g_timeout_add_seconds_called_interval = 0; + + nhm_main_name_acquired_cb(NULL, NULL, NULL); + + retval = ( (g_timeout_add_seconds_called == TRUE ) + && (g_timeout_add_seconds_called_interval == 10000)) ? 0 : -1; + g_ptr_array_unref(nodeinfo); + } + + /* Check 5: NameLost. Connection not established => Quit Mainloop */ + if(retval == 0) + { + g_main_loop_quit_stub_called = FALSE; + nhm_main_name_lost_cb(NULL, NULL, NULL); + retval = (g_main_loop_quit_stub_called == TRUE) ? 0 : -1; + } + + /* Check 6: NameLost. Name lost => Quit Mainloop */ + if(retval == 0) + { + g_main_loop_quit_stub_called = FALSE; + nhm_main_name_lost_cb((GDBusConnection*) 0x00000001, NULL, NULL); + retval = (g_main_loop_quit_stub_called == TRUE) ? 0 : -1; + } + + return retval; +} + + +/** + * nhm_test_connect_to_nsm: + * + * Will test what happens if there is an error when connecting to the NSM. + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint +nhm_test_connect_to_nsm(void) +{ + gint retval = 0; + + /* Check 1: Bus connection fails */ + if(retval == 0) + { + g_bus_get_sync_set_error = TRUE; + retval = (nhm_main_connect_to_nsm() == FALSE) ? 0 : -1; + nhm_main_free_nsm_objects(); + } + + /* Check 2: Bus connection: ok. LifecycleControl: nok */ + if(retval == 0) + { + g_bus_get_sync_set_error = FALSE; + nsm_dbus_lc_control_proxy_new_sync_stub_set_error = TRUE; + retval = (nhm_main_connect_to_nsm() == FALSE) ? 0 : -1; + nhm_main_free_nsm_objects(); + } + + /* Check 3: Bus connection: ok. LifecycleControl: ok. NodeStateConsumer: nok */ + if(retval == 0) + { + g_bus_get_sync_set_error = FALSE; + nsm_dbus_lc_control_proxy_new_sync_stub_set_error = FALSE; + nsm_dbus_consumer_proxy_new_sync_stub_set_error = TRUE; + retval = (nhm_main_connect_to_nsm() == FALSE) ? 0 : -1; + nhm_main_free_nsm_objects(); + } + + /* Check 4: Bus connection: ok. LifecycleControl: ok. NodeStateConsumer: ok. Client reg: ok. IF export: nok */ + if(retval == 0) + { + g_bus_get_sync_set_error = FALSE; + nsm_dbus_lc_control_proxy_new_sync_stub_set_error = FALSE; + nsm_dbus_consumer_proxy_new_sync_stub_set_error = FALSE; + g_dbus_interface_skeleton_export_stub_set_error = TRUE; + retval = (nhm_main_connect_to_nsm() == FALSE) ? 0 : -1; + nhm_main_free_nsm_objects(); + } + + /* Check 5: Bus connection: ok. LifecycleControl: ok. NodeStateConsumer: ok. Client reg: ok. IF export: ok. Reg: nok I */ + if(retval == 0) + { + g_bus_get_sync_set_error = FALSE; + nsm_dbus_lc_control_proxy_new_sync_stub_set_error = FALSE; + nsm_dbus_consumer_proxy_new_sync_stub_set_error = FALSE; + g_dbus_interface_skeleton_export_stub_set_error = FALSE; + nsm_dbus_consumer_call_register_shutdown_client_sync_stub_set_error = TRUE; + retval = (nhm_main_connect_to_nsm() == FALSE) ? 0 : -1; + nhm_main_free_nsm_objects(); + } + + /* Check 6: Bus connection: ok. LifecycleControl: ok. NodeStateConsumer: ok. Client reg: ok. IF export: ok. Reg: nok II */ + if(retval == 0) + { + g_bus_get_sync_set_error = FALSE; + nsm_dbus_lc_control_proxy_new_sync_stub_set_error = FALSE; + nsm_dbus_consumer_proxy_new_sync_stub_set_error = FALSE; + g_dbus_interface_skeleton_export_stub_set_error = FALSE; + nsm_dbus_consumer_call_register_shutdown_client_sync_stub_set_error = FALSE; + nsm_dbus_consumer_call_register_shutdown_client_sync_stub_out_ErrorCode = NsmErrorStatus_Error; + retval = (nhm_main_connect_to_nsm() == FALSE) ? 0 : -1; + nhm_main_free_nsm_objects(); + } + + /* Check 7: Bus connection: ok. LifecycleControl: ok. NodeStateConsumer: ok. Client reg: ok. IF export: ok. Reg: ok */ + if(retval == 0) + { + g_bus_get_sync_set_error = FALSE; + nsm_dbus_lc_control_proxy_new_sync_stub_set_error = FALSE; + nsm_dbus_consumer_proxy_new_sync_stub_set_error = FALSE; + g_dbus_interface_skeleton_export_stub_set_error = FALSE; + nsm_dbus_consumer_call_register_shutdown_client_sync_stub_set_error = FALSE; + nsm_dbus_consumer_call_register_shutdown_client_sync_stub_out_ErrorCode = NsmErrorStatus_Ok; + retval = (nhm_main_connect_to_nsm() == TRUE) ? 0 : -1; + nhm_main_free_nsm_objects(); + } + + return retval; +} + + +/** + * nhm_test_load_config: + * + * Will test loading of different formated config files. + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint +nhm_test_load_config(void) +{ + gint retval = 0; + + /* Check 1: Check if the default config file is correctly loaded */ + system("cp ../cfg/node-health-monitor.conf ./"); + + nhm_main_load_config(); + + retval = (max_lc_count == 5 ) + && (max_failed_apps == 8 ) + && (no_restart_apps == NULL) + && (ul_chk_interval == 0 ) + && (monitored_files == NULL) + && (monitored_procs == NULL) + && (monitored_progs == NULL) ? 0 : -1; + + nhm_main_free_config_objects(); + + /* Check 2: Check handling if unsigned setting contains neg. value */ + if(retval == 0) + { + system("sed -i 's/historic_lc_count = 5/historic_lc_count = -1/g' node-health-monitor.conf"); + + nhm_main_load_config(); + + retval = (max_lc_count == 0 ) + && (max_failed_apps == 8 ) + && (no_restart_apps == NULL) + && (ul_chk_interval == 0 ) + && (monitored_files == NULL) + && (monitored_procs == NULL) + && (monitored_progs == NULL) ? 0 : -1; + + nhm_main_free_config_objects(); + } + + /* Check 3: Check handling of missing unsigned keys */ + if(retval == 0) + { + system("sed -i 's/historic_lc_count = -1//g' node-health-monitor.conf"); + + nhm_main_load_config(); + + retval = (max_lc_count == 0 ) + && (max_failed_apps == 8 ) + && (no_restart_apps == NULL) + && (ul_chk_interval == 0 ) + && (monitored_files == NULL) + && (monitored_procs == NULL) + && (monitored_progs == NULL) ? 0 : -1; + + nhm_main_free_config_objects(); + } + + /* Check 4: Check handling of missing string keys */ + if(retval == 0) + { + system("sed -i 's/no_restart_apps =//g' node-health-monitor.conf"); + + nhm_main_load_config(); + + retval = (max_lc_count == 0 ) + && (max_failed_apps == 8 ) + && (no_restart_apps == NULL) + && (ul_chk_interval == 0 ) + && (monitored_files == NULL) + && (monitored_procs == NULL) + && (monitored_progs == NULL) ? 0 : -1; + + nhm_main_free_config_objects(); + } + + /* Check 5: Load some valid values */ + if(retval == 0) + { + system("sed -i 's/ul_chk_interval = 0/ul_chk_interval = 10/g' node-health-monitor.conf"); + system("sed -i 's/monitored_files =/monitored_files = File1;File2/g' node-health-monitor.conf"); + + nhm_main_load_config(); + + retval = (max_lc_count == 0 ) + && (max_failed_apps == 8 ) + && (no_restart_apps == NULL) + && (ul_chk_interval == 10 ) + && (monitored_files != NULL) + && (strcmp(monitored_files[0], "File1") == 0 ) + && (strcmp(monitored_files[1], "File2") == 0 ) + && (monitored_files[2] == NULL) + && (monitored_procs == NULL) + && (monitored_progs == NULL) ? 0 : -1; + + nhm_main_free_config_objects(); + } + + system("rm -rf node-health-monitor.conf"); + + return retval; +} + + +/** + * nhm_test_main: + * + * Will check the main function and its embedded calls to nhm_main_load_config + * and nhm_main_nsm_connect. + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint +nhm_test_main(void) +{ + gint retval = -1; + + /* Preparation for 'nhm_main_nsm_connect': + * Bus connection: ok. LifecycleControl: ok. NodeStateConsumer: ok. Client reg: ok. IF export: ok. Reg: ok + * => nhm_main_nsm_connect returns 'TRUE', should nhm_main proceed + */ + g_bus_get_sync_set_error = FALSE; + nsm_dbus_lc_consumer_proxy_new_sync_stub_set_error = FALSE; + nsm_dbus_consumer_proxy_new_sync_stub_set_error = FALSE; + g_dbus_interface_skeleton_export_stub_set_error = FALSE; + nsm_dbus_consumer_call_register_shutdown_client_sync_stub_set_error = FALSE; + nsm_dbus_consumer_call_register_shutdown_client_sync_stub_out_ErrorCode = NsmErrorStatus_Ok; + + /* Call main */ + retval = (nhm_main() == EXIT_FAILURE) ? 0 : -1; + + /* Preparation for 'nhm_main_nsm_connect': + * Bus connection: nok. + * => nhm_main_nsm_connect returns 'FALSE', should nhm_main fail + */ + if(retval == 0) + { + mainreturn = EXIT_SUCCESS; + g_bus_get_sync_set_error = TRUE; + + /* Call main */ + retval = (nhm_main() == EXIT_FAILURE) ? 0 : -1; + } + + return retval; +} + +/** + * nhm_test_on_sigterm: + * + * Will check the 'nhm_test_on_sigterm' function. + * + * Returns 0, if test succeeds. Otherwise, it will return -1. + */ +static gint +nhm_test_on_sigterm(void) +{ + g_main_loop_quit_stub_called = FALSE; + + nhm_main_on_sigterm(NULL); + + return ( (g_main_loop_quit_stub_called == TRUE) + && (mainreturn == EXIT_SUCCESS )) ? 0 : -1; +} + + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + +/** + * main: + * + * Main function of the unit test. + * + * Return value: 0 if all tests succeeded. Otherwise -1. + */ +int +main(void) +{ + int retval = 0; + + /* Test 1: Test the main function of the NHM */ + retval = (retval == 0) ? nhm_test_main() : -1; + + /* Test 2: Test loading and handling of configuration */ + retval = (retval == 0) ? nhm_test_load_config() : -1; + + /* Test 3: Test NSM connection */ + retval = (retval == 0) ? nhm_test_connect_to_nsm() : -1; + + /* Test 4: Test NHM bus connection callbacks */ + retval = (retval == 0) ? nhm_test_nhm_bus_callbacks() : -1; + + /* Test 5: Test NHM register_app_status dbus interface */ + retval = (retval == 0) ? nhm_test_register_app_status() : -1; + + /* Test 6: Test NHM read_statistics dbus interface */ + retval = (retval == 0) ? nhm_test_read_statistics() : -1; + + /* Test 7: Test NHM request node restart dbus interface */ + retval = (retval == 0) ? nhm_test_app_restart_request() : -1; + + /* Test 8: Test NHM user land check functionality */ + retval = (retval == 0) ? nhm_test_userland_check() : -1; + + /* Test 9: Test NHM WDOG handling */ + retval = (retval == 0) ? nhm_test_watchdog() : -1; + + /* Test 10: Test NHM LC request handling */ + retval = (retval == 0) ? nhm_test_handle_lc_request() : -1; + + /* Test 11: Test dbus alive */ + retval = (retval == 0) ? nhm_test_is_dbus_alive() : -1; + + /* Test 12: Test SIGTERM */ + retval = (retval == 0) ? nhm_test_on_sigterm() : -1; + + return retval; +} diff --git a/tst/nhm-main-test.h b/tst/nhm-main-test.h new file mode 100644 index 0000000..cf32ef5 --- /dev/null +++ b/tst/nhm-main-test.h @@ -0,0 +1,235 @@ +/* NHM - NodeHealthMonitor + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + */ + +/* + * This header file is only used for the unit test. It: + * - Includes headers with stubbed function definitions + * - Redefines the name of real functions to the stub names + * - Includes the main, which will be patched to use the stubs + * - Undefine stubs, to allow usage of the real functions for the tests + */ + +#ifndef NHM_TEST_MAIN_H +#define NHM_MAIN_TEST_H + +/* Include stub header files */ +#include <tst/stubs/gen/nhm-dbus-info-stub.h> +#include <tst/stubs/gen/nsm-dbus-consumer-stub.h> +#include <tst/stubs/gen/nsm-dbus-lc-control-stub.h> +#include <tst/stubs/gen/nsm-dbus-lc-consumer-stub.h> +#include <tst/stubs/gio/gio-stub.h> +#include <tst/stubs/dlt/dlt-stub.h> +#include <tst/stubs/nhm/nhm-systemd-stub.h> +#include <tst/stubs/systemd/sd-daemon-stub.h> +#include <tst/stubs/persistence/persistence_client_library_key-stub.h> + +/* Redefine some functions to stubs */ +#define nhm_systemd_connect \ + nhm_systemd_connect_stub + +#define nhm_systemd_disconnect \ + nhm_systemd_disconnect_stub + +#define dlt_register_app \ + dlt_register_app_stub + +#define dlt_check_library_version \ + dlt_check_library_version_stub + +#define dlt_register_context \ + dlt_register_context_stub + +#define dlt_unregister_context \ + dlt_unregister_context_stub + +#define dlt_unregister_app \ + dlt_unregister_app_stub + +#define dlt_user_log_write_start \ + dlt_user_log_write_start_stub + +#define dlt_user_log_write_finish \ + dlt_user_log_write_finish_stub + +#define dlt_user_log_write_string \ + dlt_user_log_write_string_stub + +#define dlt_user_log_write_int \ + dlt_user_log_write_int_stub + +#define dlt_user_log_write_uint \ + dlt_user_log_write_uint_stub + +#define nhm_dbus_info_emit_app_health_status \ + nhm_dbus_info_emit_app_health_status_stub + +#define nhm_dbus_info_complete_register_app_status \ + nhm_dbus_info_complete_register_app_status_stub + +#define nhm_dbus_info_complete_read_statistics \ + nhm_dbus_info_complete_read_statistics_stub + +#define nhm_dbus_info_complete_request_node_restart \ + nhm_dbus_info_complete_request_node_restart_stub + +#define nsm_dbus_consumer_proxy_new_sync \ + nsm_dbus_consumer_proxy_new_sync_stub + +#define nsm_dbus_consumer_call_register_shutdown_client_sync \ + nsm_dbus_consumer_call_register_shutdown_client_sync_stub + +#define nsm_dbus_lc_consumer_proxy_new_sync \ + nsm_dbus_lc_consumer_proxy_new_sync_stub + +#define nsm_dbus_lc_consumer_complete_lifecycle_request \ + nsm_dbus_lc_consumer_complete_lifecycle_request_stub + +#define nsm_dbus_lc_control_proxy_new_sync \ + nsm_dbus_lc_control_proxy_new_sync_stub + +#define nsm_dbus_lc_control_call_set_app_health_status_sync \ + nsm_dbus_lc_control_call_set_app_health_status_sync_stub + +#define nsm_dbus_lc_control_call_request_node_restart_sync \ + nsm_dbus_lc_control_call_request_node_restart_sync_stub + +#define g_file_test \ + g_file_test_stub + +#define g_file_read_link \ + g_file_read_link_stub + +#define g_dir_open \ + g_dir_open_stub + +#define g_dir_read_name \ + g_dir_read_name_stub + +#define g_dir_close \ + g_dir_close_stub + +#define g_main_loop_run \ + g_main_loop_run_stub + +#define g_main_loop_quit \ + g_main_loop_quit_stub + +#define g_bus_get_sync \ + g_bus_get_sync_stub + +#define g_dbus_connection_get_unique_name \ + g_dbus_connection_get_unique_name_stub + +#define g_bus_own_name \ + g_bus_own_name_stub + +#define g_dbus_interface_skeleton_export \ + g_dbus_interface_skeleton_export_stub + +#define g_dbus_connection_new_for_address_sync \ + g_dbus_connection_new_for_address_sync_stub + +#define g_dbus_connection_call_sync \ + g_dbus_connection_call_sync_stub + +#define g_dbus_connection_signal_subscribe \ + g_dbus_connection_signal_subscribe_stub + +#define g_dbus_connection_signal_unsubscribe \ + g_dbus_connection_signal_unsubscribe_stub + +#define g_dbus_connection_call_sync \ + g_dbus_connection_call_sync_stub + +#define g_timeout_add_seconds \ + g_timeout_add_seconds_stub + +#define g_signal_connect_data \ + g_signal_connect_data_stub + +#define g_spawn_sync \ + g_spawn_sync_stub + +#define sd_notify \ + sd_notify_stub + +#define pclKeyWriteData \ + pclKeyWriteData_stub + +#define pclKeyReadData \ + pclKeyReadData_stub + +#define pclInitLibrary \ + pclInitLibrary_stub + +#define pclDeinitLibrary \ + pclDeinitLibrary_stub + +/* Redefine main() to use test frames main() */ +#define main \ + nhm_main + +/* Include the main file. */ +#include <src/nhm-main.c> + +/* Undefine main to be able to have a main in the test frame */ +#undef main + +/* Undefine previous redefinitions */ +#undef nhm_systemd_connect +#undef nhm_systemd_disconnect +#undef dlt_check_library_version +#undef dlt_register_context +#undef dlt_unregister_context +#undef dlt_unregister_app +#undef dlt_user_log_write_start +#undef dlt_user_log_write_finish +#undef dlt_user_log_write_string +#undef dlt_user_log_write_int +#undef dlt_user_log_write_uint +#undef nhm_dbus_info_emit_app_health_status +#undef nhm_dbus_info_complete_register_app_status +#undef nhm_dbus_info_complete_read_statistics +#undef nhm_dbus_info_complete_request_node_restart +#undef nsm_dbus_consumer_proxy_new_sync +#undef nsm_dbus_consumer_call_register_shutdown_client_sync +#undef nsm_dbus_lc_consumer_proxy_new_sync +#undef nsm_dbus_lc_consumer_complete_lifecycle_request +#undef nsm_dbus_lc_control_proxy_new_sync +#undef nsm_dbus_lc_control_call_set_app_health_status_sync +#undef nsm_dbus_lc_control_call_request_node_restart_sync +#undef g_file_test +#undef g_file_read_link +#undef g_dir_open +#undef g_dir_read_name +#undef g_dir_close +#undef g_main_loop_run +#undef g_main_loop_quit +#undef g_bus_get_sync +#undef g_dbus_connection_get_unique_name +#undef g_bus_own_name +#undef g_dbus_interface_skeleton_export +#undef g_dbus_connection_new_for_address_sync +#undef g_dbus_connection_call_sync +#undef g_dbus_connection_signal_subscribe +#undef g_dbus_connection_signal_unsubscribe +#undef g_dbus_connection_call_sync +#undef g_timeout_add_seconds +#undef g_signal_connect_data +#undef g_spawn_sync +#undef sd_notify +#undef pclKeyWriteData +#undef pclKeyReadData +#undef pclInitLibrary +#undef pclDeinitLibrary + + +#endif /* NHM_MAIN_TEST_H */ diff --git a/tst/nhm-systemd-test.c b/tst/nhm-systemd-test.c new file mode 100644 index 0000000..1486eb3 --- /dev/null +++ b/tst/nhm-systemd-test.c @@ -0,0 +1,882 @@ +/* NHM - NodeHealthMonitor + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + */ + +/** + * SECTION:nhm-unit-test + * @title: NodeHealthMonitor (NHM) unit test + * @short_description: Unit test for an automatic check of the NHM systemd + * observation. + * + * The unit test will stimulate the NHM systemd observation and check for the + * expected reactions. + */ + + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +/* System header files */ +#include <stdio.h> /* NULL */ +#include <glib-2.0/glib.h> /* use gtypes */ + +/* Include the stubbed main file of the NHM. Its functions will be tested! */ +#include "nhm-systemd-test.h" + + +/******************************************************************************* +* +* Local variables and constants +* +*******************************************************************************/ + +/* Variables to check callback on unit state change */ +static gboolean nhm_systemd_test_app_state_changed_cb_called = FALSE; +static gchar *nhm_systemd_test_app_state_changed_cb_name = NULL; +static NhmAppStatus_e nhm_systemd_test_app_state_changed_cb_status = NhmAppStatus_Ok; + + +/******************************************************************************* +* +* Prototypes for file local functions (see implementation for description) +* +*******************************************************************************/ + + +/******************************************************************************* +* +* Local (static) functions +* +*******************************************************************************/ + +/** + * nhm_systemd_test_app_state_changed_cb: + * @name: Name of the application, whose state changed + * @status: New status of the application. + * + * The function is not a test case, but a callback that will be used during + * the tests. + */ +static void +nhm_systemd_test_app_state_changed_cb(const gchar *name, + NhmAppStatus_e status) +{ + /* Remember that callback was called and store passed parameters */ + nhm_systemd_test_app_state_changed_cb_called = TRUE; + nhm_systemd_test_app_state_changed_cb_name = (gchar*) name; + nhm_systemd_test_app_state_changed_cb_status = status; +} + + +/** + * nhm_test_systemd_connect: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_connect() function. + */ +static gint +nhm_test_systemd_connect(void) +{ + gint retval = 0; + NhmSystemdAppStatusCb callback = NULL; + GdbusConnectionCallSyncStubCalls g_dbus_connection_call_sync_stub_calls[3]; + GVariantBuilder *builder; + + /* Check 1: Callback nok. */ + callback = NULL; + retval = (nhm_systemd_connect(callback) == FALSE) ? 0 : -1; + + /* Check 2: Callback ok. Bus conn. nok. */ + if(retval == 0) + { + callback = &nhm_systemd_test_app_state_changed_cb; + g_bus_get_sync_set_error = TRUE; + + retval = (nhm_systemd_connect(callback) == FALSE) ? 0 : -1; + } + + /* Check 3: Callback ok. Bus conn. ok. Subscribe nok. */ + if(retval == 0) + { + callback = &nhm_systemd_test_app_state_changed_cb; + g_bus_get_sync_set_error = FALSE; + + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Subscribe"; + g_dbus_connection_call_sync_stub_calls[0].rval = NULL; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + retval = (nhm_systemd_connect(callback) == FALSE) ? 0 : -1; + } + + /* Check 4: Callback ok. Bus conn. ok. Subscribe ok. ListUnits nok */ + if(retval == 0) + { + callback = &nhm_systemd_test_app_state_changed_cb; + + g_bus_get_sync_set_error = FALSE; + + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Subscribe"; + g_dbus_connection_call_sync_stub_calls[0].rval = g_variant_new("()"); + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + g_dbus_connection_call_sync_stub_control.count = 2; + g_dbus_connection_call_sync_stub_calls[1].method = "ListUnits"; + g_dbus_connection_call_sync_stub_calls[1].rval = NULL; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + g_dbus_connection_call_sync_stub_control.count = 3; + g_dbus_connection_call_sync_stub_calls[2].method = "Unsubscribe"; + g_dbus_connection_call_sync_stub_calls[2].rval = NULL; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + retval = (nhm_systemd_connect(callback) == FALSE) ? 0 : -1; + } + + /* Check 5: Callback ok. Bus conn. ok. Subscribe ok. ListUnits ok */ + if(retval == 0) + { + /* Callback ok */ + callback = &nhm_systemd_test_app_state_changed_cb; + + /* Bus conn. ok */ + g_bus_get_sync_set_error = FALSE; + + /* Subscribe ok */ + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Subscribe"; + g_dbus_connection_call_sync_stub_calls[0].rval = g_variant_new("()"); + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + /* ListUnits ok */ + g_dbus_connection_call_sync_stub_control.count = 2; + g_dbus_connection_call_sync_stub_calls[1].method = "ListUnits"; + + builder = g_variant_builder_new (G_VARIANT_TYPE("a(ssssssouso)")); + g_variant_builder_add (builder, "(ssssssouso)", "1", "2", "3", "4", "5", "6", "/a/b/c", 100, "7", "/a/b/c"); + g_variant_builder_add (builder, "(ssssssouso)", "1.service", "2", "3", "4", "5", "6", "/a/b/c", 100, "7", "/a/b/c"); + g_dbus_connection_call_sync_stub_calls[1].rval = g_variant_new("(a(ssssssouso))", builder); + g_variant_builder_unref (builder); + + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + /* Call */ + retval = (nhm_systemd_connect(callback) == TRUE) ? 0 : -1; + + /* Free created unit object. Destroy bus conn. */ + g_slist_free_full(nhm_systemd_observed_units, &nhm_systemd_free_unit); + g_object_unref(nhm_systemd_conn); + } + + return retval; +} + + +/** + * nhm_test_systemd_disconnect: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_disconnect() function. + */ +static gint +nhm_test_systemd_disconnect(void) +{ + NhmSystemdUnit *unit = NULL; + GdbusConnectionCallSyncStubCalls g_dbus_connection_call_sync_stub_calls[1]; + + /* Check 1: Sub nok. No UnitAdd sig. No UnitRem sig. No obs. units. No systemd conn. */ + nhm_systemd_events_subscribed = FALSE; + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Unsubscribe"; + g_dbus_connection_call_sync_stub_calls[0].rval = NULL; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + nhm_systemd_unit_add_sig_id = 0; + nhm_systemd_unit_rem_sig_id = 0; + nhm_systemd_observed_units = NULL; + nhm_systemd_conn = NULL; + + nhm_systemd_disconnect(); + + /* Check 2: Sub ok. Unsub. nok. No UnitAdd sig. No UnitRem sig. No obs. units. No systemd conn. */ + nhm_systemd_events_subscribed = TRUE; + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Unsubscribe"; + g_dbus_connection_call_sync_stub_calls[0].rval = NULL; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + nhm_systemd_unit_add_sig_id = 0; + nhm_systemd_unit_rem_sig_id = 0; + nhm_systemd_observed_units = NULL; + nhm_systemd_conn = NULL; + + nhm_systemd_disconnect(); + + /* Check 3: Unsub. ok. UnitAdd sig. UnitRem sig. Obs. units. Systemd conn. */ + nhm_systemd_events_subscribed = TRUE; + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Unsubscribe"; + g_dbus_connection_call_sync_stub_calls[0].rval = g_variant_new("()"); + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + nhm_systemd_unit_add_sig_id = 1; + nhm_systemd_unit_rem_sig_id = 1; + + unit = g_new(NhmSystemdUnit, 1); + unit->active_state = NHM_ACTIVE_STATE_UNKNOWN; + unit->name = g_strdup("Unit"); + unit->path = g_strdup("/a/unit/to/destroy"); + unit->sig_sub_id = 0; + nhm_systemd_observed_units = g_slist_append(nhm_systemd_observed_units, unit); + + nhm_systemd_conn = g_object_new(G_TYPE_DBUS_CONNECTION, NULL); + + nhm_systemd_disconnect(); + + return 0; +} + + +/** + * nhm_systemd_test_active_state_string_to_enum: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_active_state_string_to_enum() function. + */ +static gint +nhm_systemd_test_active_state_string_to_enum(void) +{ + gint retval = 0; + + /* Check 1: active -> NHM_ACTIVE_STATE_ACTIVE */ + retval = ( nhm_systemd_active_state_string_to_enum("active") + == NHM_ACTIVE_STATE_ACTIVE) ? 0 : -1; + + /* Check 2: inactive -> NHM_ACTIVE_STATE_INACTIVE */ + if(retval == 0) + { + retval = (nhm_systemd_active_state_string_to_enum("inactive") + == NHM_ACTIVE_STATE_INACTIVE) ? 0 : -1; + } + + /* Check 3: activating -> NHM_ACTIVE_STATE_ACTIVATING */ + if(retval == 0) + { + retval = (nhm_systemd_active_state_string_to_enum("activating") + == NHM_ACTIVE_STATE_ACTIVATING) ? 0 : -1; + } + + /* Check 4: deactivating -> NHM_ACTIVE_STATE_DEACTIVATING */ + if(retval == 0) + { + retval = (nhm_systemd_active_state_string_to_enum("deactivating") + == NHM_ACTIVE_STATE_DEACTIVATING) ? 0 : -1; + } + + /* Check 5: failed -> NHM_ACTIVE_STATE_FAILED */ + if(retval == 0) + { + retval = (nhm_systemd_active_state_string_to_enum("failed") + == NHM_ACTIVE_STATE_FAILED) ? 0 : -1; + } + + /* Check 6: reloading -> NHM_ACTIVE_STATE_RELOADING */ + if(retval == 0) + { + retval = (nhm_systemd_active_state_string_to_enum("reloading") + == NHM_ACTIVE_STATE_RELOADING) ? 0 : -1; + } + + /* Check 6: ? -> NHM_ACTIVE_STATE_UNKNOWN */ + if(retval == 0) + { + retval = (nhm_systemd_active_state_string_to_enum("") + == NHM_ACTIVE_STATE_UNKNOWN) ? 0 : -1; + } + + return retval; +} + + +/** + * nhm_systemd_test_subscribe_properties_changed: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_subscribe_properties_changed() function. + */ +static gint +nhm_systemd_test_subscribe_properties_changed(void) +{ + NhmSystemdUnit unit; + + /* Check 1: Do a subscription */ + return (nhm_systemd_subscribe_properties_changed(&unit) == 0) ? 0 : -1; +} + + +/** + * nhm_systemd_test_find_unit_by_name: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_find_unit_by_name() function. + */ +static gint +nhm_systemd_test_find_unit_by_name(void) +{ + gint retval = 0; + NhmSystemdUnit u1; + NhmSystemdUnit u2; + + /* Check 1: Valid compare */ + u1.name = "Unit1"; + u2.name = "Unit1"; + retval = (nhm_systemd_find_unit_by_name(&u1, &u2) == 0) ? 0 : -1; + + /* Check 2: Invalid compare I */ + if(retval == 0) + { + u1.name = "Unit1"; + u2.name = "Unit2"; + retval = (nhm_systemd_find_unit_by_name(&u1, &u2) == -1) ? 0 : -1; + } + + /* Check 3: Invalid compare II */ + if(retval == 0) + { + u1.name = "Unit2"; + u2.name = "Unit1"; + retval = (nhm_systemd_find_unit_by_name(&u1, &u2) == 1) ? 0 : -1; + } + + return retval; +} + + +/** + * nhm_systemd_test_free_unit: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_free_unit() function. + */ +static gint +nhm_systemd_test_free_unit(void) +{ + NhmSystemdUnit *unit = g_new(NhmSystemdUnit, 1); + + /* Check 1: Free normal unit object */ + unit->active_state = NHM_ACTIVE_STATE_UNKNOWN; + unit->name = g_strdup("Unit"); + unit->path = g_strdup("/path/to/unit"); + unit->sig_sub_id = 0; + + nhm_systemd_free_unit(unit); + + return 0; +} + + +/** + * nhm_systemd_test_unit_active_state_changed: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_unit_active_state_changed() function. + */ +static gint +nhm_systemd_test_unit_active_state_changed(void) +{ + gint retval = 0; + NhmSystemdUnit unit = {"Unit", "Path", NHM_ACTIVE_STATE_UNKNOWN, 0}; + + /* Check 1: Change NHM_ACTIVE_STATE_UNKNOWN -> NHM_ACTIVE_STATE_UNKNOWN */ + nhm_systemd_app_status_cb = &nhm_systemd_test_app_state_changed_cb; + nhm_systemd_test_app_state_changed_cb_called = FALSE; + nhm_systemd_test_app_state_changed_cb_name = NULL; + nhm_systemd_test_app_state_changed_cb_status = NhmAppStatus_Ok; + + nhm_systemd_unit_active_state_changed(&unit, NHM_ACTIVE_STATE_UNKNOWN); + + /* Check that no callback occured */ + retval = (nhm_systemd_test_app_state_changed_cb_called == FALSE) ? 0 : -1; + + /* Check 2: Change NHM_ACTIVE_STATE_UNKNOWN -> NHM_ACTIVE_STATE_ACTIVE */ + if(retval == 0) + { + nhm_systemd_app_status_cb = &nhm_systemd_test_app_state_changed_cb; + nhm_systemd_test_app_state_changed_cb_called = FALSE; + nhm_systemd_test_app_state_changed_cb_name = NULL; + nhm_systemd_test_app_state_changed_cb_status = NhmAppStatus_Failed; + + nhm_systemd_unit_active_state_changed(&unit, NHM_ACTIVE_STATE_ACTIVE); + + /* Assert that callback occurred */ + retval = ( (nhm_systemd_test_app_state_changed_cb_called == TRUE) + && (g_strcmp0(nhm_systemd_test_app_state_changed_cb_name, unit.name) == 0) + && (nhm_systemd_test_app_state_changed_cb_status == NhmAppStatus_Ok)) + ? 0 : -1; + } + + /* Check 2: Change NHM_ACTIVE_STATE_UNKNOWN -> NHM_ACTIVE_STATE_ACTIVE */ + if(retval == 0) + { + nhm_systemd_app_status_cb = &nhm_systemd_test_app_state_changed_cb; + nhm_systemd_test_app_state_changed_cb_called = FALSE; + nhm_systemd_test_app_state_changed_cb_name = NULL; + nhm_systemd_test_app_state_changed_cb_status = NhmAppStatus_Ok; + + nhm_systemd_unit_active_state_changed(&unit, NHM_ACTIVE_STATE_FAILED); + + /* Assert that callback occurred */ + retval = ( (nhm_systemd_test_app_state_changed_cb_called == TRUE) + && (g_strcmp0(nhm_systemd_test_app_state_changed_cb_name, unit.name) == 0) + && (nhm_systemd_test_app_state_changed_cb_status == NhmAppStatus_Failed)) + ? 0 : -1; + } + + return retval; +} + + +/** + * nhm_systemd_test_unit_get_active_state: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_unit_get_active_state() function. + */ +static gint +nhm_systemd_test_unit_get_active_state(void) +{ + gint retval = 0; + GVariant *unit_state_variant = NULL; + NhmSystemdUnit unit = {"Name", "Path", NHM_ACTIVE_STATE_ACTIVE, 0}; + GdbusConnectionCallSyncStubCalls g_dbus_connection_call_sync_stub_calls[1]; + + /* Check 1: D-Bus error getting ActiveState property */ + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Get"; + g_dbus_connection_call_sync_stub_calls[0].rval = NULL; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + retval = (nhm_systemd_unit_get_active_state(&unit) == NHM_ACTIVE_STATE_UNKNOWN) + ? 0 : -1; + + /* Check 2: Retrieve D-Bus property value successful */ + if(retval == 0) + { + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Get"; + + unit_state_variant = g_variant_new_string("active"); + unit_state_variant = g_variant_new_variant(unit_state_variant); + unit_state_variant = g_variant_new_tuple(&unit_state_variant, 1); + g_dbus_connection_call_sync_stub_calls[0].rval = unit_state_variant; + + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + retval = (nhm_systemd_unit_get_active_state(&unit) == NHM_ACTIVE_STATE_ACTIVE) + ? 0 : -1; + } + + return retval; +} + + +/** + * nhm_systemd_test_unit_added: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_unit_added() function. + */ +static gint +nhm_systemd_test_unit_added(void) +{ + gint retval = 0; + GVariant *param = NULL; + GVariant *unit_state_variant = NULL; + NhmSystemdUnit *unit = NULL; + GdbusConnectionCallSyncStubCalls g_dbus_connection_call_sync_stub_calls[1]; + + /* Check 1: Wrong parameter format */ + nhm_systemd_observed_units = NULL; + param = g_variant_new("(uss)", 10, "Wrong", "Unit"); + + nhm_systemd_unit_added(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + + retval = (nhm_systemd_observed_units == NULL) ? 0 : -1; + + /* Check 2: New unit added, but no service */ + if(retval == 0) + { + nhm_systemd_observed_units = NULL; + param = g_variant_new("(so)", "Unit", "/Path/to/Unit"); + + /* Function will retrieve unit's active state */ + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Get"; + + unit_state_variant = g_variant_new_string("active"); + unit_state_variant = g_variant_new_variant(unit_state_variant); + unit_state_variant = g_variant_new_tuple(&unit_state_variant, 1); + g_dbus_connection_call_sync_stub_calls[0].rval = unit_state_variant; + + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + nhm_systemd_unit_added(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + g_variant_unref(param); + /* Check that unit was not added */ + retval = (nhm_systemd_observed_units == NULL) ? 0 : -1; + } + + /* Check 3: Add new service */ + if(retval == 0) + { + nhm_systemd_observed_units = NULL; + param = g_variant_new("(so)", "Unit.service", "/Path/to/Unit"); + + /* Function will retrieve unit's active state */ + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Get"; + + unit_state_variant = g_variant_new_string("active"); + unit_state_variant = g_variant_new_variant(unit_state_variant); + unit_state_variant = g_variant_new_tuple(&unit_state_variant, 1); + g_dbus_connection_call_sync_stub_calls[0].rval = unit_state_variant; + + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + nhm_systemd_unit_added(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + + g_variant_unref(param); + /* Check that unit was not added */ + unit = (NhmSystemdUnit*) nhm_systemd_observed_units->data; + retval = ( (g_strcmp0(unit->name, "Unit.service") == 0) + && (g_strcmp0(unit->path, "/Path/to/Unit") == 0) + && (unit->active_state == NHM_ACTIVE_STATE_ACTIVE) + && (unit->sig_sub_id == 0)) ? 0 : -1; + + g_slist_free_full(nhm_systemd_observed_units, &nhm_systemd_free_unit); + } + + /* Check 4: Add same service */ + if(retval == 0) + { + param = g_variant_new("(so)", "Unit.service", "/Path/to/Unit"); + + /* Add unit to the list */ + nhm_systemd_observed_units = NULL; + unit = g_new(NhmSystemdUnit, 1); + unit->name = g_strdup("Unit.service"); + unit->path = g_strdup("/Path/to/Unit"); + unit->active_state = NHM_ACTIVE_STATE_UNKNOWN; + unit->sig_sub_id = 0; + nhm_systemd_observed_units = g_slist_append(nhm_systemd_observed_units, unit); + + nhm_systemd_unit_added(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + + g_variant_unref(param); + retval = (g_slist_length(nhm_systemd_observed_units) == 1) ? 0 : -1; + + g_slist_free_full(nhm_systemd_observed_units, &nhm_systemd_free_unit); + } + + return retval; +} + + +/** + * nhm_systemd_test_unit_removed: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_unit_removed() function. + */ +static gint +nhm_systemd_test_unit_removed(void) +{ + gint retval = 0; + GVariant *param = NULL; + NhmSystemdUnit *unit; + + /* Preparation: Build up a list with an observed unit */ + nhm_systemd_observed_units = NULL; + unit = g_new(NhmSystemdUnit, 1); + unit->name = g_strdup("Unit.service"); + unit->path = g_strdup("/Path/to/Unit"); + unit->active_state = NHM_ACTIVE_STATE_UNKNOWN; + unit->sig_sub_id = 0; + nhm_systemd_observed_units = g_slist_append(nhm_systemd_observed_units, unit); + + /* Reuse unit variable to point on first list element */ + unit = (NhmSystemdUnit*) (nhm_systemd_observed_units->data); + + + /* Check 1: Invalid parameter format */ + param = g_variant_new("(uss)", 10, "Unit", "/Path/to/Unit"); + + nhm_systemd_unit_removed(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + g_variant_unref(param); + /* Assert unit still on the list */ + retval = ( (g_strcmp0(unit->name, "Unit.service") == 0) + && (g_strcmp0(unit->path, "/Path/to/Unit") == 0) + && (unit->active_state == NHM_ACTIVE_STATE_UNKNOWN) + && (unit->sig_sub_id == 0)) ? 0 : -1; + + /* Check 2: No service removed */ + if(retval == 0) + { + param = g_variant_new("(so)", "Unit1", "/Path/to/Unit"); + + nhm_systemd_unit_removed(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + g_variant_unref(param); + /* Assert unit still on the list */ + retval = ( (g_strcmp0(unit->name, "Unit.service") == 0) + && (g_strcmp0(unit->path, "/Path/to/Unit") == 0) + && (unit->active_state == NHM_ACTIVE_STATE_UNKNOWN) + && (unit->sig_sub_id == 0)) ? 0 : -1; + } + + /* Check 3: Unknown unit removed */ + if(retval == 0) + { + param = g_variant_new("(so)", "Unit1.service", "/Path/to/Unit"); + + nhm_systemd_unit_removed(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + g_variant_unref(param); + /* Assert unit still on the list */ + retval = ( (g_strcmp0(unit->name, "Unit.service") == 0) + && (g_strcmp0(unit->path, "/Path/to/Unit") == 0) + && (unit->active_state == NHM_ACTIVE_STATE_UNKNOWN) + && (unit->sig_sub_id == 0)) ? 0 : -1; + } + + /* Check 4: Unit removed */ + if(retval == 0) + { + param = g_variant_new("(so)", "Unit.service", "/Path/to/Unit"); + + nhm_systemd_unit_removed(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + g_variant_unref(param); + retval = (nhm_systemd_observed_units == NULL) ? 0 : -1; + } + + return retval; +} + + +/** + * nhm_systemd_test_unit_properties_changed: + * @Return: 0, if test succeeded. Otherwise -1. + * + * Test nhm_systemd_unit_properties_changed() function. + */ +static gint +nhm_systemd_test_unit_properties_changed(void) +{ + gint retval = 0; + GVariant *param = NULL; + GVariant *unit_state_variant = NULL; + gchar *inv_prop[2] = {"state", NULL}; + NhmSystemdUnit unit; + GdbusConnectionCallSyncStubCalls g_dbus_connection_call_sync_stub_calls[1]; + + /* Check 1: Parameter format nok. */ + param = g_variant_new("(s)", "Test"); + nhm_systemd_app_status_cb = &nhm_systemd_test_app_state_changed_cb; + nhm_systemd_test_app_state_changed_cb_called = FALSE; + + nhm_systemd_unit_properties_changed(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + g_variant_unref(param); + retval = (nhm_systemd_test_app_state_changed_cb_called == FALSE) ? 0 : -1; + + /* Check 2: Parameter format ok. ActiveState unchanged. */ + if(retval == 0) + { + inv_prop[0] = "Invalid"; + param = g_variant_new("(sa{sv}^as)", "Test", NULL, inv_prop); + + nhm_systemd_app_status_cb = &nhm_systemd_test_app_state_changed_cb; + nhm_systemd_test_app_state_changed_cb_called = FALSE; + + nhm_systemd_unit_properties_changed(NULL, + NULL, + NULL, + NULL, + NULL, + param, + NULL); + g_variant_unref(param); + retval = (nhm_systemd_test_app_state_changed_cb_called == FALSE) ? 0 : -1; + } + + /* Check 3: Parameter format ok. Same ActiveState. */ + if(retval == 0) + { + inv_prop[0] = "ActiveState"; + param = g_variant_new("(sa{sv}^as)", "Test", NULL, inv_prop); + + unit.name = "Unit"; + unit.path = "Path"; + unit.active_state = NHM_ACTIVE_STATE_ACTIVE; + unit.sig_sub_id = 0; + + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Get"; + unit_state_variant = g_variant_new_string("active"); + unit_state_variant = g_variant_new_variant(unit_state_variant); + unit_state_variant = g_variant_new_tuple(&unit_state_variant, 1); + g_dbus_connection_call_sync_stub_calls[0].rval = unit_state_variant; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + nhm_systemd_app_status_cb = &nhm_systemd_test_app_state_changed_cb; + nhm_systemd_test_app_state_changed_cb_called = FALSE; + + nhm_systemd_unit_properties_changed(NULL, + NULL, + NULL, + NULL, + NULL, + param, + &unit); + g_variant_unref(param); + retval = (nhm_systemd_test_app_state_changed_cb_called == FALSE) ? 0 : -1; + } + + /* Check 4: Parameter format ok. ActiveState changed. */ + if(retval == 0) + { + inv_prop[0] = "ActiveState"; + param = g_variant_new("(sa{sv}^as)", "Test", NULL, inv_prop); + + unit.name = "Unit"; + unit.path = "Path"; + unit.active_state = NHM_ACTIVE_STATE_FAILED; + unit.sig_sub_id = 0; + g_dbus_connection_call_sync_stub_control.count = 1; + g_dbus_connection_call_sync_stub_calls[0].method = "Get"; + unit_state_variant = g_variant_new_string("active"); + unit_state_variant = g_variant_new_variant(unit_state_variant); + unit_state_variant = g_variant_new_tuple(&unit_state_variant, 1); + g_dbus_connection_call_sync_stub_calls[0].rval = unit_state_variant; + g_dbus_connection_call_sync_stub_control.calls = g_dbus_connection_call_sync_stub_calls; + + nhm_systemd_test_app_state_changed_cb_called = FALSE; + nhm_systemd_app_status_cb = &nhm_systemd_test_app_state_changed_cb; + nhm_systemd_unit_properties_changed(NULL, + NULL, + NULL, + NULL, + NULL, + param, + &unit); + g_variant_unref(param); + retval = (nhm_systemd_test_app_state_changed_cb_called == TRUE) ? 0 : -1; + } + + return retval; +} + + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + +/** + * main: + * + * Main function of the unit test. + * + * Return value: 0 if all tests succeeded. Otherwise -1. + */ +int +main(void) +{ + int retval = 0; + + g_type_init(); + + /* Test interfaces */ + retval = nhm_test_systemd_connect(); + retval = (retval == 0) ? nhm_test_systemd_disconnect() : -1; + + /* Test static functions */ + retval = (retval == 0) ? nhm_systemd_test_active_state_string_to_enum() : -1; + + /* Test helper functions */ + retval = (retval == 0) ? nhm_systemd_test_subscribe_properties_changed() : -1; + retval = (retval == 0) ? nhm_systemd_test_find_unit_by_name() : -1; + retval = (retval == 0) ? nhm_systemd_test_free_unit() : -1; + + /* Test unit state change chain */ + retval = (retval == 0) ? nhm_systemd_test_unit_active_state_changed() : -1; + retval = (retval == 0) ? nhm_systemd_test_unit_get_active_state() : -1; + retval = (retval == 0) ? nhm_systemd_test_unit_added() : -1; + retval = (retval == 0) ? nhm_systemd_test_unit_removed() : -1; + retval = (retval == 0) ? nhm_systemd_test_unit_properties_changed() : -1; + + return retval; +} diff --git a/tst/nhm-systemd-test.h b/tst/nhm-systemd-test.h new file mode 100644 index 0000000..299b59c --- /dev/null +++ b/tst/nhm-systemd-test.h @@ -0,0 +1,90 @@ +/* NHM - NodeHealthMonitor + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + */ + +/* + * This header file is used for the NHM systemd unit test. It: + * - Includes headers with stubbed function definitions + * - Redefines the name of real functions to the stub names + * - Includes the test file, which will be patched to use the stubs + * - Undefine stubs, to allow usage of the real functions for the tests + */ + +#ifndef NHM_TEST_SYSTEMD_H +#define NHM_TEST_SYSTEMD_H + +/* Include stub header files */ +#include <tst/stubs/gio/gio-stub.h> +#include <tst/stubs/dlt/dlt-stub.h> + + +/* Redefine some functions to stubs */ +#define dlt_register_app \ + dlt_register_app_stub + +#define dlt_check_library_version \ + dlt_check_library_version_stub + +#define dlt_register_context \ + dlt_register_context_stub + +#define dlt_unregister_context \ + dlt_unregister_context_stub + +#define dlt_unregister_app \ + dlt_unregister_app_stub + +#define dlt_user_log_write_start \ + dlt_user_log_write_start_stub + +#define dlt_user_log_write_finish \ + dlt_user_log_write_finish_stub + +#define dlt_user_log_write_string \ + dlt_user_log_write_string_stub + +#define dlt_user_log_write_int \ + dlt_user_log_write_int_stub + +#define dlt_user_log_write_uint \ + dlt_user_log_write_uint_stub + +#define g_bus_get_sync \ + g_bus_get_sync_stub + +#define g_dbus_connection_call_sync \ + g_dbus_connection_call_sync_stub + +#define g_dbus_connection_signal_subscribe \ + g_dbus_connection_signal_subscribe_stub + +#define g_dbus_connection_signal_unsubscribe \ + g_dbus_connection_signal_unsubscribe_stub + +/* Include the main file. */ +#include <src/nhm-systemd.c> + +/* Undefine previous redefinitions */ +#undef dlt_check_library_version +#undef dlt_register_context +#undef dlt_unregister_context +#undef dlt_unregister_app +#undef dlt_user_log_write_start +#undef dlt_user_log_write_finish +#undef dlt_user_log_write_string +#undef dlt_user_log_write_int +#undef dlt_user_log_write_uint + +#undef g_bus_get_sync +#undef g_dbus_connection_call_sync +#undef g_dbus_connection_signal_subscribe +#undef g_dbus_connection_signal_unsubscribe + +#endif /* NHM_TEST_SYSTEMD_H */ diff --git a/tst/stubs/dlt/dlt-stub.c b/tst/stubs/dlt/dlt-stub.c new file mode 100644 index 0000000..6a1d091 --- /dev/null +++ b/tst/stubs/dlt/dlt-stub.c @@ -0,0 +1,141 @@ +/* NHM - NodeHealthMonitor + * + * Implementation of stubs for dlt + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <dlt/dlt.h> /* Header of real sd daemon */ +#include <tst/stubs/dlt/dlt-stub.h> /* Header of stub sd daemon */ + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + +int +dlt_register_app_stub(const char *appid, + const char *description) +{ + return 0; +} + +/** + * dlt_check_library_version_stub: + * + * Stub for dlt_check_library_version() + */ +int +dlt_check_library_version_stub(const char *user_major_version, + const char *user_minor_version) +{ + return 0; +} + +/** + * dlt_register_context_stub: + * + * Stub for dlt_register_context() + */ +int +dlt_register_context_stub(DltContext *handle, + const char *contextid, + const char * description) +{ + return 0; +} + +/** + * dlt_unregister_context_stub: + * + * Stub for dlt_unregister_context() + */ +int +dlt_unregister_context_stub(DltContext *handle) +{ + return 0; +} + +/** + * dlt_unregister_app_stub: + * + * Stub for dlt_unregister_app() + */ +int +dlt_unregister_app_stub(void) +{ + return 0; +} + +/** + * dlt_user_log_write_start_stub: + * + * Stub for dlt_user_log_write_start() + */ +int +dlt_user_log_write_start_stub(DltContext *handle, + DltContextData *log, + DltLogLevelType loglevel) +{ + return 0; +} + +/** + * dlt_user_log_write_finish_stub: + * + * Stub for dlt_user_log_write_finish() + */ +int +dlt_user_log_write_finish_stub(DltContextData *log) +{ + return 0; +} + +/** + * dlt_user_log_write_string_stub: + * + * Stub for dlt_user_log_write_string() + */ +int +dlt_user_log_write_string_stub(DltContextData *log, + const char *text) +{ + return 0; +} + +/** + * dlt_user_log_write_int_stub: + * + * Stub for dlt_user_log_write_int() + */ +int +dlt_user_log_write_int_stub(DltContextData *log, + int data) +{ + return 0; +} + +/** + * dlt_user_log_write_uint_stub: + * + * Stub for dlt_user_log_write_uint() + */ +int +dlt_user_log_write_uint_stub(DltContextData *log, + unsigned int data) +{ + return 0; +} diff --git a/tst/stubs/dlt/dlt-stub.h b/tst/stubs/dlt/dlt-stub.h new file mode 100644 index 0000000..ff1d2cd --- /dev/null +++ b/tst/stubs/dlt/dlt-stub.h @@ -0,0 +1,51 @@ +/* NHM - NodeHealthMonitor + * + * Definition of stubs for dlt + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef DLT_STUB_H +#define DLT_STUB_H + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <dlt/dlt.h> /* Include header of real dlt */ + +/******************************************************************************* +* +* Exported variables, constants and defines +* +*******************************************************************************/ + +int dlt_register_app_stub (const char *appid, + const char *description); +int dlt_check_library_version_stub(const char *user_major_version, + const char *user_minor_version); +int dlt_register_context_stub (DltContext *handle, + const char *contextid, + const char *description); +int dlt_unregister_context_stub (DltContext *handle); +int dlt_unregister_app_stub (void); +int dlt_user_log_write_start_stub (DltContext *handle, + DltContextData *log, + DltLogLevelType loglevel); +int dlt_user_log_write_finish_stub(DltContextData *log); +int dlt_user_log_write_string_stub(DltContextData *log, + const char *text); +int dlt_user_log_write_int_stub (DltContextData *log, + int data); +int dlt_user_log_write_uint_stub (DltContextData *log, + unsigned int data); + +#endif /* DLT_STUB_H */ diff --git a/tst/stubs/gen/nhm-dbus-info-stub.c b/tst/stubs/gen/nhm-dbus-info-stub.c new file mode 100644 index 0000000..bca004f --- /dev/null +++ b/tst/stubs/gen/nhm-dbus-info-stub.c @@ -0,0 +1,97 @@ +/* NHM - NodeHealthMonitor + * + * Implementation of stubs for the nsm-dbus-consumer + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <gen/nhm-dbus-info.h> +#include <tst/stubs/gen/nhm-dbus-info-stub.h> + +/******************************************************************************* +* +* Exported variables and constants +* +*******************************************************************************/ + +gint nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount = 0; +gint nhm_dbus_info_complete_read_statistics_stub_TotalFailures = 0; +gint nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles = 0; +gint nhm_dbus_info_complete_request_node_restart_stub_ErrorStatus = 0; + + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + +/** + * nhm_dbus_info_emit_app_health_status_stub: + * + * Stub for nhm_dbus_info_emit_app_health_status() + */ +void +nhm_dbus_info_emit_app_health_status_stub(NhmDbusInfo *object, + const gchar *arg_AppName, + gint arg_AppStatus) +{ + +} + +/** + * nhm_dbus_info_complete_register_app_status_stub: + * + * Stub for nhm_dbus_info_complete_register_app_status() + */ +void +nhm_dbus_info_complete_register_app_status_stub(NhmDbusInfo *object, + GDBusMethodInvocation *invocation) +{ + +} + +/** + * nhm_dbus_info_complete_read_statistics_stub: + * + * Stub for nhm_dbus_info_complete_read_statistics() + */ +void +nhm_dbus_info_complete_read_statistics_stub(NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + guint CurrentFailCount, + guint TotalFailures, + guint TotalLifecycles, + gint ErrorStatus) +{ + nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount = CurrentFailCount; + nhm_dbus_info_complete_read_statistics_stub_TotalFailures = TotalFailures; + nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles = TotalLifecycles; +} + +/** + * nhm_dbus_info_complete_request_node_restart_stub: + * + * Stub for nhm_dbus_info_complete_request_node_restart() + */ +void +nhm_dbus_info_complete_request_node_restart_stub(NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + gint ErrorStatus) +{ + nhm_dbus_info_complete_request_node_restart_stub_ErrorStatus = ErrorStatus; +} + diff --git a/tst/stubs/gen/nhm-dbus-info-stub.h b/tst/stubs/gen/nhm-dbus-info-stub.h new file mode 100644 index 0000000..368593e --- /dev/null +++ b/tst/stubs/gen/nhm-dbus-info-stub.h @@ -0,0 +1,62 @@ +/* NHM - NodeHealthMonitor + * + * Definition of stubs for nhm-dbus-info + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef NHM_DBUS_INFO_STUB_H +#define NHM_DBUS_INFO_STUB_H + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <gen/nhm-dbus-info.h> /* Header of real nsm-dbus-info */ + +/******************************************************************************* +* +* Exported variables, constants and defines +* +*******************************************************************************/ + +extern gint nhm_dbus_info_complete_read_statistics_stub_CurrentFailCount; +extern gint nhm_dbus_info_complete_read_statistics_stub_TotalFailures; +extern gint nhm_dbus_info_complete_read_statistics_stub_TotalLifecycles; +extern gint nhm_dbus_info_complete_request_node_restart_stub_ErrorStatus; + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +void nhm_dbus_info_emit_app_health_status_stub (NhmDbusInfo *object, + const gchar *arg_AppName, + gint arg_AppStatus); + +void nhm_dbus_info_complete_register_app_status_stub (NhmDbusInfo *object, + GDBusMethodInvocation *invocation); + +void nhm_dbus_info_complete_read_statistics_stub (NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + guint CurrentFailCount, + guint TotalFailures, + guint TotalLifecycles, + gint ErrorStatus); + + +void nhm_dbus_info_complete_request_node_restart_stub(NhmDbusInfo *object, + GDBusMethodInvocation *invocation, + gint ErrorStatus); + +#endif /* NHM_DBUS_INFO_STUB_H */ diff --git a/tst/stubs/gen/nsm-dbus-consumer-stub.c b/tst/stubs/gen/nsm-dbus-consumer-stub.c new file mode 100644 index 0000000..03a24a2 --- /dev/null +++ b/tst/stubs/gen/nsm-dbus-consumer-stub.c @@ -0,0 +1,98 @@ +/* NHM - NodeHealthMonitor + * + * Implementation of stubs for the nsm-dbus-consumer + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <gen/nsm-dbus-consumer.h> +#include <tst/stubs/gen/nsm-dbus-consumer-stub.h> + +/******************************************************************************* +* +* Exported variables and constants +* +*******************************************************************************/ + +gboolean nsm_dbus_consumer_proxy_new_sync_stub_set_error = FALSE; +gboolean nsm_dbus_consumer_call_register_shutdown_client_sync_stub_set_error = FALSE; +gint nsm_dbus_consumer_call_register_shutdown_client_sync_stub_out_ErrorCode = 0; + + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + +/** + * nsm_dbus_consumer_proxy_new_sync_stub: + * + * Stub for nsm_dbus_consumer_proxy_new_sync() + */ +NsmDbusConsumer* +nsm_dbus_consumer_proxy_new_sync_stub(GDBusConnection *connection, + GDBusProxyFlags flags, + const gchar *name, + const gchar *object_path, + GCancellable *cancellable, + GError **error) +{ + NsmDbusConsumer *retval = NULL; + + if(nsm_dbus_consumer_proxy_new_sync_stub_set_error == FALSE) + { + retval = g_object_new(NSM_DBUS_TYPE_CONSUMER_PROXY, NULL); + } + else + { + retval = NULL; + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED, NULL); + } + + return retval; +} + +/** + * nsm_dbus_consumer_call_register_shutdown_client_sync_stub: + * + * Stub for nsm_dbus_consumer_call_register_shutdown_client_sync() + */ +gboolean +nsm_dbus_consumer_call_register_shutdown_client_sync_stub(NsmDbusConsumer *proxy, + const gchar *arg_BusName, + const gchar *arg_ObjName, + guint arg_ShutdownMode, + guint arg_TimeoutMs, + gint *out_ErrorCode, + GCancellable *cancellable, + GError **error) +{ + gboolean retval = TRUE; + + if(nsm_dbus_consumer_call_register_shutdown_client_sync_stub_set_error == FALSE) + { + retval = TRUE; + *out_ErrorCode = nsm_dbus_consumer_call_register_shutdown_client_sync_stub_out_ErrorCode; + } + else + { + retval = FALSE; + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED, NULL); + } + + return retval; +} diff --git a/tst/stubs/gen/nsm-dbus-consumer-stub.h b/tst/stubs/gen/nsm-dbus-consumer-stub.h new file mode 100644 index 0000000..8dbde6c --- /dev/null +++ b/tst/stubs/gen/nsm-dbus-consumer-stub.h @@ -0,0 +1,58 @@ +/* NHM - NodeHealthMonitor + * + * Definition of stubs for nsm-dbus-consumer + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef NSM_DBUS_CONSUMER_STUB_H +#define NSM_DBUS_CONSUMER_STUB_H + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <gen/nsm-dbus-consumer.h> /* Header of real nsm-dbus-consumer */ + +/******************************************************************************* +* +* Exported variables, constants and defines +* +*******************************************************************************/ + +extern gboolean nsm_dbus_consumer_proxy_new_sync_stub_set_error; +extern gboolean nsm_dbus_consumer_call_register_shutdown_client_sync_stub_set_error; +extern gint nsm_dbus_consumer_call_register_shutdown_client_sync_stub_out_ErrorCode; + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +NsmDbusConsumer* nsm_dbus_consumer_proxy_new_sync_stub (GDBusConnection *connection, + GDBusProxyFlags flags, + const gchar *name, + const gchar *object_path, + GCancellable *cancellable, + GError **error); + +gboolean nsm_dbus_consumer_call_register_shutdown_client_sync_stub(NsmDbusConsumer *proxy, + const gchar *arg_BusName, + const gchar *arg_ObjName, + guint arg_ShutdownMode, + guint arg_TimeoutMs, + gint *out_ErrorCode, + GCancellable *cancellable, + GError **error); + +#endif /* NSM_DBUS_CONSUMER_STUB_H */ diff --git a/tst/stubs/gen/nsm-dbus-lc-consumer-stub.c b/tst/stubs/gen/nsm-dbus-lc-consumer-stub.c new file mode 100644 index 0000000..82b0195 --- /dev/null +++ b/tst/stubs/gen/nsm-dbus-lc-consumer-stub.c @@ -0,0 +1,78 @@ +/* NHM - NodeHealthMonitor + * + * Implementation of stubs for the nsm-dbus-lc-consumer + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <gen/nsm-dbus-lc-consumer.h> +#include <tst/stubs/gen/nsm-dbus-lc-consumer-stub.h> + +/******************************************************************************* +* +* Exported variables and constants +* +*******************************************************************************/ + +gboolean nsm_dbus_lc_consumer_proxy_new_sync_stub_set_error = FALSE; +gint nsm_dbus_lc_consumer_complete_lifecycle_request_stub_ErrorCode = 0; + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + +/** + * nsm_dbus_lc_consumer_proxy_new_sync_stub: + * + * Stub for nsm_dbus_lc_consumer_proxy_new_sync() + */ +NsmDbusLcConsumer* +nsm_dbus_lc_consumer_proxy_new_sync_stub(GDBusConnection *connection, + GDBusProxyFlags flags, + const gchar *name, + const gchar *object_path, + GCancellable *cancellable, + GError **error) +{ + NsmDbusLcConsumer *retval = NULL; + + if(nsm_dbus_lc_consumer_proxy_new_sync_stub_set_error == FALSE) + { + retval = g_object_new(NSM_DBUS_LC_TYPE_CONSUMER_PROXY, NULL); + } + else + { + retval = NULL; + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED, NULL); + } + + return retval; +} + +/** + * nsm_dbus_lc_consumer_complete_lifecycle_request_stub: + * + * Stub for nsm_dbus_lc_consumer_complete_lifecycle_request() + */ +void +nsm_dbus_lc_consumer_complete_lifecycle_request_stub(NsmDbusLcConsumer *object, + GDBusMethodInvocation *invocation, + gint ErrorCode) +{ + nsm_dbus_lc_consumer_complete_lifecycle_request_stub_ErrorCode = ErrorCode; +} diff --git a/tst/stubs/gen/nsm-dbus-lc-consumer-stub.h b/tst/stubs/gen/nsm-dbus-lc-consumer-stub.h new file mode 100644 index 0000000..5e32057 --- /dev/null +++ b/tst/stubs/gen/nsm-dbus-lc-consumer-stub.h @@ -0,0 +1,54 @@ +/* NHM - NodeHealthMonitor + * + * Definition of stubs for nsm-dbus-lc-consumer + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef NSM_DBUS_LC_CONSUMER_STUB_H +#define NSM_DBUS_LC_CONSUMER_STUB_H + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <gen/nsm-dbus-lc-consumer.h> /* Header of real nsm-dbus-lc-consumer */ + +/******************************************************************************* +* +* Exported variables, constants and defines +* +*******************************************************************************/ + +extern gboolean nsm_dbus_lc_consumer_proxy_new_sync_stub_set_error; +extern gint nsm_dbus_lc_consumer_complete_lifecycle_request_stub_ErrorCode; + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +NsmDbusLcConsumer* nsm_dbus_lc_consumer_proxy_new_sync_stub(GDBusConnection *connection, + GDBusProxyFlags flags, + const gchar *name, + const gchar *object_path, + GCancellable *cancellable, + GError **error); + + +void nsm_dbus_lc_consumer_complete_lifecycle_request_stub (NsmDbusLcConsumer *object, + GDBusMethodInvocation *invocation, + gint ErrorCode); + +#endif /* NSM_DBUS_LC_CONSUMER_STUB_H */ + diff --git a/tst/stubs/gen/nsm-dbus-lc-control-stub.c b/tst/stubs/gen/nsm-dbus-lc-control-stub.c new file mode 100644 index 0000000..14e3096 --- /dev/null +++ b/tst/stubs/gen/nsm-dbus-lc-control-stub.c @@ -0,0 +1,123 @@ +/* NHM - NodeHealthMonitor + * + * Implementation of stubs for the nsm-dbus-lc-control + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <gen/nsm-dbus-lc-control.h> +#include <tst/stubs/gen/nsm-dbus-lc-control-stub.h> + +/******************************************************************************* +* +* Exported variables and constants +* +*******************************************************************************/ + +gboolean nsm_dbus_lc_control_proxy_new_sync_stub_set_error = FALSE; +gboolean nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error = FALSE; +gboolean nsm_dbus_lc_control_call_request_node_restart_sync_stub_set_error = FALSE; +gint nsm_dbus_lc_control_call_request_node_restart_sync_stub_out_ErrorCode = 0; + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + +/** + * nsm_dbus_lc_control_proxy_new_sync_stub: + * + * Stub for nsm_dbus_lc_control_proxy_new_sync() + */ +NsmDbusLcControl* +nsm_dbus_lc_control_proxy_new_sync_stub(GDBusConnection *connection, + GDBusProxyFlags flags, + const gchar *name, + const gchar *object_path, + GCancellable *cancellable, + GError **error) +{ + NsmDbusLcControl* retval = NULL; + + if(nsm_dbus_lc_control_proxy_new_sync_stub_set_error == FALSE) + { + retval = g_object_new(NSM_DBUS_LC_TYPE_CONTROL_PROXY, NULL); + } + else + { + retval = NULL; + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED, NULL); + } + + return retval; +} + +/** + * nsm_dbus_lc_control_call_set_app_health_status_sync_stub: + * + * Stub for nsm_dbus_lc_control_call_set_app_health_status_sync() + */ +gboolean +nsm_dbus_lc_control_call_set_app_health_status_sync_stub(NsmDbusLcControl *proxy, + const gchar *arg_AppName, + gboolean arg_AppRunning, + gint *out_ErrorCode, + GCancellable *cancellable, + GError **error) +{ + gboolean retval = FALSE; + + if(nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error == FALSE) + { + retval = TRUE; + } + else + { + retval = FALSE; + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED, NULL); + } + + return retval; +} + +/** + * nsm_dbus_lc_control_call_request_node_restart_sync_stub: + * + * Stub for nsm_dbus_lc_control_call_request_node_restart_sync() + */ +gboolean +nsm_dbus_lc_control_call_request_node_restart_sync_stub(NsmDbusLcControl *proxy, + gint arg_RestartReason, + guint arg_RestartType, + gint *out_ErrorCode, + GCancellable *cancellable, + GError **error) +{ + gboolean retval = FALSE; + + if(nsm_dbus_lc_control_call_request_node_restart_sync_stub_set_error == FALSE) + { + *out_ErrorCode = nsm_dbus_lc_control_call_request_node_restart_sync_stub_out_ErrorCode; + } + else + { + retval = FALSE; + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED, NULL); + } + + return retval; +} diff --git a/tst/stubs/gen/nsm-dbus-lc-control-stub.h b/tst/stubs/gen/nsm-dbus-lc-control-stub.h new file mode 100644 index 0000000..80a554d --- /dev/null +++ b/tst/stubs/gen/nsm-dbus-lc-control-stub.h @@ -0,0 +1,68 @@ +/* NHM - NodeHealthMonitor + * + * Definition of stubs for nsm-dbus-lc-control + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef NSM_DBUS_LC_CONTROL_STUB_H +#define NSM_DBUS_LC_CONTROL_STUB_H + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <gen/nsm-dbus-lc-control.h> /* Header of real nsm-dbus-lc-control */ + +/******************************************************************************* +* +* Exported variables, constants and defines +* +*******************************************************************************/ + +extern gboolean nsm_dbus_lc_control_proxy_new_sync_stub_set_error; +extern gboolean nsm_dbus_lc_control_call_set_app_health_status_sync_stub_set_error; +extern gboolean nsm_dbus_lc_control_call_request_node_restart_sync_stub_set_error; +extern gint nsm_dbus_lc_control_call_request_node_restart_sync_stub_out_ErrorCode; + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +NsmDbusLcControl* nsm_dbus_lc_control_proxy_new_sync_stub (GDBusConnection *connection, + GDBusProxyFlags flags, + const gchar *name, + const gchar *object_path, + GCancellable *cancellable, + GError **error); + + + +gboolean nsm_dbus_lc_control_call_set_app_health_status_sync_stub(NsmDbusLcControl *proxy, + const gchar *arg_AppName, + gboolean arg_AppRunning, + gint *out_ErrorCode, + GCancellable *cancellable, + GError **error); + + +gboolean nsm_dbus_lc_control_call_request_node_restart_sync_stub (NsmDbusLcControl *proxy, + gint arg_RestartReason, + guint arg_RestartType, + gint *out_ErrorCode, + GCancellable *cancellable, + GError **error); + + +#endif /* NSM_DBUS_LC_CONTROL_STUB_H */ diff --git a/tst/stubs/gio/gio-stub.c b/tst/stubs/gio/gio-stub.c new file mode 100644 index 0000000..6cf8fb1 --- /dev/null +++ b/tst/stubs/gio/gio-stub.c @@ -0,0 +1,422 @@ +/* NHM - NodeHealthMonitor + * + * Implementation of stubs for gio + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <stdio.h> /* NULL */ +#include <string.h> /* strcmp */ +#include <gio/gio.h> /* Header of real gio */ +#include <tst/stubs/gio/gio-stub.h> /* Header of stub gio */ + + +/******************************************************************************* +* +* Exported variables and constants +* +*******************************************************************************/ + +gboolean g_bus_get_sync_set_error = FALSE; +gboolean g_dbus_interface_skeleton_export_stub_set_error = FALSE; +gboolean g_main_loop_quit_stub_called = FALSE; +guint g_timeout_add_seconds_called_interval = 0; +gboolean g_timeout_add_seconds_called = FALSE; +gboolean g_dbus_connection_new_for_address_sync_stub_set_error = FALSE; +GdbusConnectionCallSyncStubControl g_dbus_connection_call_sync_stub_control; + + +/******************************************************************************* +* +* File local variables and constants +* +*******************************************************************************/ + +static guint folder_file_idx = 0; +static gchar *folder_files[] = {"0000", "0001", NULL}; + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + +/** + * g_file_test_stub: + * + * Stub for g_file_test() + */ +gboolean +g_file_test_stub(const gchar *filename, + GFileTest test) +{ + return (g_strcmp0(filename, "existing_file") == 0); +} + +/** + * g_file_read_link_stub: + * + * Stub for g_file_read_link() + */ +gchar* +g_file_read_link_stub(const gchar *filename, + GError **error) +{ + gchar *linked_file = NULL; + + if(strcmp("/proc/0000/exe", filename) == 0) + { + linked_file = g_strdup("/usr/bin/valid_prog1"); + } + else if(strcmp("/proc/0001/exe", filename) == 0) + { + linked_file = g_strdup("/usr/bin/valid_prog2"); + } + else + { + linked_file = NULL; + } + + return linked_file; +} + +/** + * g_dir_open_stub: + * + * Stub for g_dir_open() + */ +GDir* +g_dir_open_stub(const gchar *path, + guint flags, + GError **error) +{ + folder_file_idx = 0; + return (GDir*) folder_files; +} + +/** + * g_dir_read_name_stub: + * + * Stub for g_dir_read_name() + */ +const gchar* +g_dir_read_name_stub(GDir *dir) +{ + gchar *file_name = NULL; + + if(folder_file_idx < sizeof(folder_files)/sizeof(gchar*)) + { + file_name = folder_files[folder_file_idx]; + folder_file_idx++; + } + + return file_name; +} + +/** + * g_dir_close_stub: + * + * Stub for g_dir_close() + */ +void +g_dir_close_stub(GDir *dir) +{ + folder_file_idx = 0; +} + + +/** + * g_bus_get_sync_stub: + * + * Stub for g_bus_get_sync() + */ +GDBusConnection* +g_bus_get_sync_stub(GBusType bus_type, + GCancellable *cancellable, + GError **error) +{ + gpointer retval = FALSE; + + if(g_bus_get_sync_set_error == FALSE) + { + retval = g_object_new(G_TYPE_DBUS_CONNECTION, NULL); + } + else + { + retval = NULL; + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, NULL); + } + + return retval; +} + +/** + * g_bus_own_name_stub: + * + * Stub for g_bus_own_name() + */ +guint +g_bus_own_name_stub(GBusType bus_type, + const gchar *name, + GBusNameOwnerFlags flags, + GBusAcquiredCallback bus_acquired_handler, + GBusNameAcquiredCallback name_acquired_handler, + GBusNameLostCallback name_lost_handler, + gpointer user_data, + GDestroyNotify user_data_free_func) +{ + return 0; +} + +/** + * g_dbus_connection_get_unique_name_stub: + * + * Stub for g_dbus_connection_get_unique_name() + */ +const gchar* +g_dbus_connection_get_unique_name_stub(GDBusConnection *connection) +{ + return NULL; +} + +/** + * g_dbus_interface_skeleton_export_stub: + * + * Stub for g_dbus_interface_skeleton_export() + */ +gboolean +g_dbus_interface_skeleton_export_stub(GDBusInterfaceSkeleton *interface_, + GDBusConnection *connection, + const gchar *object_path, + GError **error) +{ + gboolean retval = FALSE; + + if(g_dbus_interface_skeleton_export_stub_set_error == FALSE) + { + retval = TRUE; + } + else + { + retval = FALSE; + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, NULL); + } + + return retval; +} + + +/** + * g_dbus_connection_new_for_address_sync_stub: + * + * Stub for g_dbus_connection_new_for_address_sync() + */ +GDBusConnection* +g_dbus_connection_new_for_address_sync_stub(const gchar *address, + GDBusConnectionFlags flags, + GDBusAuthObserver *observer, + GCancellable *cancellable, + GError **error) +{ + GDBusConnection *retval = NULL; + + if(g_dbus_connection_new_for_address_sync_stub_set_error == FALSE) + { + retval = g_object_new(G_TYPE_DBUS_CONNECTION, NULL); + } + else + { + retval = NULL; + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, NULL); + } + + return retval; +} + + +/** + * g_dbus_connection_call_sync_stub: + * + * Stub for g_dbus_connection_call_sync() + */ +GVariant* +g_dbus_connection_call_sync_stub(GDBusConnection *connection, + const gchar *bus_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + const GVariantType *reply_type, + GDBusCallFlags flags, + gint timeout_msec, + GCancellable *cancellable, + GError **error) +{ + GVariant *rval = NULL; + guint control_array_idx = 0; + GdbusConnectionCallSyncStubCalls *call = NULL; + + for(control_array_idx = 0; + (control_array_idx < g_dbus_connection_call_sync_stub_control.count) + && (call == NULL); + control_array_idx++) + { + if(g_strcmp0(g_dbus_connection_call_sync_stub_control.calls[control_array_idx].method, + method_name) == 0) + { + call = &g_dbus_connection_call_sync_stub_control.calls[control_array_idx]; + } + } + + if(call != NULL) + { + rval = call->rval; + + if((rval == NULL) && (error != NULL)) + { + g_set_error(error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, NULL); + } + } + + return rval; +} + + +/** + * g_dbus_connection_signal_subscribe_stub: + * + * Stub for g_dbus_connection_signal_subscribe() + */ +guint +g_dbus_connection_signal_subscribe_stub(GDBusConnection *connection, + const gchar *sender, + const gchar *interface_name, + const gchar *member, + const gchar *object_path, + const gchar *arg0, + GDBusSignalFlags flags, + GDBusSignalCallback callback, + gpointer user_data, + GDestroyNotify user_data_free_func) +{ + return 0; +} + + +/** + * g_dbus_connection_signal_unsubscribe_stub: + * + * Stub for g_dbus_connection_signal_unsubscribe() + */ +void +g_dbus_connection_signal_unsubscribe_stub(GDBusConnection *connection, + guint subscription_id) +{ + +} + + +/** + * g_main_loop_run_stub: + * + * Stub for g_main_loop_run() + */ +void +g_main_loop_run_stub(GMainLoop *loop) +{ +} + +/** + * g_main_loop_quit_stub: + * + * Stub for g_main_loop_quit() + */ +void +g_main_loop_quit_stub(GMainLoop *loop) +{ + g_main_loop_quit_stub_called = TRUE; +} + +/** + * g_timeout_add_seconds_stub: + * + * Stub for g_timeout_add_seconds() + */ +guint +g_timeout_add_seconds_stub(guint interval, + GSourceFunc function, + gpointer data) +{ + g_timeout_add_seconds_called_interval = interval; + g_timeout_add_seconds_called = TRUE; + + return 0; +} + +/** + * g_signal_connect_data_stub: + * + * Stub for g_signal_connect_data() + */ +gulong +g_signal_connect_data_stub(gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags) +{ + return 0; +} + +/** + * g_spawn_sync_stub: + * + * Stub for g_spawn_sync() + */ +gboolean +g_spawn_sync_stub(const gchar *working_directory, + gchar **argv, + gchar **envp, + GSpawnFlags flags, + GSpawnChildSetupFunc child_setup, + gpointer user_data, + gchar **standard_output, + gchar **standard_error, + gint *exit_status, + GError **error) +{ + gboolean retval = FALSE; + + if(strcmp(argv[0], "valid_proc") == 0) + { + retval = TRUE; + *exit_status = 0; + *error = NULL; + } + else if(strcmp(argv[0], "failing_proc") == 0) + { + retval = TRUE; + *exit_status = -1; + *error = NULL; + } + else + { + retval = FALSE; + g_set_error(error, G_SPAWN_ERROR, G_SPAWN_ERROR_FAILED, NULL); + } + + return retval; +} diff --git a/tst/stubs/gio/gio-stub.h b/tst/stubs/gio/gio-stub.h new file mode 100644 index 0000000..fbb4d0e --- /dev/null +++ b/tst/stubs/gio/gio-stub.h @@ -0,0 +1,161 @@ +/* NHM - NodeHealthMonitor + * + * Definition of stubs for gio + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef GIO_STUB_H +#define GIO_STUB_H + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> /* Include header of real gio */ + +/******************************************************************************* +* +* Exported variables, constants and defines +* +*******************************************************************************/ + +typedef struct +{ + gchar *method; + GVariant *rval; +} GdbusConnectionCallSyncStubCalls; + +typedef struct +{ + guint count; + GdbusConnectionCallSyncStubCalls *calls; +} GdbusConnectionCallSyncStubControl; + + +extern gboolean g_main_loop_quit_stub_called; +extern gboolean g_bus_get_sync_set_error; +extern guint g_timeout_add_seconds_called_interval; +extern gboolean g_timeout_add_seconds_called; +extern gboolean g_dbus_interface_skeleton_export_stub_set_error; +extern gboolean g_dbus_connection_new_for_address_sync_stub_set_error; +extern gboolean g_dbus_connection_call_sync_stub_set_error; +extern GdbusConnectionCallSyncStubControl g_dbus_connection_call_sync_stub_control; + + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +/* File and folder reading */ +gboolean g_file_test_stub (const gchar *filename, + GFileTest test); +gchar *g_file_read_link_stub (const gchar *filename, + GError **error); +GDir *g_dir_open_stub (const gchar *path, + guint flags, + GError **error); +const gchar *g_dir_read_name_stub (GDir *dir); +void g_dir_close_stub (GDir *dir); + +/* Mainloop handling */ +void g_main_loop_run_stub (GMainLoop *loop); +void g_main_loop_quit_stub (GMainLoop *loop); + +/* Dbus handling */ +GDBusConnection *g_bus_get_sync_stub (GBusType bus_type, + GCancellable *cancellable, + GError **error); +const gchar *g_dbus_connection_get_unique_name_stub(GDBusConnection *connection); +guint g_bus_own_name_stub (GBusType bus_type, + const gchar *name, + GBusNameOwnerFlags flags, + GBusAcquiredCallback bus_acquired_handler, + GBusNameAcquiredCallback name_acquired_handler, + GBusNameLostCallback name_lost_handler, + gpointer user_data, + GDestroyNotify user_data_free_func); + + +gboolean g_dbus_interface_skeleton_export_stub (GDBusInterfaceSkeleton *interface_, + GDBusConnection *connection, + const gchar *object_path, + GError **error); + +GDBusConnection *g_dbus_connection_new_for_address_sync_stub(const gchar *address, + GDBusConnectionFlags flags, + GDBusAuthObserver *observer, + GCancellable *cancellable, + GError **error); + +GVariant *g_dbus_connection_call_sync_stub (GDBusConnection *connection, + const gchar *bus_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + const GVariantType *reply_type, + GDBusCallFlags flags, + gint timeout_msec, + GCancellable *cancellable, + GError **error); +guint g_dbus_connection_signal_subscribe_stub (GDBusConnection *connection, + const gchar *sender, + const gchar *interface_name, + const gchar *member, + const gchar *object_path, + const gchar *arg0, + GDBusSignalFlags flags, + GDBusSignalCallback callback, + gpointer user_data, + GDestroyNotify user_data_free_func); +void g_dbus_connection_signal_unsubscribe_stub (GDBusConnection *connection, + guint subscription_id); +GVariant *g_dbus_connection_call_sync_stub (GDBusConnection *connection, + const gchar *bus_name, + const gchar *object_path, + const gchar *interface_name, + const gchar *method_name, + GVariant *parameters, + const GVariantType *reply_type, + GDBusCallFlags flags, + gint timeout_msec, + GCancellable *cancellable, + GError **error); + +/* Timer and signals */ +guint g_timeout_add_seconds_stub (guint interval, + GSourceFunc function, + gpointer data); + +gulong g_signal_connect_data_stub (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data, + GClosureNotify destroy_data, + GConnectFlags connect_flags); + +/* Process handling */ +gboolean g_spawn_sync_stub (const gchar *working_directory, + gchar **argv, + gchar **envp, + GSpawnFlags flags, + GSpawnChildSetupFunc child_setup, + gpointer user_data, + gchar **standard_output, + gchar **standard_error, + gint *exit_status, + GError **error); + + +#endif /* GIO_STUB_H */ diff --git a/tst/stubs/nhm/nhm-systemd-stub.c b/tst/stubs/nhm/nhm-systemd-stub.c new file mode 100644 index 0000000..658f032 --- /dev/null +++ b/tst/stubs/nhm/nhm-systemd-stub.c @@ -0,0 +1,48 @@ +/* NHM - NodeHealthMonitor + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + */ + +/****************************************************************************** +* +* Header includes +* +******************************************************************************/ + +#include <gio/gio.h> /* Use gtypes */ +#include <src/nhm-systemd.h> /* Original header */ + +/****************************************************************************** +* +* Interfaces. Exported functions. See Header for detailed description. +* +******************************************************************************/ + + +/** + * nhm_systemd_connect_stub: + * + * Stub for nhm_systemd_connect() + */ +gboolean +nhm_systemd_connect_stub(NhmSystemdAppStatusCb app_status_cb) +{ + return TRUE; +} + +/** + * nhm_systemd_disconnect_stub: + * + * Stub for nhm_systemd_disconnect() + */ +void +nhm_systemd_disconnect_stub(void) +{ + +} diff --git a/tst/stubs/nhm/nhm-systemd-stub.h b/tst/stubs/nhm/nhm-systemd-stub.h new file mode 100644 index 0000000..a236cb7 --- /dev/null +++ b/tst/stubs/nhm/nhm-systemd-stub.h @@ -0,0 +1,33 @@ +#ifndef NHM_SYSTEMD_STUB_H +#define NHM_SYSTEMD_STUB_H + +/* NHM - NodeHealthMonitor + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> /* Use gtypes */ +#include <src/nhm-systemd.h> /* Original header */ + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +gboolean nhm_systemd_connect_stub (NhmSystemdAppStatusCb app_status_cb); +void nhm_systemd_disconnect_stub(void); + +#endif /* NHM_SYSTEMD_STUB_H */ diff --git a/tst/stubs/persistence/persistence_client_library_key-stub.c b/tst/stubs/persistence/persistence_client_library_key-stub.c new file mode 100644 index 0000000..9a88d3f --- /dev/null +++ b/tst/stubs/persistence/persistence_client_library_key-stub.c @@ -0,0 +1,103 @@ +/* NHM - NodeHealthMonitor + * + * Implementation of stubs for the persistence client library + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +/* Own header */ +#include <stdio.h> +#include <string.h> +#include <tst/stubs/persistence/persistence_client_library_key-stub.h> + +/******************************************************************************* +* +* Exported variables and constants +* +*******************************************************************************/ + +int pclInitLibrary_stub_return = 0; +int pclKeyWriteData_stub_return = 0; +int pclKeyWriteData_stub_WriteVal = 0; +int pclKeyReadData_stub_return = 0; +int pclKeyReadData_stub_ReadVal = 0; +int pclDeinitLibrary_stub_return = 0; + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + + +/** + * pclInitLibrary_stub: + * + * Stub for pclInitLibrary() + */ +int +pclInitLibrary_stub(const char *appname, + int shutdownMode) +{ + return pclInitLibrary_stub_return; +} + + +/** + * pclKeyWriteData_stub: + * + * Stub for pclKeyWriteData() + */ +int +pclKeyWriteData_stub(unsigned int ldbid, + const char* resource_id, + unsigned int user_no, + unsigned int seat_no, + unsigned char* buffer, + int buffer_size) +{ + memcpy(&pclKeyWriteData_stub_WriteVal, buffer, buffer_size); + + return pclKeyWriteData_stub_return; +} + +/** + * pclKeyReadData_stub: + * + * Stub for pclKeyReadData() + */ +int pclKeyReadData_stub(unsigned int ldbid, + const char* resource_id, + unsigned int user_no, + unsigned int seat_no, + unsigned char* buffer, + int buffer_size) +{ + memcpy(buffer, &pclKeyReadData_stub_ReadVal, buffer_size); + + return pclKeyReadData_stub_return; +} + + +/** + * pclDeinitLibrary_stub: + * + * Stub for pclDeinitLibrary() + */ +int +pclDeinitLibrary_stub(void) +{ + return pclDeinitLibrary_stub_return; +} diff --git a/tst/stubs/persistence/persistence_client_library_key-stub.h b/tst/stubs/persistence/persistence_client_library_key-stub.h new file mode 100644 index 0000000..f85062c --- /dev/null +++ b/tst/stubs/persistence/persistence_client_library_key-stub.h @@ -0,0 +1,52 @@ +/* NHM - NodeHealthMonitor + * + * Definition of stubs for the persistence client library + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef PERSISTENCE_CLIENT_LIBRARY_KEY_STUB_H +#define PERSISTENCE_CLIENT_LIBRARY_KEY_STUB_H + +/******************************************************************************* +* +* Exported variables, constants and defines +* +*******************************************************************************/ + +extern int pclInitLibrary_stub_return; +extern int pclKeyWriteData_stub_return; +extern int pclKeyWriteData_stub_WriteVal; +extern int pclKeyReadData_stub_ReadVal; +extern int pclKeyReadData_stub_return; +extern int pclDeinitLibrary_stub_return; + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +int pclInitLibrary_stub (const char *appname, + int shutdownMode); +int pclKeyWriteData_stub (unsigned int ldbid, + const char *resource_id, + unsigned int user_no, + unsigned int seat_no, + unsigned char *buffer, + int buffer_size); +int pclKeyReadData_stub (unsigned int ldbid, + const char *resource_id, + unsigned int user_no, + unsigned int seat_no, + unsigned char *buffer, + int buffer_size); +int pclDeinitLibrary_stub(void); + +#endif /* PERSISTENCE_CLIENT_LIBRARY_KEY_STUB_H */ diff --git a/tst/stubs/systemd/sd-daemon-stub.c b/tst/stubs/systemd/sd-daemon-stub.c new file mode 100644 index 0000000..0c23eca --- /dev/null +++ b/tst/stubs/systemd/sd-daemon-stub.c @@ -0,0 +1,50 @@ +/* NHM - NodeHealthMonitor + * + * Implementation of stubs for the sd daemon + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <systemd/sd-daemon.h> /* Header of real sd daemon */ +#include <tst/stubs/systemd/sd-daemon-stub.h> /* Header of stub sd daemon */ + +/******************************************************************************* +* +* Exported variables and constants +* +*******************************************************************************/ + +gboolean sd_notify_stub_called = FALSE; + +/******************************************************************************* +* +* Interfaces. Exported functions. +* +*******************************************************************************/ + +/** + * sd_notify_stub: + * + * Stub for sd_notify() + */ +int +sd_notify_stub(int unset_environment, + const char *state) +{ + sd_notify_stub_called = TRUE; + + return 0; +} diff --git a/tst/stubs/systemd/sd-daemon-stub.h b/tst/stubs/systemd/sd-daemon-stub.h new file mode 100644 index 0000000..dca9a5e --- /dev/null +++ b/tst/stubs/systemd/sd-daemon-stub.h @@ -0,0 +1,42 @@ +/* NHM - NodeHealthMonitor + * + * Definition of stubs for the sd daemon + * + * Author: Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com> + * + * Copyright (C) 2013 Continental Automotive Systems, Inc. + * + * This Source Code Form is subject to the terms of the Mozilla Public License, + * v. 2.0. If a copy of the MPL was not distributed with this file, You can + * obtain one at http://mozilla.org/MPL/2.0/. + */ + +#ifndef SD_DAEMON_STUB_H +#define SD_DAEMON_STUB_H + +/******************************************************************************* +* +* Header includes +* +*******************************************************************************/ + +#include <gio/gio.h> +#include <systemd/sd-daemon.h> /* Include header of real sd daemon */ + +/******************************************************************************* +* +* Exported variables, constants and defines +* +*******************************************************************************/ + +extern gboolean sd_notify_stub_called; + +/******************************************************************************* +* +* Exported functions +* +*******************************************************************************/ + +int sd_notify_stub(int unset_environment, const char *state); + +#endif /* SD_DAEMON_STUB_H */ |