--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<?fileVersion 4.0.0?>
+
+<cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+<storageModule moduleId="org.eclipse.cdt.core.settings">
+<cconfiguration id="cdt.managedbuild.toolchain.gnu.cross.base.1196063785">
+<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.toolchain.gnu.cross.base.1196063785" moduleId="org.eclipse.cdt.core.settings" name="Cross GCC">
+<externalSettings/>
+<extensions>
+<extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+<extension id="org.eclipse.cdt.core.MakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+</extensions>
+</storageModule>
+<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+<configuration artifactName="libplpha2" buildProperties="" description="" id="cdt.managedbuild.toolchain.gnu.cross.base.1196063785" name="Cross GCC" parent="org.eclipse.cdt.build.core.emptycfg">
+<folderInfo id="cdt.managedbuild.toolchain.gnu.cross.base.1196063785.592276132" name="/" resourcePath="">
+<toolChain id="cdt.managedbuild.toolchain.gnu.cross.base.256416209" name="cdt.managedbuild.toolchain.gnu.cross.base" superClass="cdt.managedbuild.toolchain.gnu.cross.base">
+<option id="cdt.managedbuild.option.gnu.cross.prefix.2096487669" name="Prefix" superClass="cdt.managedbuild.option.gnu.cross.prefix"/>
+<option id="cdt.managedbuild.option.gnu.cross.path.1988795369" name="Path" superClass="cdt.managedbuild.option.gnu.cross.path"/>
+<targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="cdt.managedbuild.targetPlatform.gnu.cross.312022990" isAbstract="false" osList="all" superClass="cdt.managedbuild.targetPlatform.gnu.cross"/>
+<builder id="cdt.managedbuild.toolchain.gnu.cross.base.1196063785.1138409088" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
+<tool id="cdt.managedbuild.tool.gnu.cross.cpp.compiler.934785405" name="Cross G++ Compiler" superClass="cdt.managedbuild.tool.gnu.cross.cpp.compiler">
+<inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.113975571" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/>
+</tool>
+<tool id="cdt.managedbuild.tool.gnu.cross.cpp.linker.1919764139" name="Cross G++ Linker" superClass="cdt.managedbuild.tool.gnu.cross.cpp.linker">
+<inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.157916714" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input">
+<additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+<additionalInput kind="additionalinput" paths="$(LIBS)"/>
+</inputType>
+</tool>
+</toolChain>
+</folderInfo>
+</configuration>
+</storageModule>
+<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
+<storageModule moduleId="scannerConfiguration">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile"/>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<scannerConfigBuildInfo instanceId="cdt.managedbuild.toolchain.gnu.cross.base.1196063785;cdt.managedbuild.toolchain.gnu.cross.base.1196063785.592276132;cdt.managedbuild.tool.gnu.cross.cpp.compiler.934785405;cdt.managedbuild.tool.gnu.cpp.compiler.input.113975571">
+<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP"/>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="makefileGenerator">
+<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
+<buildOutputProvider>
+<openAction enabled="true" filePath=""/>
+<parser enabled="true"/>
+</buildOutputProvider>
+<scannerInfoProvider id="specsFile">
+<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
+<parser enabled="true"/>
+</scannerInfoProvider>
+</profile>
+</scannerConfigBuildInfo>
+</storageModule>
+</cconfiguration>
+</storageModule>
+<storageModule moduleId="cdtBuildSystem" version="4.0.0">
+<project id="libplpha2.null.377175162" name="libplpha2"/>
+</storageModule>
+</cproject>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>libplpha</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+ <triggers>clean,full,incremental,</triggers>
+ <arguments>
+ <dictionary>
+ <key>?name?</key>
+ <value></value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.append_environment</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.autoBuildTarget</key>
+ <value>all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.buildArguments</key>
+ <value></value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.buildCommand</key>
+ <value>make</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
+ <value>clean</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.contents</key>
+ <value>org.eclipse.cdt.make.core.activeConfigSettings</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableAutoBuild</key>
+ <value>false</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableCleanBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.enableFullBuild</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.fullBuildTarget</key>
+ <value>all</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.stopOnError</key>
+ <value>true</value>
+ </dictionary>
+ <dictionary>
+ <key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
+ <value>true</value>
+ </dictionary>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.cdt.core.cnature</nature>
+ <nature>org.eclipse.cdt.core.ccnature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+ </natures>
+</projectDescription>
--- /dev/null
+Mika Laitio <lamikr at pilppa dot org>
--- /dev/null
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
--- /dev/null
+Installation Instructions
+*************************
+
+Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005,
+2006, 2007, 2008, 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+are permitted in any medium without royalty provided the copyright
+notice and this notice are preserved. This file is offered as-is,
+without warranty of any kind.
+
+Basic Installation
+==================
+
+ Briefly, the shell commands `./configure; make; make install' should
+configure, build, and install this package. The following
+more-detailed instructions are generic; see the `README' file for
+instructions specific to this package. Some packages provide this
+`INSTALL' file but do not implement all of the features documented
+below. The lack of an optional feature in a given package is not
+necessarily a bug. More recommendations for GNU packages can be found
+in *note Makefile Conventions: (standards)Makefile Conventions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, and a
+file `config.log' containing compiler output (useful mainly for
+debugging `configure').
+
+ It can also use an optional file (typically called `config.cache'
+and enabled with `--cache-file=config.cache' or simply `-C') that saves
+the results of its tests to speed up reconfiguring. Caching is
+disabled by default to prevent problems with accidental use of stale
+cache files.
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If you are using the cache, and at
+some point `config.cache' contains results you don't want to keep, you
+may remove or edit it.
+
+ The file `configure.ac' (or `configure.in') is used to create
+`configure' by a program called `autoconf'. You need `configure.ac' if
+you want to change it or regenerate `configure' using a newer version
+of `autoconf'.
+
+ The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system.
+
+ Running `configure' might take a while. While running, it prints
+ some messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package, generally using the just-built uninstalled binaries.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation. When installing into a prefix owned by root, it is
+ recommended that the package be configured and built as a regular
+ user, and only the `make install' phase executed with root
+ privileges.
+
+ 5. Optionally, type `make installcheck' to repeat any self-tests, but
+ this time using the binaries in their final installed location.
+ This target does not install anything. Running this target as a
+ regular user, particularly if the prior `make install' required
+ root privileges, verifies that the installation completed
+ correctly.
+
+ 6. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+ 7. Often, you can also type `make uninstall' to remove the installed
+ files again. In practice, not all packages have tested that
+ uninstallation works correctly, even though it is required by the
+ GNU Coding Standards.
+
+ 8. Some packages, particularly those that use Automake, provide `make
+ distcheck', which can by used by developers to test that all other
+ targets like `make install' and `make uninstall' work correctly.
+ This target is generally not run by end users.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. Run `./configure --help'
+for details on some of the pertinent environment variables.
+
+ You can give `configure' initial values for configuration parameters
+by setting variables in the command line or in the environment. Here
+is an example:
+
+ ./configure CC=c99 CFLAGS=-g LIBS=-lposix
+
+ *Note Defining Variables::, for more details.
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you can use GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'. This
+is known as a "VPATH" build.
+
+ With a non-GNU `make', it is safer to compile the package for one
+architecture at a time in the source code directory. After you have
+installed the package for one architecture, use `make distclean' before
+reconfiguring for another architecture.
+
+ On MacOS X 10.5 and later systems, you can create libraries and
+executables that work on multiple system types--known as "fat" or
+"universal" binaries--by specifying multiple `-arch' options to the
+compiler but only a single `-arch' option to the preprocessor. Like
+this:
+
+ ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \
+ CPP="gcc -E" CXXCPP="g++ -E"
+
+ This is not guaranteed to produce working output in all cases, you
+may have to build one architecture at a time and combine the results
+using the `lipo' tool if you have problems.
+
+Installation Names
+==================
+
+ By default, `make install' installs the package's commands under
+`/usr/local/bin', include files under `/usr/local/include', etc. You
+can specify an installation prefix other than `/usr/local' by giving
+`configure' the option `--prefix=PREFIX', where PREFIX must be an
+absolute file name.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+pass the option `--exec-prefix=PREFIX' to `configure', the package uses
+PREFIX as the prefix for installing programs and libraries.
+Documentation and other data files still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=DIR' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them. In general, the
+default for these options is expressed in terms of `${prefix}', so that
+specifying just `--prefix' will affect all of the other directory
+specifications that were not explicitly provided.
+
+ The most portable way to affect installation locations is to pass the
+correct locations to `configure'; however, many packages provide one or
+both of the following shortcuts of passing variable assignments to the
+`make install' command line to change installation locations without
+having to reconfigure or recompile.
+
+ The first method involves providing an override variable for each
+affected directory. For example, `make install
+prefix=/alternate/directory' will choose an alternate location for all
+directory configuration variables that were expressed in terms of
+`${prefix}'. Any directories that were specified during `configure',
+but not in terms of `${prefix}', must each be overridden at install
+time for the entire installation to be relocated. The approach of
+makefile variable overrides for each directory variable is required by
+the GNU Coding Standards, and ideally causes no recompilation.
+However, some platforms have known limitations with the semantics of
+shared libraries that end up requiring recompilation when using this
+method, particularly noticeable in packages that use GNU Libtool.
+
+ The second method involves providing the `DESTDIR' variable. For
+example, `make install DESTDIR=/alternate/directory' will prepend
+`/alternate/directory' before all installation names. The approach of
+`DESTDIR' overrides is not required by the GNU Coding Standards, and
+does not work on platforms that have drive letters. On the other hand,
+it does better at avoiding recompilation issues, and works well even
+when some directory options were not specified in terms of `${prefix}'
+at `configure' time.
+
+Optional Features
+=================
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+ Some packages offer the ability to configure how verbose the
+execution of `make' will be. For these packages, running `./configure
+--enable-silent-rules' sets the default to minimal output, which can be
+overridden with `make V=1'; while running `./configure
+--disable-silent-rules' sets the default to verbose, which can be
+overridden with `make V=0'.
+
+Particular systems
+==================
+
+ On HP-UX, the default C compiler is not ANSI C compatible. If GNU
+CC is not installed, it is recommended to use the following options in
+order to use an ANSI C compiler:
+
+ ./configure CC="cc -Ae -D_XOPEN_SOURCE=500"
+
+and if that doesn't work, install pre-built binaries of GCC for HP-UX.
+
+ On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot
+parse its `<wchar.h>' header file. The option `-nodtk' can be used as
+a workaround. If GNU CC is not installed, it is therefore recommended
+to try
+
+ ./configure CC="cc"
+
+and if that doesn't work, try
+
+ ./configure CC="cc -nodtk"
+
+ On Solaris, don't put `/usr/ucb' early in your `PATH'. This
+directory contains several dysfunctional programs; working variants of
+these programs are available in `/usr/bin'. So, if you need `/usr/ucb'
+in your `PATH', put it _after_ `/usr/bin'.
+
+ On Haiku, software installed for all users goes in `/boot/common',
+not `/usr/local'. It is recommended to use the following options:
+
+ ./configure --prefix=/boot/common
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' cannot figure out
+automatically, but needs to determine by the type of machine the package
+will run on. Usually, assuming the package is built to be run on the
+_same_ architectures, `configure' can figure that out, but if it prints
+a message saying it cannot guess the machine type, give it the
+`--build=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name which has the form:
+
+ CPU-COMPANY-SYSTEM
+
+where SYSTEM can have one of these forms:
+
+ OS
+ KERNEL-OS
+
+ See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the machine type.
+
+ If you are _building_ compiler tools for cross-compiling, you should
+use the option `--target=TYPE' to select the type of system they will
+produce code for.
+
+ If you want to _use_ a cross compiler, that generates code for a
+platform different from the build platform, you should specify the
+"host" platform (i.e., that on which the generated programs will
+eventually be run) with `--host=TYPE'.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Defining Variables
+==================
+
+ Variables not defined in a site shell script can be set in the
+environment passed to `configure'. However, some packages may run
+configure again during the build, and the customized values of these
+variables may be lost. In order to avoid this problem, you should set
+them in the `configure' command line, using `VAR=value'. For example:
+
+ ./configure CC=/usr/local2/bin/gcc
+
+causes the specified `gcc' to be used as the C compiler (unless it is
+overridden in the site shell script).
+
+Unfortunately, this technique does not work for `CONFIG_SHELL' due to
+an Autoconf bug. Until the bug is fixed you can use this workaround:
+
+ CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash
+
+`configure' Invocation
+======================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--help'
+`-h'
+ Print a summary of all of the options to `configure', and exit.
+
+`--help=short'
+`--help=recursive'
+ Print a summary of the options unique to this package's
+ `configure', and exit. The `short' variant lists options used
+ only in the top level, while the `recursive' variant lists options
+ also present in any nested packages.
+
+`--version'
+`-V'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--cache-file=FILE'
+ Enable the cache: use and save the results of the tests in FILE,
+ traditionally `config.cache'. FILE defaults to `/dev/null' to
+ disable caching.
+
+`--config-cache'
+`-C'
+ Alias for `--cache-file=config.cache'.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--prefix=DIR'
+ Use DIR as the installation prefix. *note Installation Names::
+ for more details, including other options available for fine-tuning
+ the installation locations.
+
+`--no-create'
+`-n'
+ Run the configure checks, but stop before creating any output
+ files.
+
+`configure' also accepts some other, not widely useful, options. Run
+`configure --help' for more details.
+
--- /dev/null
+libplpha is copyrighted software by Mika Laitio <lamikr@pilppa.org>.
+You can redistribute it and/or modify it under either the terms of the LGPL version 3
+(see COPYING.txt file), or by obtaining the license from the author.
+
--- /dev/null
+SUBDIRS = \
+ src \
+ src_test \
+ data/configs
+pkgconfigdir = $(libdir)/pkgconfig
+EXTRA_DIST = libplpha.pc.in
+pkgconfig_DATA = libplpha.pc
+DISTCLEANFILES = \
+ aclocal.m4 \
+ config.h \
+ config.h.in \
+ config.log \
+ config.status \
+ config.cache \
+ config.guess \
+ config.sub \
+ configure \
+ depcomp \
+ install-sh \
+ libtool \
+ ltmain.sh \
+ Makefile.in \
+ Makefile \
+ missing \
+ stamp-h \
+ stamp-h1 \
+ autom4te.cache \
+ $(pkgconfig_DATA)
\ No newline at end of file
--- /dev/null
+Description
+-----------
+This library provides a mechanism to read service files and launch and monitor them.
+
+Dependencies to other libraries
+-------------------------------
+- libuci for reading configuration files
+
+Build, install and clean
+------------------------
+- build with command: ./autobuild.sh (generates required autoconf files)
+- install with command: make install
+- clean source code from generated build files: make distclean
+
+Examples
+--------
+See the src_test/test_ha
+"test_ha" is a example application which launches the processes defined in the
+.service files available in the directory "src_test/etc/plp/ha"
+(Note that these files needs to be copied to /etc/plp/ha directory and you must fix from them the ExecStart to executables)
+
+TODO
+----
+- inotify integration
+- process polling
+
+License
+-------
+GNU LESSER GENERAL PUBLIC LICENSE (lgpl) version 3, for details see the COPYING file.
--- /dev/null
+#!/bin/sh
+
+if ! [ -e Makefile ] ;
+then
+ echo "No Makefile available, generating it."
+ libtoolize --automake --force --copy
+ autoreconf --force --install
+ PKG_CONFIG_PATH=/usr/local/lib/pkgconfig ./configure --prefix=/usr/local
+else
+ echo "Makefile found, no need to generate it."
+fi
+make
--- /dev/null
+AC_INIT(src/launcher.c)
+AM_CONFIG_HEADER(config.h)
+AC_CONFIG_MACRO_DIR([m4])
+
+PACKAGE=libplpha
+VERSION=1.0.0
+
+CFLAGS="$CFLAGS -g -Wall -Werror"
+LDFLAGS="$LDFLAGS -lpthread"
+AC_SUBST(CFLAGS)
+AC_SUBST(LDFLAGS)
+AC_MSG_NOTICE([libplpha Makefile])
+
+AM_INIT_AUTOMAKE($PACKAGE, $VERSION)
+
+#AC_PROG_CXX
+AC_STDC_HEADERS
+AC_PROG_LIBTOOL
+AC_PROG_INSTALL
+#AM_PROG_CC_C_O
+
+PKG_PROG_PKG_CONFIG()
+
+PKG_CHECK_MODULES(SRC, libuci)
+AC_SUBST(SRC_CFLAGS)
+AC_SUBST(SRC_LIBS)
+
+AC_OUTPUT([
+libplpha.pc
+Makefile
+src/Makefile
+src_test/Makefile
+data/configs/Makefile
+data/configs/test_client.service
+data/configs/test_client2.service
+])
--- /dev/null
+configdir = $(sysconfdir)/plp/ha
+config_in_files = test_client.service.in test_client2.service.in
+config_DATA = $(config_in_files:.service.in=.service)
+EXTRA_DIST = $(config_in_files)
+DISTCLEANFILES = $(config_DATA) Makefile.in
+
--- /dev/null
+config 'test_client' 'service'
+ option 'ExecStart' '@prefix@/bin/test_client'
--- /dev/null
+config 'hello' 'service'
+ option 'ExecStart' '@prefix@/bin/test_client2'
+
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libplpha
+Description: pilppa communication bus library
+Version: @VERSION@
+Requires: libuci
+Cflags: -I${includedir} -I${includedir}/libplpha
+Libs: -L${libdir}
--- /dev/null
+lib_LTLIBRARIES = libplpha.la
+libplpha_la_SOURCES = \
+ launcher.c launcher.h \
+ process_listener.c process_listener.h \
+ process_parser.c process_parser.h \
+ servicedir_listener.c servicedir_listener.h \
+ process_info.h
+libplpha_la_LDFLAGS = $(SRC_LIBS) $(all_libraries) -version-info 1:0:0 -no-undefined
+AM_CPPFLAGS = $(SRC_CFLAGS)
+DISTCLEANFILES = Makefile.in
--- /dev/null
+/*
+ * common.h
+ *
+ * Created on: Sep 19, 2010
+ * Author: lamikr
+ */
+
+#ifndef COMMON_H_
+#define COMMON_H_
+
+#define CONST_SERVICE_DIRECTORY_LOCATION "/etc/plp/ha"
+#define CONST_MAX_INOTIFY_EVENT_COUNT_READ 16
+#define CONST_MAX_EXPECTED_INOTIFY_EVENT_SIZE 1024
+
+#endif /* COMMON_H_ */
--- /dev/null
+/*
+ * launcher.c
+ *
+ * Created on: Sep 14, 2010
+ * Author: lamikr
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int launch_new_process(char *param_arr[]) {
+ int ret_val;
+ int child_pid;
+
+ child_pid = fork();
+ if (child_pid == -1) {
+ // failed to fork a new process
+ ret_val = -1;
+ }
+ else if (child_pid == 0) {
+ // code for launched child process
+ //execvp(param_arr[0], param_arr);
+ // first parameter must contain a full path to executable
+ execv(param_arr[0], param_arr);
+ printf("Failed to execute\n");
+ exit(-1);
+ }
+ else {
+ // code for parent process which launched the child
+ ret_val = child_pid;
+ }
+ return ret_val;
+}
--- /dev/null
+/*
+ * launcher.h
+ *
+ * Created on: Sep 14, 2010
+ * Author: lamikr
+ */
+
+#ifndef LAUNCHER_H_
+#define LAUNCHER_H_
+
+void launch_new_process(char *param_arr[]);
+
+#endif /* LAUNCHER_H_ */
--- /dev/null
+/*
+ * process_info.h
+ *
+ * Created on: Sep 17, 2010
+ * Author: lamikr
+ */
+
+#ifndef PROCESS_INFO_H_
+#define PROCESS_INFO_H_
+
+typedef struct t_process_arg_list {
+ int count;
+ char **arg_arr;
+} t_process_arg_list;
+
+typedef struct t_process_info {
+ int p_id;
+ t_process_arg_list *arg_list;
+ struct t_process_info *next;
+} t_process_info;
+
+typedef struct t_process_info_list {
+ int count;
+ t_process_info *first_item;
+ t_process_info *last_item;
+} t_process_info_list;
+
+#endif /* PROCESS_INFO_H_ */
--- /dev/null
+/*
+ * process_listener.c
+ *
+ * Created on: Sep 18, 2010
+ * Author: lamikr
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include <stdbool.h>
+
+#include "process_listener.h"
+
+static pthread_t _listener_thread;
+static bool _continue;
+
+static void *process_listener_thread(void *thread_args_pointer)
+{
+ int status;
+ int closed_pid;
+
+ while(_continue) {
+ closed_pid = wait(&status);
+ if (closed_pid >= 0) {
+ printf("process closed: %d, status: %d\n", closed_pid, status);
+ }
+ }
+ pthread_exit(NULL);
+}
+
+void start_process_listener() {
+ printf("listen_closed_processes()\n");
+
+ _listener_thread = 0;
+ _continue = true;
+ pthread_create(&_listener_thread,
+ NULL,
+ process_listener_thread,
+ (void *)NULL);
+}
+
+void stop_process_listener() {
+ _continue = false;
+// pthread_cancel(_listener_thread);
+// pthread_join(_listener_thread, NULL);
+}
--- /dev/null
+/*
+ * process_listener.h
+ *
+ * Created on: Sep 18, 2010
+ * Author: lamikr
+ */
+
+#ifndef PROCESS_LISTENER_H_
+#define PROCESS_LISTENER_H_
+
+/**
+ * Listens when the launched processes will close.
+ */
+void start_process_listener();
+void stop_process_listener();
+
+#endif /* PROCESS_LISTENER_H_ */
--- /dev/null
+/*
+ * process_parser.c
+ *
+ * Created on: Sep 16, 2010
+ * Author: lamikr
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <uci.h>
+
+#include "common.h"
+#include "process_parser.h"
+
+t_process_arg_list *parse_command_line_args(char *cmd_line_param) {
+ char *line_pointer;
+ char *start;
+ int len;
+ t_process_arg_list *ret_val;
+
+ ret_val = NULL;
+ if (cmd_line_param != NULL) {
+ ret_val = calloc(1, sizeof(t_process_arg_list));
+ line_pointer = cmd_line_param;
+ while(*line_pointer != '\0') {
+ while((*line_pointer == ' ') ||
+ (*line_pointer == '\t')) {
+ line_pointer++;
+ }
+ if (*line_pointer != '\0') {
+ if (ret_val->arg_arr == NULL) {
+ ret_val->arg_arr = calloc(1, sizeof(char *));
+ }
+ else {
+ char **arg_arr;
+
+ arg_arr = ret_val->arg_arr;
+ arg_arr = realloc(arg_arr, (ret_val->count + 1) * sizeof(char *));
+ ret_val->arg_arr = arg_arr;
+ }
+ start = line_pointer;
+ len = 1;
+ while((*++line_pointer != '\0') &&
+ (*line_pointer != ' ') &&
+ (*line_pointer != '\t')) {
+ len++;
+ }
+ ret_val->arg_arr[ret_val->count] = strndup(start, len);
+ printf("ret_val[%d] = %s\n", ret_val->count, ret_val->arg_arr[ret_val->count]);
+ ret_val->count = ret_val->count + 1;
+ }
+ else {
+ break;
+ }
+ }
+ // terminate list with null
+ ret_val->arg_arr = realloc(ret_val->arg_arr, (ret_val->count + 1) * sizeof(char *));
+ ret_val->arg_arr[ret_val->count] = NULL;
+ ret_val->count = ret_val->count + 1;
+ }
+ return ret_val;
+}
+
+t_process_info *parse_process_info(struct uci_option *option_param) {
+ t_process_info *ret_val;
+
+ ret_val = NULL;
+ if (option_param->type == UCI_TYPE_STRING) {
+ ret_val = calloc(1, sizeof(t_process_info));
+ ret_val->arg_list = parse_command_line_args(option_param->v.string);
+ }
+ return ret_val;
+}
+
+int add_process_config(t_process_info_list *list_param, struct uci_option *option_param) {
+ int ret_val;
+ t_process_info *new_item;
+
+ ret_val = -1;
+ new_item = parse_process_info(option_param);
+ if (new_item != NULL) {
+ if (list_param->last_item != NULL) {
+ list_param->last_item->next = new_item;
+ list_param->last_item = new_item;
+ }
+ else {
+ list_param->first_item = new_item;
+ list_param->last_item = new_item;
+ }
+ list_param->count = list_param->count + 1;
+ ret_val = 0;
+ }
+ return ret_val;
+}
+
+t_process_info_list *get_process_config_list() {
+ char **config_list;
+ char **config_file;
+ int err_flg;
+ struct uci_context *ctx;
+ struct uci_package *pkg;
+ struct uci_section *section;
+ struct uci_option *option;
+ t_process_info_list *ret_val;
+
+ ret_val = calloc(1, sizeof(t_process_info_list));
+ ctx = uci_alloc_context();
+ if (ctx != NULL) {
+ uci_set_confdir(ctx, CONST_SERVICE_DIRECTORY_LOCATION);
+ config_list = NULL;
+ err_flg = uci_list_configs(ctx, &config_list);
+ if ((err_flg == UCI_OK) &&
+ (config_list != NULL)) {
+ for (config_file = config_list; *config_file != NULL; config_file++) {
+ err_flg = uci_load(ctx, *config_file, &pkg);
+ if (err_flg == UCI_OK) {
+ section = uci_lookup_section(ctx, pkg, "service");
+ if (section != NULL) {
+ option = uci_lookup_option(ctx, section, "ExecStart");
+ switch (option->type) {
+ case UCI_TYPE_STRING:
+ printf("config file: %s name: %s, value: %s\n", *config_file, option->e.name, option->v.string);
+ add_process_config(ret_val, option);
+ break;
+ default:
+ break;
+ }
+ }
+ //int num_sections = _uci_show_package(*config_file, result);
+ //printf("Queried package: %s -> %d\n", *config_file, num_sections);
+ }
+ uci_unload(ctx, pkg);
+ }
+ // free config_files
+/*
+ for (config_file = config_list; *config_file != NULL; config_file++) {
+ free(config_file);
+ }
+*/
+ free(config_list);
+ }
+ else {
+ printf("Failed to read service configurations from directory: %s\n", CONST_SERVICE_DIRECTORY_LOCATION);
+ }
+ uci_free_context(ctx);
+ }
+ else {
+ printf("Failed to read service configurations from directory: %s\n Memory allocation error.", CONST_SERVICE_DIRECTORY_LOCATION);
+ }
+ return ret_val;
+}
+
+void release_process_config_arg_list(t_process_arg_list *arg_list_param) {
+ int ii;
+
+ for (ii = 0; ii < arg_list_param->count; ii++) {
+ if (arg_list_param->arg_arr[ii] != NULL) {
+ free(arg_list_param->arg_arr[ii]);
+ arg_list_param->arg_arr[ii] = NULL;
+ }
+ }
+ free(arg_list_param->arg_arr);
+ arg_list_param->count = 0;
+ free(arg_list_param);
+}
+
+void release_process_config_list(t_process_info_list *list_param) {
+ t_process_info *item;
+ t_process_info *next;
+
+ if (list_param != NULL) {
+ item = list_param->first_item;
+ while (item != NULL) {
+ next = item->next;
+ item->next = NULL;
+ release_process_config_arg_list(item->arg_list);
+ item->arg_list = NULL;
+ free(item);
+ item = next;
+ }
+ list_param->first_item = NULL;
+ list_param->last_item = NULL;
+ free(list_param);
+ }
+}
--- /dev/null
+/*
+ * process_parser.h
+ *
+ * Created on: Sep 16, 2010
+ * Author: lamikr
+ */
+
+#ifndef INIT_PARSER_H_
+#define INIT_PARSER_H_
+
+#include "process_info.h"
+
+t_process_info_list *get_process_config_list();
+void release_process_config_list(t_process_info_list *list_param);
+void release_process_config_arg_list(t_process_arg_list *arg_list_param);
+
+#endif /* INIT_PARSER_H_ */
--- /dev/null
+/*
+ * servicedir_listener.c
+ *
+ * Created on: Sep 25, 2010
+ * Author: lamikr
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/inotify.h>
+#include <stdbool.h>
+#include <pthread.h>
+#include <fcntl.h>
+
+#include "common.h"
+#include "servicedir_listener.h"
+
+static pthread_t _listener_thread;
+static bool _listener_stop_requested;
+static bool _listener_running = false;
+static int _dir_handle = -1;
+static int _inotify_handle = -1;
+static pthread_mutex_t _listener_mutex;
+
+static void init_servicedir_listener() {
+ //_listener_mutex = PTHREAD_MUTEX_INITIALIZER;
+ pthread_mutex_init(&_listener_mutex, NULL);
+}
+
+static void deinit_servicedir_listener() {
+ pthread_mutex_destroy(&_listener_mutex);
+}
+
+static void *servicedir_listener_thread(void *thread_args_pointer)
+{
+ int b_count;
+ int ii;
+ char *buffer;
+ struct inotify_event *event;
+ int buffer_max_size;
+
+ /*
+ * Size of each i-notify event read: size of event structure + filename length that caused the event. (name follows the struct).
+ * We create a buffer that could in theory handle 16 events for files which name would be in maximum 1024 chars. (=CONST_MAX_EXPECTED_INOTIFY_EVENT_SIZE)
+ */
+ buffer_max_size = CONST_MAX_INOTIFY_EVENT_COUNT_READ * (sizeof(struct inotify_event) + CONST_MAX_EXPECTED_INOTIFY_EVENT_SIZE);
+ buffer = calloc(1, buffer_max_size);
+ if (buffer != NULL) {
+ _inotify_handle = inotify_init();
+ if (_inotify_handle >= 0) {
+ _dir_handle = inotify_add_watch(_inotify_handle,
+ CONST_SERVICE_DIRECTORY_LOCATION,
+ IN_CREATE | IN_ATTRIB | IN_MODIFY | IN_DELETE);
+ if (_dir_handle >= 0) {
+ printf("Waiting service directory file events\n");
+ while (_listener_stop_requested == false) {
+ ii = 0;
+ printf("Waiting service directory file event\n");
+ b_count = read(_inotify_handle,
+ buffer,
+ buffer_max_size);
+ printf("Service directory file event received\n");
+ if (b_count >= 0) {
+ while (ii < b_count) {
+ event = (struct inotify_event *)&buffer[ii];
+ printf("event length = %d\n", event->len);
+ if (event->len) {
+ if (event->mask & IN_CREATE) {
+ if ((event->mask & IN_ISDIR) == 0) {
+ printf("file create event: %s\n", event->name);
+ }
+ else {
+ printf("sub-directory create event: %s, no need to process\n", event->name);
+ }
+ }
+ else if (event->mask & IN_ATTRIB) {
+ if ((event->mask & IN_ISDIR) == 0) {
+ printf("file attribute change event: %s\n", event->name);
+ }
+ else {
+ printf("sub-directory attribute change event: %s, no need to process\n", event->name);
+ }
+ }
+ else if (event->mask & IN_MODIFY) {
+ if ((event->mask & IN_ISDIR) == 0) {
+ printf("file modify event: %s\n", event->name);
+ }
+ else {
+ printf("sub-directory modify event: %s, no need to process\n", event->name);
+ }
+ }
+ else if (event->mask & IN_DELETE) {
+ if ((event->mask & IN_ISDIR) == 0) {
+ printf("file delete event: %s\n", event->name);
+ }
+ else {
+ printf("sub-directory delete event: %s, no need to process\n", event->name);
+ }
+ }
+ }
+ ii = ii + sizeof(struct inotify_event) + event->len;
+ }
+ }
+ else {
+ printf("Failed to initialize service directory listener: %s, event read failed.\n", CONST_SERVICE_DIRECTORY_LOCATION);
+ }
+ }
+ printf("Closing service directory listener: %s, close request received.\n", CONST_SERVICE_DIRECTORY_LOCATION);
+ pthread_mutex_lock(&_listener_mutex);
+ if ((_inotify_handle > 0) && (_dir_handle)) {
+ inotify_rm_watch(_inotify_handle, _dir_handle);
+ _dir_handle = -1;
+ }
+ pthread_mutex_unlock(&_listener_mutex);
+ }
+ else {
+ printf("Failed to initialize service directory listener: %s, event listener start-up error.\n", CONST_SERVICE_DIRECTORY_LOCATION);
+ }
+ pthread_mutex_lock(&_listener_mutex);
+ if (_inotify_handle > 0) {
+ close(_inotify_handle);
+ _inotify_handle = -1;
+ }
+ pthread_mutex_unlock(&_listener_mutex);
+ }
+ else {
+ printf("Failed to initialize service directory listener: %s\n", CONST_SERVICE_DIRECTORY_LOCATION);
+ }
+ if (buffer != NULL) {
+ free(buffer);
+ buffer = NULL;
+ }
+ }
+ else {
+ printf("Failed to initialize service directory listener: %s, buffer allocation error.\n", CONST_SERVICE_DIRECTORY_LOCATION);
+ }
+ _listener_running = false;
+ pthread_exit(NULL);
+}
+
+void start_servicedir_listener() {
+ printf("listen_closed_processes()\n");
+ init_servicedir_listener();
+ if (_listener_running == false) {
+ _listener_thread = 0;
+ _listener_stop_requested = false;
+ _listener_running = true;
+ pthread_create(&_listener_thread,
+ NULL,
+ servicedir_listener_thread,
+ (void *)NULL);
+ }
+}
+
+void stop_servicedir_listener() {
+ _listener_stop_requested = true;
+ pthread_mutex_lock(&_listener_mutex);
+ if ((_inotify_handle > 0) && (_dir_handle)) {
+ inotify_rm_watch(_inotify_handle, _dir_handle);
+ close(_inotify_handle);
+ _dir_handle = -1;
+ _inotify_handle = -1;
+ }
+ pthread_mutex_unlock(&_listener_mutex);
+ pthread_join(_listener_thread, NULL);
+ deinit_servicedir_listener();
+}
--- /dev/null
+/*
+ * servicedir_listener.h
+ *
+ * Created on: Sep 25, 2010
+ * Author: lamikr
+ */
+
+#ifndef SERVICEDIR_LISTENER_H_
+#define SERVICEDIR_LISTENER_H_
+
+/**
+ * Listens changes in the service configuration directory.
+ */
+void start_servicedir_listener();
+void stop_servicedir_listener();
+
+#endif /* SERVICEDIR_LISTENER_H_ */
--- /dev/null
+bin_PROGRAMS = test_ha test_client test_client2
+
+test_ha_SOURCES = test_ha.c
+test_ha_LDADD = $(SRC_LIBS) ../src/.libs/libplpha.a
+
+test_client_SOURCES = test_client.c
+test_client_LDADD = $(SRC_LIBS) ../src/.libs/libplpha.a
+
+test_client2_SOURCES = test_client.c
+test_client2_LDADD = $(SRC_LIBS) ../src/.libs/libplpha.a
+
+AM_CPPFLAGS = $(SRC_CFLAGS) -I../src
+
+DISTCLEANFILES = Makefile.in
\ No newline at end of file
--- /dev/null
+/*
+ * test_client.c
+ *
+ * Created on: Jun 9, 2010
+ * Author: lamikr
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "common.h"
+#include "process_parser.h"
+#include <string.h>
+
+int main(int argc, char** argv)
+{
+ int sleep_time = 2;
+
+ t_process_arg_list *ret_val;
+ int ii;
+
+ ret_val = calloc(1, sizeof(t_process_arg_list));
+ for (ii = 0; ii < 1; ii++) {
+ if (ret_val->arg_arr == NULL) {
+ ret_val->arg_arr = calloc(1, sizeof(char *));
+ }
+ else {
+ char **arg_arr;
+
+ arg_arr = ret_val->arg_arr;
+ arg_arr = realloc(arg_arr, (ret_val->count + 1) * sizeof(char *));
+ ret_val->arg_arr = arg_arr;
+ }
+ ret_val->arg_arr[ii] = strdup("hello\n");
+ ret_val->count = ret_val->count + 1;
+ }
+ if (argc > 1) {
+ sleep_time = atoi(argv[1]);
+ }
+ release_process_config_arg_list(ret_val);
+ ret_val = NULL;
+ printf("sleep-time: %d seconds\n", sleep_time);
+ sleep(sleep_time);
+ return 0;
+}
--- /dev/null
+/*
+ * test_ha.c
+ *
+ * Created on: Sep 16, 2010
+ * Author: lamikr
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "launcher.h"
+#include "process_parser.h"
+#include "process_listener.h"
+#include "servicedir_listener.h"
+
+int main(int argc, char** argv)
+{
+ t_process_info_list *process_list;
+ t_process_info *process_item;
+
+ start_process_listener();
+ start_servicedir_listener();
+ process_list = get_process_config_list();
+ if (process_list != NULL) {
+ printf("process_list->count: %d\n", process_list->count);
+ process_item = process_list->first_item;
+ if (process_item != NULL) {
+ if ((process_item->arg_list != NULL) &&
+ (process_item->arg_list->arg_arr != NULL)) {
+ launch_new_process(process_item->arg_list->arg_arr);
+ process_item = process_item->next;
+ }
+ }
+ sleep(8);
+ stop_servicedir_listener();
+ release_process_config_list(process_list);
+ }
+ //closed_pid = wait(&status);
+ //printf("closed process: %d, status: %d\n", closed_pid, status);
+ return 0;
+}