From e8ec4787395986599cc2c816ac2bbe56d3c85764 Mon Sep 17 00:00:00 2001 From: Jean-Pierre Bogler Date: Tue, 29 Oct 2013 09:30:57 +0100 Subject: NodeHealthMonitor version 1.3.3 for initial OSS release --- AUTHORS | 1 + COPYING | 373 +++ ChangeLog | 32 + Makefile.am | 21 + NEWS | 38 + README | 28 + autogen.sh | 19 + cfg/Makefile.am | 34 + cfg/node-health-monitor.conf | 50 + cfg/node-health-monitor.pc.in | 14 + cfg/node-health-monitor.service.in | 15 + cfg/org.genivi.NodeHealthMonitor.service.in | 6 + configure.ac | 85 + gen/Makefile.am | 51 + inc/Makefile.am | 21 + inc/NodeHealthMonitor.h | 73 + mod/Makefile.am | 24 + mod/org.genivi.NodeHealthMonitor.Info.xml | 108 + src/Makefile.am | 58 + src/nhm-helper.c | 80 + src/nhm-helper.h | 45 + src/nhm-main.c | 2394 ++++++++++++++++++++ src/nhm-systemd.c | 930 ++++++++ src/nhm-systemd.h | 47 + tst/Makefile.am | 104 + tst/nhm-main-test.c | 1110 +++++++++ tst/nhm-main-test.h | 235 ++ tst/nhm-systemd-test.c | 882 ++++++++ tst/nhm-systemd-test.h | 90 + tst/stubs/dlt/dlt-stub.c | 141 ++ tst/stubs/dlt/dlt-stub.h | 51 + tst/stubs/gen/nhm-dbus-info-stub.c | 97 + tst/stubs/gen/nhm-dbus-info-stub.h | 62 + tst/stubs/gen/nsm-dbus-consumer-stub.c | 98 + tst/stubs/gen/nsm-dbus-consumer-stub.h | 58 + tst/stubs/gen/nsm-dbus-lc-consumer-stub.c | 78 + tst/stubs/gen/nsm-dbus-lc-consumer-stub.h | 54 + tst/stubs/gen/nsm-dbus-lc-control-stub.c | 123 + tst/stubs/gen/nsm-dbus-lc-control-stub.h | 68 + tst/stubs/gio/gio-stub.c | 422 ++++ tst/stubs/gio/gio-stub.h | 161 ++ tst/stubs/nhm/nhm-systemd-stub.c | 48 + tst/stubs/nhm/nhm-systemd-stub.h | 33 + .../persistence_client_library_key-stub.c | 103 + .../persistence_client_library_key-stub.h | 52 + tst/stubs/systemd/sd-daemon-stub.c | 50 + tst/stubs/systemd/sd-daemon-stub.h | 42 + 47 files changed, 8709 insertions(+) create mode 100644 AUTHORS create mode 100644 COPYING create mode 100644 ChangeLog create mode 100644 Makefile.am create mode 100644 NEWS create mode 100644 README create mode 100755 autogen.sh create mode 100644 cfg/Makefile.am create mode 100644 cfg/node-health-monitor.conf create mode 100644 cfg/node-health-monitor.pc.in create mode 100644 cfg/node-health-monitor.service.in create mode 100644 cfg/org.genivi.NodeHealthMonitor.service.in create mode 100644 configure.ac create mode 100644 gen/Makefile.am create mode 100644 inc/Makefile.am create mode 100644 inc/NodeHealthMonitor.h create mode 100644 mod/Makefile.am create mode 100644 mod/org.genivi.NodeHealthMonitor.Info.xml create mode 100644 src/Makefile.am create mode 100644 src/nhm-helper.c create mode 100644 src/nhm-helper.h create mode 100644 src/nhm-main.c create mode 100644 src/nhm-systemd.c create mode 100644 src/nhm-systemd.h create mode 100644 tst/Makefile.am create mode 100644 tst/nhm-main-test.c create mode 100644 tst/nhm-main-test.h create mode 100644 tst/nhm-systemd-test.c create mode 100644 tst/nhm-systemd-test.h create mode 100644 tst/stubs/dlt/dlt-stub.c create mode 100644 tst/stubs/dlt/dlt-stub.h create mode 100644 tst/stubs/gen/nhm-dbus-info-stub.c create mode 100644 tst/stubs/gen/nhm-dbus-info-stub.h create mode 100644 tst/stubs/gen/nsm-dbus-consumer-stub.c create mode 100644 tst/stubs/gen/nsm-dbus-consumer-stub.h create mode 100644 tst/stubs/gen/nsm-dbus-lc-consumer-stub.c create mode 100644 tst/stubs/gen/nsm-dbus-lc-consumer-stub.h create mode 100644 tst/stubs/gen/nsm-dbus-lc-control-stub.c create mode 100644 tst/stubs/gen/nsm-dbus-lc-control-stub.h create mode 100644 tst/stubs/gio/gio-stub.c create mode 100644 tst/stubs/gio/gio-stub.h create mode 100644 tst/stubs/nhm/nhm-systemd-stub.c create mode 100644 tst/stubs/nhm/nhm-systemd-stub.h create mode 100644 tst/stubs/persistence/persistence_client_library_key-stub.c create mode 100644 tst/stubs/persistence/persistence_client_library_key-stub.h create mode 100644 tst/stubs/systemd/sd-daemon-stub.c create mode 100644 tst/stubs/systemd/sd-daemon-stub.h diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..387c7d3 --- /dev/null +++ b/AUTHORS @@ -0,0 +1 @@ +Jean-Pierre Bogler 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 + * 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 + * Changed handling of restart_apps + +17th Jun 2013 Jean-Pierre Bogler + * 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 + * Call Init/DeInit of PCL to support version 6.0.0 + +15th May 2013 Jean-Pierre Bogler + * Introduced dbus observation. Added new config. key, adapted source code. + Extended unit test to cover new functionality. + +02nd May 2013 Jean-Pierre Bogler + * Adapted code to store "shutdown flag" via GENIVI Persistency, + instead of using the file "${datadir}/lib/shutdownflag". + +15th Mar 2013 Jean-Pierre Bogler + * 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + */ + +/** + * 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 trace */ +#include /* 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 + * + * 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 traces */ +#include /* 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 + */ + +/** + * 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 /* FILE, write, read */ +#include /* Use strlen */ +#include /* Use strtol */ +#include /* Define SIGTERM */ +#include /* Use errno */ +#include /* Catch SIGTERM */ +#include /* GIO for dbus */ +#include /* GLIB for lists, arrays, etc. */ +#include /* DLT Log'n'Trace */ +#include /* systemd WDOG */ +#include /* NSM types for dbus comm. */ +#include /* Init/DeInit PCL */ +#include /* Access persistent data */ + + +/* Generated D-Bus interface header files */ +#include /* Own dbus info interface */ +#include /* Consumer interface of the NSM */ +#include /* LC Control interface of the NSM */ +#include /* 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 + */ + +/** + * 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 /* NULL */ +#include /* Use gdbus */ +#include /* 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 + * + * 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 /* 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 + */ + +/** + * 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 +#include + +/* 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 + */ + +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +/* 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 + +/* 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 + */ + +/** + * 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 /* NULL */ +#include /* 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 + */ + +/* + * 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 +#include + + +/* 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 + +/* 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 + * + * 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 /* Header of real sd daemon */ +#include /* 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 + * + * 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 /* 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 + * + * 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 +#include +#include + +/******************************************************************************* +* +* 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 + * + * 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 +#include /* 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 + * + * 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 +#include +#include + +/******************************************************************************* +* +* 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 + * + * 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 +#include /* 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 + * + * 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 +#include +#include + +/******************************************************************************* +* +* 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 + * + * 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 +#include /* 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 + * + * 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 +#include +#include + +/******************************************************************************* +* +* 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 + * + * 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 +#include /* 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 + * + * 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 /* NULL */ +#include /* strcmp */ +#include /* Header of real gio */ +#include /* 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 + * + * 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 /* 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 + */ + +/****************************************************************************** +* +* Header includes +* +******************************************************************************/ + +#include /* Use gtypes */ +#include /* 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 + * + * 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 /* Use gtypes */ +#include /* 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 + * + * 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 +#include +#include + +/******************************************************************************* +* +* 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 + * + * 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 + * + * 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 +#include /* Header of real sd daemon */ +#include /* 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 + * + * 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 +#include /* 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 */ -- cgit v1.2.1