summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Pierre Bogler <jean-pierre.bogler@continental-corporation.com>2013-10-29 09:30:57 +0100
committerJean-Pierre Bogler <jean-pierre.bogler@continental-corporation.com>2013-10-29 09:30:57 +0100
commite8ec4787395986599cc2c816ac2bbe56d3c85764 (patch)
tree10ea50af26d25cf94da09cf9cf7c80094be94405
downloadnode-health-monitor-e8ec4787395986599cc2c816ac2bbe56d3c85764.tar.gz
NodeHealthMonitor version 1.3.3 for initial OSS release1.3.3
-rw-r--r--AUTHORS1
-rw-r--r--COPYING373
-rw-r--r--ChangeLog32
-rw-r--r--Makefile.am21
-rw-r--r--NEWS38
-rw-r--r--README28
-rwxr-xr-xautogen.sh19
-rw-r--r--cfg/Makefile.am34
-rw-r--r--cfg/node-health-monitor.conf50
-rw-r--r--cfg/node-health-monitor.pc.in14
-rw-r--r--cfg/node-health-monitor.service.in15
-rw-r--r--cfg/org.genivi.NodeHealthMonitor.service.in6
-rw-r--r--configure.ac85
-rw-r--r--gen/Makefile.am51
-rw-r--r--inc/Makefile.am21
-rw-r--r--inc/NodeHealthMonitor.h73
-rw-r--r--mod/Makefile.am24
-rw-r--r--mod/org.genivi.NodeHealthMonitor.Info.xml108
-rw-r--r--src/Makefile.am58
-rw-r--r--src/nhm-helper.c80
-rw-r--r--src/nhm-helper.h45
-rw-r--r--src/nhm-main.c2394
-rw-r--r--src/nhm-systemd.c930
-rw-r--r--src/nhm-systemd.h47
-rw-r--r--tst/Makefile.am104
-rw-r--r--tst/nhm-main-test.c1110
-rw-r--r--tst/nhm-main-test.h235
-rw-r--r--tst/nhm-systemd-test.c882
-rw-r--r--tst/nhm-systemd-test.h90
-rw-r--r--tst/stubs/dlt/dlt-stub.c141
-rw-r--r--tst/stubs/dlt/dlt-stub.h51
-rw-r--r--tst/stubs/gen/nhm-dbus-info-stub.c97
-rw-r--r--tst/stubs/gen/nhm-dbus-info-stub.h62
-rw-r--r--tst/stubs/gen/nsm-dbus-consumer-stub.c98
-rw-r--r--tst/stubs/gen/nsm-dbus-consumer-stub.h58
-rw-r--r--tst/stubs/gen/nsm-dbus-lc-consumer-stub.c78
-rw-r--r--tst/stubs/gen/nsm-dbus-lc-consumer-stub.h54
-rw-r--r--tst/stubs/gen/nsm-dbus-lc-control-stub.c123
-rw-r--r--tst/stubs/gen/nsm-dbus-lc-control-stub.h68
-rw-r--r--tst/stubs/gio/gio-stub.c422
-rw-r--r--tst/stubs/gio/gio-stub.h161
-rw-r--r--tst/stubs/nhm/nhm-systemd-stub.c48
-rw-r--r--tst/stubs/nhm/nhm-systemd-stub.h33
-rw-r--r--tst/stubs/persistence/persistence_client_library_key-stub.c103
-rw-r--r--tst/stubs/persistence/persistence_client_library_key-stub.h52
-rw-r--r--tst/stubs/systemd/sd-daemon-stub.c50
-rw-r--r--tst/stubs/systemd/sd-daemon-stub.h42
47 files changed, 8709 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..387c7d3
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1 @@
+Jean-Pierre Bogler <Jean-Pierre.Bogler@continental-corporation.com>
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..14e2f77
--- /dev/null
+++ b/COPYING
@@ -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
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..46b6119
--- /dev/null
+++ b/NEWS
@@ -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)
diff --git a/README b/README
new file mode 100644
index 0000000..ee2eb34
--- /dev/null
+++ b/README
@@ -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 */