diff options
author | Robert Ginda <rginda@google.com> | 2015-08-10 15:45:03 -0700 |
---|---|---|
committer | Robert Ginda <rginda@google.com> | 2015-08-10 15:45:03 -0700 |
commit | 4340b1831d360a440ab7bf5e1aa0170398437163 (patch) | |
tree | f5a90fac0006dada785191bc4e626982b62131e7 | |
parent | d012a8bd96e5ae970e89b181ae352c909adf506a (diff) | |
parent | 8d8ad60fce9134f31b233c78bd286d3f949aa3b8 (diff) | |
download | platform_external_libdaemon-4340b1831d360a440ab7bf5e1aa0170398437163.tar.gz platform_external_libdaemon-4340b1831d360a440ab7bf5e1aa0170398437163.tar.bz2 platform_external_libdaemon-4340b1831d360a440ab7bf5e1aa0170398437163.zip |
Import libdaemon into the Android tree.
Import libdaemon (a dep of external/avahi, which is a dep of
system/peerd).
At the time of the import the libdaemon HEAD was
0630da04e575213229f695bdc3dc90aa92ca4f55
Committed on 2012-09-03.
Bug: 22921222
36 files changed, 4565 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..213e254 --- /dev/null +++ b/.gitignore @@ -0,0 +1,29 @@ +compile +*~ +*.tar.gz +config.rpath +Makefile +Makefile.in +*.lo +*.la +*.o +.deps/ +.libs/ +*.cache +stamp-* +README +aclocal.m4 +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +depcomp +install-sh +libdaemon.spec +libtool +ltmain.sh +missing +*.pc diff --git a/Android.mk b/Android.mk new file mode 100644 index 0000000..5053e7d --- /dev/null +++ b/Android.mk @@ -0,0 +1 @@ +include $(call all-subdir-makefiles) @@ -0,0 +1,19 @@ +Copyright (C) 2003-2008 Lennart Poettering + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MODULE_LICENSE_MIT b/MODULE_LICENSE_MIT new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/MODULE_LICENSE_MIT diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..ef13592 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,59 @@ +# This file is part of libdaemon. +# +# Copyright 2003-2008 Lennart Poettering +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +ACLOCAL_AMFLAGS = -I m4 + +EXTRA_DIST=bootstrap.sh LICENSE +SUBDIRS=libdaemon doc + +if EXAMPLES +SUBDIRS += examples +endif + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = pkgconfig/libdaemon.pc + +dist_noinst_DATA = +MAINTAINERCLEANFILES= + +if USE_LYNX +dist_noinst_DATA += README +MAINTAINERCLEANFILES += README + +README: + rm -f README + $(MAKE) -C doc README + ln -s doc/README README +endif + +doxygen: + $(MAKE) -C doc doxygen + +homepage: dist doxygen + test -d $$HOME/homepage/private + mkdir -p $$HOME/homepage/private/projects/libdaemon + cp libdaemon-@PACKAGE_VERSION@.tar.gz $$HOME/homepage/private/projects/libdaemon + cp doc/README.html doc/style.css $$HOME/homepage/private/projects/libdaemon + ln -sf README.html $$HOME/homepage/private/projects/libdaemon/index.html + cp -av doc/reference/ $$HOME/homepage/private/projects/libdaemon/ + +.PHONY: homepage doxygen @@ -0,0 +1,19 @@ +Copyright (C) 2003-2008 Lennart Poettering + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/bootstrap.sh b/bootstrap.sh new file mode 100755 index 0000000..381f31c --- /dev/null +++ b/bootstrap.sh @@ -0,0 +1,71 @@ +#!/bin/sh + +# This file is part of libdaemon. +# +# Copyright 2003-2008 Lennart Poettering +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +VERSION=1.9 + +run_versioned() { + local P + local V + + V=$(echo "$2" | sed -e 's,\.,,g') + + if [ -e "`which $1$V 2> /dev/null`" ] ; then + P="$1$V" + else + if [ -e "`which $1-$2 2> /dev/null`" ] ; then + P="$1-$2" + else + P="$1" + fi + fi + + shift 2 + "$P" "$@" +} + +set -ex + +if [ "x$1" = "xam" ] ; then + run_versioned automake "$VERSION" -a -c --foreign + ./config.status +else + rm -rf autom4te.cache + rm -f config.cache + + touch config.rpath + test "x$LIBTOOLIZE" = "x" && LIBTOOLIZE=libtoolize + + mkdir -p common + + "$LIBTOOLIZE" -c --force + run_versioned aclocal "$VERSION" -I m4 + run_versioned autoconf 2.59 -Wall + run_versioned autoheader 2.59 + run_versioned automake "$VERSION" -a -c --foreign + + if test "x$NOCONFIGURE" = "x"; then + CFLAGS="-g -O0" ./configure --sysconfdir=/etc --localstatedir=/var "$@" + make clean + fi +fi diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..c659e37 --- /dev/null +++ b/configure.ac @@ -0,0 +1,94 @@ +# -*- Autoconf -*- +# Process this file with autoconf to produce a configure script. + +# This file is part of libdaemon. +# +# Copyright 2003-2008 Lennart Poettering +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +AC_PREREQ(2.63) + +AC_INIT([libdaemon],[0.14],[mzqnrzba (at) 0pointer (dot) de]) +AC_CONFIG_SRCDIR([libdaemon/dfork.c]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIR([m4]) + +AM_INIT_AUTOMAKE([foreign 1.10 -Wall]) + +AC_SUBST(PACKAGE_URL, [http://0pointer.de/lennart/projects/libdaemon/]) + +AC_SUBST(LIBDAEMON_VERSION_INFO, [5:0:5]) + +if type -p stow > /dev/null && test -d /usr/local/stow ; then + AC_MSG_NOTICE([*** Found /usr/local/stow: default install prefix set to /usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION} ***]) + ac_default_prefix="/usr/local/stow/${PACKAGE_NAME}-${PACKAGE_VERSION}" +fi + +m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_CC_C99 dnl This enable gnu99 if present +AM_PROG_CC_C_O + +AC_USE_SYSTEM_EXTENSIONS + +AC_PROG_INSTALL +AC_PROG_LN_S +AC_PROG_MAKE_SET +AC_PROG_LIBTOOL + +CC_CHECK_CFLAGS_APPEND([-pipe -Wall -W -Wextra -pedantic -Wformat -Wold-style-definition -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline -Wno-unused-parameter -Wstrict-aliasing]) + +# Checks for header files. +AC_HEADER_ASSERT +AC_HEADER_STDC +AC_CHECK_HEADERS([fcntl.h limits.h stdlib.h string.h syslog.h unistd.h sys/ioctl.h sys/time.h]) +AC_HEADER_SYS_WAIT + +# Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_PID_T +AC_HEADER_TIME +AC_C_VOLATILE + +# Checks for library functions. +AC_FUNC_FORK +AC_FUNC_SELECT_ARGTYPES +AC_FUNC_VPRINTF +AC_CHECK_FUNCS([select strerror dup2 memset strrchr asprintf]) +AC_TYPE_MODE_T +AC_FUNC_SETPGRP +AC_TYPE_SIGNAL +AC_TYPE_SIZE_T + +AC_SYS_LARGEFILE + +CC_NOUNDEFINED + +ZP_LYNX_DOC + +AC_ARG_ENABLE(examples, + AS_HELP_STRING([--disable-examples], [Don't build examples during make]),, + enable_examples="yes") +AM_CONDITIONAL(EXAMPLES, [test "$enable_examples" = "yes"]) + +AC_CONFIG_FILES([libdaemon/Makefile Makefile doc/Makefile doc/README.html doc/doxygen.conf examples/Makefile pkgconfig/libdaemon.pc pkgconfig/libdaemon-uninstalled.pc]) +AC_OUTPUT diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 0000000..54af4f6 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,5 @@ +reference +README +README.html +doxygen.conf + diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..140ad1a --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,47 @@ +# This file is part of libdaemon. +# +# Copyright 2003-2008 Lennart Poettering +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +dist_html_DATA = README.html style.css +EXTRA_DIST = README.html.in + +MAINTAINERCLEANFILES = README.html +CLEANFILES = + +doxygen: doxygen.conf + doxygen doxygen.conf + +maintainer-clean-local: + rm -rf reference + +if USE_LYNX +dist_doc_DATA = README +MAINTAINERCLEANFILES += README +README: README.html + lynx --dump $^ | sed 's,file://localhost/.*/doc/README.html,README,' | sed 's,file://localhost/.*/doc/reference/,reference/,' > $@ + +CLEANFILES += README +endif + +tidy: README.html + tidy -e < README.html + +.PHONY: doxygen tidy diff --git a/doc/README.html.in b/doc/README.html.in new file mode 100644 index 0000000..2c2cccd --- /dev/null +++ b/doc/README.html.in @@ -0,0 +1,177 @@ +<?xml version="1.0" encoding="iso-8859-15"?> <!-- -*-html-helper-*- --> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + +<head> +<title>libdaemon @PACKAGE_VERSION@</title> +<link rel="stylesheet" type="text/css" href="style.css" /> +</head> + +<body> +<h1><a name="top">libdaemon @PACKAGE_VERSION@</a></h1> + +<p><i>Copyright 2003-2009 Lennart Poettering <@PACKAGE_BUGREPORT@></i></p> + +<ul class="toc"> + <li><a href="#license">License</a></li> + <li><a href="#news">News</a></li> + <li><a href="#overview">Overview</a></li> + <li><a href="#status">Current Status</a></li> + <li><a href="#documentation">Documentation</a></li> + <li><a href="#requirements">Requirements</a></li> + <li><a href="#installation">Installation</a></li> + <li><a href="#acks">Acknowledgements</a></li> + <li><a href="#download">Download</a></li> +</ul> + +<h2><a name="license">License</a></h2> + +<p>Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions:</p> + +<p>The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.</p> + +<p>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.</p> + +<h2><a name="news">News</a></h2> + +<div class="news-date">Sun Aug 29 2012: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.14.tar.gz">Version 0.15</a> license change from LGPL to MIT</p> + +<div class="news-date">Sun Oct 18 2009: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.14.tar.gz">Version 0.14</a> released; changes include: add <tt>daemon_set_verbosity()</tt> call; numerous updates</p> + +<div class="news-date">Tue Jul 29 2008: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.13.tar.gz">Version 0.13</a> released; changes include: add <tt>daemon_reset_sigs()</tt> and <tt>daemon_unblock_sigs()</tt> calls for resetting signal handlers to sensible states; improve error handling.</p> + +<div class="news-date">Tue Jul 10 2007: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.12.tar.gz">Version 0.12</a> released; changes include: make <tt>daemon_close_all()</tt> actually work properly.</p> + +<div class="news-date">Fri Jun 22 2007: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.11.tar.gz">Version 0.11</a> released; changes include: automatically detect whether lynx is installed; properly set <tt>errno</tt> on every error condition; add new function <tt>daemon_close_all()</tt> to close all open file descriptors except a given set; add <tt>daemon_logv()</tt>, which is identical to <tt>daemon_log()</tt>, but takes a <tt>va_list</tt> argument; add <tt>daemon_execv()</tt> in similar style; other fixes</p> + +<div class="news-date">Thu Nov 24 2005: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.10.tar.gz">Version 0.10</a> released; changes include: make logging compatible with daemons running in a <tt>chroot()</tt> environment</p> + +<div class="news-date">Fri Nov 18 2005: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.9.tar.gz">Version 0.9</a> released; changes include: portability (FreeBSD, NetBSD, OpenBSD, Darwin, Solaris, Cygwin); some minor header file cleanups; fix access mode of PID files; other cleanups; license change from GPL to LGPL</p> + +<div class="news-date">Sat Jun 4 2005: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.8.tar.gz">Version 0.8</a> released; changes include: proper PID file locking</p> + +<div class="news-date">Sat Dec 18 2004: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.7.tar.gz">Version 0.7</a> released; changes include: minor cleanups; C++ compatibility; gcc 2.95 compatiblity</p> + +<div class="news-date">Wed Apr 7 2004: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.6.tar.gz">Version 0.6</a> released; changes include: backgrounding fixes, minor other stuff</p> + +<div class="news-date">Tue Feb 10 2004: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.5.tar.gz">Version 0.5</a> released; changes include: signal handling fix, forking fix</p> + +<div class="news-date">Sat Jan 10 2004: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.4.tar.gz">Version 0.4</a> released; changes include: new module <tt>dexec.c</tt>; added <tt>pkg-config</tt> support.</p> + +<div class="news-date">Mon Oct 20 2003: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.3.tar.gz">Version 0.3</a> released; changes include: documentation update, build fixes, RPM spec file added, added new function int <tt>daemon_pid_file_kill_wait()</tt>.</p> + +<div class="news-date">Thu July 10 2003: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.2.tar.gz">Version 0.2</a> released; changes include: ugly umask error fix, documentation update</p> + +<div class="news-date">Mon July 7 2003: </div> +<p class="news-text"><a href="@PACKAGE_URL@libdaemon-0.1.tar.gz">Version 0.1</a> released</p> + +<h2><a name="overview">Overview</a></h2> + +<p><tt>libdaemon</tt> is a lightweight C library that eases the writing of UNIX +daemons. It consists of the following parts:</p> + +<ul> + <li>A wrapper around <tt>fork()</tt> which does the correct + daemonization procedure of a process</li> + + <li>A wrapper around <tt>syslog()</tt> for simpler and compatible + log output to Syslog or STDERR</li> + + <li>An API for writing PID files</li> + + <li>An API for serializing UNIX signals into a pipe for + usage with <tt>select()</tt> or <tt>poll()</tt></li> + + <li>An API for running subprocesses with STDOUT and STDERR redirected to syslog.</li> +</ul> + +<p>APIs like these are used in most daemon software +available. It is not that simple to get it done right and code +duplication is not a goal.</p> + +<p><tt>libdaemon</tt> is currently used by <a +href="http://0pointer.de/lennart/projects/ifplugd/"><tt>ifplugd</tt></a>, +<a +href="http://freedesktop.org/Software/Avahi">Avahi</a>, +<a +href="http://0pointer.de/lennart/projects/ivam2/"><tt>ivam2</tt></a>, +<a href="http://gentoo.ovibes.net/nautilus-share/mediawiki-1.4.4/index.php/Accueil">Nautilus-Share</a> +and <a +href="http://0pointer.de/lennart/projects/aeswepd/"><tt>aeswepd</tt></a>.</p> + +<h2><a name="status">Current Status</a></h2> + +<p>Version @PACKAGE_VERSION@ is feature complete.</p> + +<h2><a name="documentation">Documentation</a></h2> + +<p>An extensive API reference is <a +href="reference/html/index.html">available</a></p> + +<h2><a name="requirements">Requirements</a></h2> + +<p><tt>libdaemon</tt> was developed and tested on Debian GNU/Linux +"testing" from July 2003, it should work on most other Linux +distributions (and some Unix versions) since it uses GNU Autoconf and +GNU libtool for source code configuration and shared library +management.</p> + +<p><tt>libdaemon</tt> is known to work on modern Linux systems, FreeBSD, NetBSD, OpenBSD, Darwin, Solaris and Windows/Cygwin.</p> + +<h2><a name="installation">Installation</a></h2> + +<p>As this package is made with the GNU autotools you should run +<tt>./configure</tt> inside the distribution directory for configuring +the source tree. After that you should run <tt>make</tt> for +compilation and <tt>make install</tt> (as root) for installation of +<tt>libdaemon</tt>.</p> + +<p>Please use <tt>gmake</tt> instead of traditional <tt>make</tt> for compilation on non-Linux systems.</p> + +<h2><a name="acks">Acknowledgements</a></h2> + +<p>Sebastien Estienne, for a lot of portability work.</p> + +<h2><a name="download">Download</a></h2> + +<p>The newest release is always available from <a href="@PACKAGE_URL@">@PACKAGE_URL@</a></p> + +<p>Get <tt>libdaemon</tt>'s development sources from the <a href="http://git.or.cz/">GIT</a> <a href="git://git.0pointer.de/libdaemon">repository</a> (<a href="http://git.0pointer.de/?p=libdaemon.git">gitweb</a>): </p> + +<pre>git clone git://git.0pointer.de/libdaemon</pre> + +<p>You may find an up to date Debian package of <tt>libdaemon</tt> on the <a href="http://packages.debian.org/libdaemon0">Debian package repository</a>.</p> + +<p>If you want to be notified whenever I release a new version of this software use the subscription feature of <a href="http://freshmeat.net/projects/libdaemon/">Freshmeat</a>.</p> + +<hr/> +<address class="grey">Lennart Poettering <@PACKAGE_BUGREPORT@>, October 2009</address> + +</body> +</html> diff --git a/doc/doxygen.conf.in b/doc/doxygen.conf.in new file mode 100644 index 0000000..cace988 --- /dev/null +++ b/doc/doxygen.conf.in @@ -0,0 +1,1161 @@ +# Doxyfile 1.3.9.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = @PACKAGE_NAME@ + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = reference + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of source +# files, where putting all generated files in the same directory would otherwise +# cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, +# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese, +# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian, +# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish, +# Swedish, and Ukrainian. + +OUTPUT_LANGUAGE = English + +# This tag can be used to specify the encoding used in the generated output. +# The encoding is not always determined by the language that is chosen, +# but also whether or not the output is meant for Windows or non-Windows users. +# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES +# forces the Windows encoding (this is the default for the Windows binary), +# whereas setting the tag to NO uses a Unix-style encoding (the default for +# all platforms other than Windows). + +USE_WINDOWS_ENCODING = NO + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is used +# as the annotated text. Otherwise, the brief description is used as-is. If left +# blank, the following values are used ("$name" is automatically replaced with the +# name of the entity): "The $name class" "The $name widget" "The $name file" +# "is" "provides" "specifies" "contains" "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited +# members of a class in the documentation of that class as if those members were +# ordinary class members. Constructors, destructors and assignment operators of +# the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like the Qt-style comments (thus requiring an +# explicit @brief command for a brief description. + +JAVADOC_AUTOBRIEF = YES + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the DETAILS_AT_TOP tag is set to YES then Doxygen +# will output the detailed description near the top, like JavaDoc. +# If set to NO, the detailed description appears after the member +# documentation. + +DETAILS_AT_TOP = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 4 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources +# only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources +# only. Doxygen will then generate output that is more tailored for Java. +# For instance, namespaces will be presented as packages, qualified scopes +# will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = YES + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = NO + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = NO + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = NO + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. + +SHOW_DIRECTORIES = NO + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = ../libdaemon/ + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp +# *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm + +FILE_PATTERNS = *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories +# that are symbolic links (a Unix filesystem feature) are excluded from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. + +EXCLUDE_PATTERNS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = ../examples/ + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = *.c + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = YES + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES (the default) +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = YES + +# If the REFERENCES_RELATION tag is set to YES (the default) +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = YES + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = NO + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be +# generated containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+, +# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are +# probably better off using the HTML help feature. + +GENERATE_TREEVIEW = YES + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = NO + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = NO + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = NO + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. This is useful +# if you want to understand what is going on. On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_PREDEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse the +# parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base or +# super classes. Setting the tag to NO turns the diagrams off. Note that this +# option is superseded by the HAVE_DOT option below. This is only a fallback. It is +# recommended to install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will +# generate a call dependency graph for every global function or class method. +# Note that enabling this option will significantly increase the time of a run. +# So in most cases it will be better to enable call graphs for selected +# functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found on the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_WIDTH = 1024 + +# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height +# (in pixels) of the graphs generated by dot. If a graph becomes larger than +# this value, doxygen will try to truncate the graph, so that it fits within +# the specified constraint. Beware that most browsers cannot cope with very +# large images. + +MAX_DOT_GRAPH_HEIGHT = 1024 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes that +# lay further from the root node will be omitted. Note that setting this option to +# 1 or 2 may greatly reduce the computation time needed for large code bases. Also +# note that a graph may be further truncated if the graph's image dimensions are +# not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH and MAX_DOT_GRAPH_HEIGHT). +# If 0 is used for the depth value (the default), the graph is not depth-constrained. + +MAX_DOT_GRAPH_DEPTH = 0 + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to the search engine +#--------------------------------------------------------------------------- + +# The SEARCHENGINE tag specifies whether or not a search engine should be +# used. If set to NO the values of all tags below this one will be ignored. + +SEARCHENGINE = NO diff --git a/doc/style.css b/doc/style.css new file mode 100644 index 0000000..15efaec --- /dev/null +++ b/doc/style.css @@ -0,0 +1,30 @@ +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +body { color: black; background-color: white; } +a:link, a:visited { color: #900000; } +div.news-date { font-size: 80%; font-style: italic; } +pre { background-color: #f0f0f0; padding: 0.4cm; } +.grey { color: #8f8f8f; font-size: 80%; } diff --git a/examples/.gitignore b/examples/.gitignore new file mode 100644 index 0000000..db50de7 --- /dev/null +++ b/examples/.gitignore @@ -0,0 +1,2 @@ +testd + diff --git a/examples/Makefile.am b/examples/Makefile.am new file mode 100644 index 0000000..930c3bf --- /dev/null +++ b/examples/Makefile.am @@ -0,0 +1,28 @@ +# This file is part of libdaemon. +# +# Copyright 2003-2008 Lennart Poettering +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +noinst_PROGRAMS = testd + +AM_CPPFLAGS=-I$(top_srcdir) + +testd_SOURCES=testd.c +testd_LDADD=../libdaemon/libdaemon.la diff --git a/examples/testd.c b/examples/testd.c new file mode 100644 index 0000000..9154f7b --- /dev/null +++ b/examples/testd.c @@ -0,0 +1,194 @@ +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#include <signal.h> +#include <errno.h> +#include <string.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/unistd.h> +#include <sys/select.h> + +#include <libdaemon/dfork.h> +#include <libdaemon/dsignal.h> +#include <libdaemon/dlog.h> +#include <libdaemon/dpid.h> +#include <libdaemon/dexec.h> + +int main(int argc, char *argv[]) { + pid_t pid; + + /* Reset signal handlers */ + if (daemon_reset_sigs(-1) < 0) { + daemon_log(LOG_ERR, "Failed to reset all signal handlers: %s", strerror(errno)); + return 1; + } + + /* Unblock signals */ + if (daemon_unblock_sigs(-1) < 0) { + daemon_log(LOG_ERR, "Failed to unblock all signals: %s", strerror(errno)); + return 1; + } + + /* Set indetification string for the daemon for both syslog and PID file */ + daemon_pid_file_ident = daemon_log_ident = daemon_ident_from_argv0(argv[0]); + + /* Check if we are called with -k parameter */ + if (argc >= 2 && !strcmp(argv[1], "-k")) { + int ret; + + /* Kill daemon with SIGTERM */ + + /* Check if the new function daemon_pid_file_kill_wait() is available, if it is, use it. */ + if ((ret = daemon_pid_file_kill_wait(SIGTERM, 5)) < 0) + daemon_log(LOG_WARNING, "Failed to kill daemon: %s", strerror(errno)); + + return ret < 0 ? 1 : 0; + } + + /* Check that the daemon is not rung twice a the same time */ + if ((pid = daemon_pid_file_is_running()) >= 0) { + daemon_log(LOG_ERR, "Daemon already running on PID file %u", pid); + return 1; + } + + /* Prepare for return value passing from the initialization procedure of the daemon process */ + if (daemon_retval_init() < 0) { + daemon_log(LOG_ERR, "Failed to create pipe."); + return 1; + } + + /* Do the fork */ + if ((pid = daemon_fork()) < 0) { + + /* Exit on error */ + daemon_retval_done(); + return 1; + + } else if (pid) { /* The parent */ + int ret; + + /* Wait for 20 seconds for the return value passed from the daemon process */ + if ((ret = daemon_retval_wait(20)) < 0) { + daemon_log(LOG_ERR, "Could not recieve return value from daemon process: %s", strerror(errno)); + return 255; + } + + daemon_log(ret != 0 ? LOG_ERR : LOG_INFO, "Daemon returned %i as return value.", ret); + return ret; + + } else { /* The daemon */ + int fd, quit = 0; + fd_set fds; + + /* Close FDs */ + if (daemon_close_all(-1) < 0) { + daemon_log(LOG_ERR, "Failed to close all file descriptors: %s", strerror(errno)); + + /* Send the error condition to the parent process */ + daemon_retval_send(1); + goto finish; + } + + /* Create the PID file */ + if (daemon_pid_file_create() < 0) { + daemon_log(LOG_ERR, "Could not create PID file (%s).", strerror(errno)); + daemon_retval_send(2); + goto finish; + } + + /* Initialize signal handling */ + if (daemon_signal_init(SIGINT, SIGTERM, SIGQUIT, SIGHUP, 0) < 0) { + daemon_log(LOG_ERR, "Could not register signal handlers (%s).", strerror(errno)); + daemon_retval_send(3); + goto finish; + } + + /*... do some further init work here */ + + + /* Send OK to parent process */ + daemon_retval_send(0); + + daemon_log(LOG_INFO, "Sucessfully started"); + + /* Prepare for select() on the signal fd */ + FD_ZERO(&fds); + fd = daemon_signal_fd(); + FD_SET(fd, &fds); + + while (!quit) { + fd_set fds2 = fds; + + /* Wait for an incoming signal */ + if (select(FD_SETSIZE, &fds2, 0, 0, 0) < 0) { + + /* If we've been interrupted by an incoming signal, continue */ + if (errno == EINTR) + continue; + + daemon_log(LOG_ERR, "select(): %s", strerror(errno)); + break; + } + + /* Check if a signal has been recieved */ + if (FD_ISSET(fd, &fds2)) { + int sig; + + /* Get signal */ + if ((sig = daemon_signal_next()) <= 0) { + daemon_log(LOG_ERR, "daemon_signal_next() failed: %s", strerror(errno)); + break; + } + + /* Dispatch signal */ + switch (sig) { + + case SIGINT: + case SIGQUIT: + case SIGTERM: + daemon_log(LOG_WARNING, "Got SIGINT, SIGQUIT or SIGTERM."); + quit = 1; + break; + + case SIGHUP: + daemon_log(LOG_INFO, "Got a HUP"); + daemon_exec("/", NULL, "/bin/ls", "ls", (char*) NULL); + break; + + } + } + } + + /* Do a cleanup */ +finish: + daemon_log(LOG_INFO, "Exiting..."); + daemon_retval_send(255); + daemon_signal_done(); + daemon_pid_file_remove(); + + return 0; + } +} diff --git a/libdaemon/Android.mk b/libdaemon/Android.mk new file mode 100644 index 0000000..565c873 --- /dev/null +++ b/libdaemon/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_SRC_FILES:= \ + dexec.c \ + dfork.c \ + dlog.c \ + dnonblock.c \ + dpid.c \ + dsignal.c + +LOCAL_C_INCLUDES+= $(LOCAL_PATH)/.. + +LOCAL_MODULE:=libdaemon + +LOCAL_EXPORT_C_INCLUDE_DIRS:= $(LOCAL_PATH)/.. + +# -std=gnu99 -DHAVE_CONFIG_H -I. -I.. -I.. -g -O2 -pipe +# -Wall -W -Wextra -pedantic -Wformat -Wold-style-definition +# -Wdeclaration-after-statement -Wfloat-equal -Wmissing-declarations +# -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls +# -Wmissing-noreturn -Wshadow -Wendif-labels -Wpointer-arith +# -Wbad-function-cast -Wcast-qual -Wcast-align -Wwrite-strings -Winline +# -Wstrict-aliasing +# -MT testd.o -MD -MP -MF .deps/testd.Tpo -c -o testd.o testd.c + +LOCAL_CFLAGS+= \ + -Wno-unused-parameter \ + -DHAVE_CONFIG_H \ + -DLOCALSTATEDIR=\"/var\" + +include $(BUILD_SHARED_LIBRARY) diff --git a/libdaemon/Makefile.am b/libdaemon/Makefile.am new file mode 100644 index 0000000..9c56611 --- /dev/null +++ b/libdaemon/Makefile.am @@ -0,0 +1,47 @@ +# This file is part of libdaemon. +# +# Copyright 2003-2008 Lennart Poettering +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +# + +AM_CPPFLAGS='-DLOCALSTATEDIR="$(localstatedir)"' + +pkginclude_HEADERS = \ + dlog.h \ + dfork.h \ + dsignal.h \ + dnonblock.h \ + dpid.h \ + dexec.h \ + daemon.h + +lib_LTLIBRARIES = libdaemon.la + +libdaemon_la_SOURCES = \ + dlog.c \ + dfork.c \ + dsignal.c \ + dnonblock.c \ + dpid.c \ + dexec.c \ + daemon.h \ + $(pkg_include_HEADERS) + +libdaemon_la_LDFLAGS = -version-info $(LIBDAEMON_VERSION_INFO) $(LDFLAGS_NOUNDEFINED) diff --git a/libdaemon/daemon.h b/libdaemon/daemon.h new file mode 100644 index 0000000..3d3573a --- /dev/null +++ b/libdaemon/daemon.h @@ -0,0 +1,41 @@ +#ifndef foodaemonhfoo +#define foodaemonhfoo + +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +/** \file + * + * A header file including all other header files part of libdaemon + */ + +#include <libdaemon/dfork.h> +#include <libdaemon/dlog.h> +#include <libdaemon/dpid.h> +#include <libdaemon/dsignal.h> +#include <libdaemon/dexec.h> +#include <libdaemon/dnonblock.h> + +#endif diff --git a/libdaemon/dexec.c b/libdaemon/dexec.c new file mode 100644 index 0000000..7a89b62 --- /dev/null +++ b/libdaemon/dexec.c @@ -0,0 +1,232 @@ +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <unistd.h> +#include <string.h> +#include <errno.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/wait.h> +#include <limits.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdarg.h> +#include <assert.h> + +#include "dlog.h" +#include "dsignal.h" +#include "dfork.h" +#include "dexec.h" + +#define MAX_ARGS 64 + +int daemon_execv(const char *dir, int *ret, const char *prog, va_list ap) { + pid_t pid; + int p[2]; + unsigned n = 0; + static char buf[256]; + int sigfd, r; + fd_set fds; + int saved_errno; + + assert(daemon_signal_fd() >= 0); + + if (pipe(p) < 0) { + daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno)); + return -1; + } + + if ((pid = fork()) < 0) { + daemon_log(LOG_ERR, "fork() failed: %s", strerror(errno)); + + saved_errno = errno; + close(p[0]); + close(p[1]); + errno = saved_errno; + + return -1; + + } else if (pid == 0) { + char *args[MAX_ARGS]; + int i; + + if (p[1] != 1) + if (dup2(p[1], 1) < 0) { + daemon_log(LOG_ERR, "dup2: %s", strerror(errno)); + goto fail; + } + + if (p[1] != 2) + if (dup2(p[1], 2) < 0) { + daemon_log(LOG_ERR, "dup2: %s", strerror(errno)); + goto fail; + } + + + if (p[0] > 2) + close(p[0]); + + if (p[1] > 2) + close(p[1]); + + close(0); + + if (open("/dev/null", O_RDONLY) != 0) { + daemon_log(LOG_ERR, "Unable to open /dev/null as STDIN"); + goto fail; + } + + daemon_close_all(-1); + daemon_reset_sigs(-1); + daemon_unblock_sigs(-1); + + umask(0022); /* Set up a sane umask */ + + if (dir && chdir(dir) < 0) { + daemon_log(LOG_WARNING, "Failed to change to directory '%s'", dir); + chdir("/"); + } + + for (i = 0; i < MAX_ARGS-1; i++) + if (!(args[i] = va_arg(ap, char*))) + break; + args[i] = NULL; + + execv(prog, args); + + daemon_log(LOG_ERR, "execv(%s) failed: %s", prog, strerror(errno)); + + fail: + + _exit(EXIT_FAILURE); + } + + close(p[1]); + + FD_ZERO(&fds); + FD_SET(p[0], &fds); + sigfd = daemon_signal_fd(); + FD_SET(sigfd, &fds); + + n = 0; + + for (;;) { + fd_set qfds = fds; + + if (select(FD_SETSIZE, &qfds, NULL, NULL, NULL) < 0) { + + if (errno == EINTR) + continue; + + daemon_log(LOG_ERR, "select() failed: %s", strerror(errno)); + + saved_errno = errno; + close(p[0]); + errno = saved_errno; + return -1; + } + + if (FD_ISSET(p[0], &qfds)) { + char c; + + if (read(p[0], &c, 1) != 1) + break; + + buf[n] = c; + + if (c == '\n' || n >= sizeof(buf) - 2) { + if (c != '\n') n++; + buf[n] = 0; + + if (buf[0]) + daemon_log(LOG_INFO, "client: %s", buf); + + n = 0; + } else + n++; + } + + if (FD_ISSET(sigfd, &qfds)) { + int sig; + + if ((sig = daemon_signal_next()) < 0) { + saved_errno = errno; + close(p[0]); + errno = saved_errno; + return -1; + } + + if (sig != SIGCHLD) { + daemon_log(LOG_WARNING, "Killing child."); + kill(pid, SIGTERM); + } + } + } + + if (n > 0) { + buf[n] = 0; + daemon_log(LOG_WARNING, "client: %s", buf); + } + + close(p[0]); + + for (;;) { + if (waitpid(pid, &r, 0) < 0) { + + if (errno == EINTR) + continue; + + daemon_log(LOG_ERR, "waitpid(): %s", strerror(errno)); + return -1; + } else { + if (!WIFEXITED(r)) { + errno = ECANCELED; + return -1; + } + + if (ret) + *ret = WEXITSTATUS(r); + + return 0; + } + } +} + +int daemon_exec(const char *dir, int *ret, const char *prog, ...) { + va_list ap; + int r; + + va_start(ap, prog); + r = daemon_execv(dir, ret, prog, ap); + va_end(ap); + + return r; +} diff --git a/libdaemon/dexec.h b/libdaemon/dexec.h new file mode 100644 index 0000000..7c03017 --- /dev/null +++ b/libdaemon/dexec.h @@ -0,0 +1,84 @@ +#ifndef foodexechfoo +#define foodexechfoo + +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file + * + * Contains a robust API for running sub processes with STDOUT and + * STDERR redirected to syslog + */ + +/** This variable is defined to 1 iff daemon_exec() is supported. + * @since 0.4 + * @see daemon_exec() */ +#define DAEMON_EXEC_AVAILABLE 1 + +#if defined(__GNUC__) && ! defined(DAEMON_GCC_SENTINEL) +#define DAEMON_GCC_SENTINEL __attribute__ ((sentinel)) +#else +/** A macro for making use of GCCs printf compilation warnings */ +#define DAEMON_GCC_SENTINEL +#endif + +/** Run the specified executable with the specified arguments in the + * specified directory and return the return value of the program in + * the specified pointer. The calling process is blocked until the + * child finishes and all child output (either STDOUT or STDIN) has + * been written to syslog. Running this function requires that + * daemon_signal() has been called with SIGCHLD as argument. + * + * @param dir Working directory for the process. + * @param ret A pointer to an integer to write the return value of the program to. + * @param prog The path to the executable + * @param ... The arguments to be passed to the program, followed by a (char *) NULL + * @return Nonzero on failure, zero on success + * @since 0.4 + * @see DAEMON_EXEC_AVAILABLE + */ +int daemon_exec(const char *dir, int *ret, const char *prog, ...) DAEMON_GCC_SENTINEL; + +/** This variable is defined to 1 iff daemon_execv() is supported. + * @since 0.11 + * @see daemon_execv() */ +#define DAEMON_EXECV_AVAILABLE 1 + +/** The same as daemon_exec, but without variadic arguments + * @since 0.11 + * @see DAEMON_EXECV_AVAILABLE */ +int daemon_execv(const char *dir, int *ret, const char *prog, va_list ap); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libdaemon/dfork.c b/libdaemon/dfork.c new file mode 100644 index 0000000..783033f --- /dev/null +++ b/libdaemon/dfork.c @@ -0,0 +1,730 @@ +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <assert.h> +#include <sys/ioctl.h> +#include <signal.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <dirent.h> + +#include "dfork.h" +#include "dnonblock.h" +#include "dlog.h" + +#if defined(_NSIG) /* On glibc NSIG does not count RT signals */ +# define SIGNAL_UPPER_BOUND _NSIG +#elif defined(NSIG) /* Solaris defines just this */ +# define SIGNAL_UPPER_BOUND NSIG +#else +# error "Unknown upper bound for signals" +#endif + +static int _daemon_retval_pipe[2] = { -1, -1 }; + +static int _null_open(int f, int fd) { + int fd2; + + if ((fd2 = open("/dev/null", f)) < 0) + return -1; + + if (fd2 == fd) + return fd; + + if (dup2(fd2, fd) < 0) + return -1; + + close(fd2); + return fd; +} + +static ssize_t atomic_read(int fd, void *d, size_t l) { + ssize_t t = 0; + + while (l > 0) { + ssize_t r; + + if ((r = read(fd, d, l)) <= 0) { + + if (r < 0) + return t > 0 ? t : -1; + else + return t; + } + + t += r; + d = (char*) d + r; + l -= r; + } + + return t; +} + +static ssize_t atomic_write(int fd, const void *d, size_t l) { + ssize_t t = 0; + + while (l > 0) { + ssize_t r; + + if ((r = write(fd, d, l)) <= 0) { + + if (r < 0) + return t > 0 ? t : -1; + else + return t; + } + + t += r; + d = (const char*) d + r; + l -= r; + } + + return t; +} + +static int move_fd_up(int *fd) { + assert(fd); + + while (*fd <= 2) { + if ((*fd = dup(*fd)) < 0) { + daemon_log(LOG_ERR, "dup(): %s", strerror(errno)); + return -1; + } + } + + return 0; +} + +static void sigchld(int s) { +} + +pid_t daemon_fork(void) { + pid_t pid; + int pipe_fds[2] = {-1, -1}; + struct sigaction sa_old, sa_new; + sigset_t ss_old, ss_new; + int saved_errno; + + memset(&sa_new, 0, sizeof(sa_new)); + sa_new.sa_handler = sigchld; + sa_new.sa_flags = SA_RESTART; + + if (sigemptyset(&ss_new) < 0) { + daemon_log(LOG_ERR, "sigemptyset() failed: %s", strerror(errno)); + return (pid_t) -1; + } + + if (sigaddset(&ss_new, SIGCHLD) < 0) { + daemon_log(LOG_ERR, "sigaddset() failed: %s", strerror(errno)); + return (pid_t) -1; + } + + if (sigaction(SIGCHLD, &sa_new, &sa_old) < 0) { + daemon_log(LOG_ERR, "sigaction() failed: %s", strerror(errno)); + return (pid_t) -1; + } + + if (sigprocmask(SIG_UNBLOCK, &ss_new, &ss_old) < 0) { + daemon_log(LOG_ERR, "sigprocmask() failed: %s", strerror(errno)); + + saved_errno = errno; + sigaction(SIGCHLD, &sa_old, NULL); + errno = saved_errno; + + return (pid_t) -1; + } + + if (pipe(pipe_fds) < 0) { + daemon_log(LOG_ERR, "pipe() failed: %s", strerror(errno)); + + saved_errno = errno; + sigaction(SIGCHLD, &sa_old, NULL); + sigprocmask(SIG_SETMASK, &ss_old, NULL); + errno = saved_errno; + + return (pid_t) -1; + } + + if ((pid = fork()) < 0) { /* First fork */ + daemon_log(LOG_ERR, "First fork() failed: %s", strerror(errno)); + + saved_errno = errno; + close(pipe_fds[0]); + close(pipe_fds[1]); + sigaction(SIGCHLD, &sa_old, NULL); + sigprocmask(SIG_SETMASK, &ss_old, NULL); + errno = saved_errno; + + return (pid_t) -1; + + } else if (pid == 0) { + pid_t dpid; + + /* First child. Now we are sure not to be a session leader or + * process group leader anymore, i.e. we know that setsid() + * will succeed. */ + + if (daemon_log_use & DAEMON_LOG_AUTO) + daemon_log_use = DAEMON_LOG_SYSLOG; + + if (close(pipe_fds[0]) < 0) { + daemon_log(LOG_ERR, "close() failed: %s", strerror(errno)); + goto fail; + } + + /* Move file descriptors up*/ + if (move_fd_up(&pipe_fds[1]) < 0) + goto fail; + + if (_daemon_retval_pipe[0] >= 0 && move_fd_up(&_daemon_retval_pipe[0]) < 0) + goto fail; + if (_daemon_retval_pipe[1] >= 0 && move_fd_up(&_daemon_retval_pipe[1]) < 0) + goto fail; + + if (_null_open(O_RDONLY, 0) < 0) { + daemon_log(LOG_ERR, "Failed to open /dev/null for STDIN: %s", strerror(errno)); + goto fail; + } + + if (_null_open(O_WRONLY, 1) < 0) { + daemon_log(LOG_ERR, "Failed to open /dev/null for STDOUT: %s", strerror(errno)); + goto fail; + } + + if (_null_open(O_WRONLY, 2) < 0) { + daemon_log(LOG_ERR, "Failed to open /dev/null for STDERR: %s", strerror(errno)); + goto fail; + } + + /* Create a new session. This will create a new session and a + * new process group for us and we will be the ledaer of + * both. This should always succeed because we cannot be the + * process group leader because we just forked. */ + if (setsid() < 0) { + daemon_log(LOG_ERR, "setsid() failed: %s", strerror(errno)); + goto fail; + } + + umask(0077); + + if (chdir("/") < 0) { + daemon_log(LOG_ERR, "chdir() failed: %s", strerror(errno)); + goto fail; + } + + if ((pid = fork()) < 0) { /* Second fork */ + daemon_log(LOG_ERR, "Second fork() failed: %s", strerror(errno)); + goto fail; + + } else if (pid == 0) { + /* Second child. Our father will exit right-away. That way + * we can be sure that we are a child of init now, even if + * the process which spawned us stays around for a longer + * time. Also, since we are no session leader anymore we + * can be sure that we will never acquire a controlling + * TTY. */ + + if (sigaction(SIGCHLD, &sa_old, NULL) < 0) { + daemon_log(LOG_ERR, "close() failed: %s", strerror(errno)); + goto fail; + } + + if (sigprocmask(SIG_SETMASK, &ss_old, NULL) < 0) { + daemon_log(LOG_ERR, "sigprocmask() failed: %s", strerror(errno)); + goto fail; + } + + if (signal(SIGTTOU, SIG_IGN) == SIG_ERR) { + daemon_log(LOG_ERR, "signal(SIGTTOU, SIG_IGN) failed: %s", strerror(errno)); + goto fail; + } + + if (signal(SIGTTIN, SIG_IGN) == SIG_ERR) { + daemon_log(LOG_ERR, "signal(SIGTTIN, SIG_IGN) failed: %s", strerror(errno)); + goto fail; + } + + if (signal(SIGTSTP, SIG_IGN) == SIG_ERR) { + daemon_log(LOG_ERR, "signal(SIGTSTP, SIG_IGN) failed: %s", strerror(errno)); + goto fail; + } + + dpid = getpid(); + if (atomic_write(pipe_fds[1], &dpid, sizeof(dpid)) != sizeof(dpid)) { + daemon_log(LOG_ERR, "write() failed: %s", strerror(errno)); + goto fail; + } + + if (close(pipe_fds[1]) < 0) { + daemon_log(LOG_ERR, "close() failed: %s", strerror(errno)); + goto fail; + } + + return 0; + + } else { + /* Second father */ + close(pipe_fds[1]); + _exit(0); + } + + fail: + dpid = (pid_t) -1; + + if (atomic_write(pipe_fds[1], &dpid, sizeof(dpid)) != sizeof(dpid)) + daemon_log(LOG_ERR, "Failed to write error PID: %s", strerror(errno)); + + close(pipe_fds[1]); + _exit(0); + + } else { + /* First father */ + pid_t dpid; + + close(pipe_fds[1]); + + if (waitpid(pid, NULL, WUNTRACED) < 0) { + saved_errno = errno; + close(pipe_fds[0]); + sigaction(SIGCHLD, &sa_old, NULL); + sigprocmask(SIG_SETMASK, &ss_old, NULL); + errno = saved_errno; + return -1; + } + + sigprocmask(SIG_SETMASK, &ss_old, NULL); + sigaction(SIGCHLD, &sa_old, NULL); + + if (atomic_read(pipe_fds[0], &dpid, sizeof(dpid)) != sizeof(dpid)) { + daemon_log(LOG_ERR, "Failed to read daemon PID."); + dpid = (pid_t) -1; + errno = EINVAL; + } else if (dpid == (pid_t) -1) + errno = EIO; + + saved_errno = errno; + close(pipe_fds[0]); + errno = saved_errno; + + return dpid; + } +} + +int daemon_retval_init(void) { + + if (_daemon_retval_pipe[0] < 0 || _daemon_retval_pipe[1] < 0) { + + if (pipe(_daemon_retval_pipe) < 0) { + daemon_log(LOG_ERR, "pipe(): %s", strerror(errno)); + return -1; + } + } + + return 0; +} + +void daemon_retval_done(void) { + int saved_errno = errno; + + if (_daemon_retval_pipe[0] >= 0) + close(_daemon_retval_pipe[0]); + + if (_daemon_retval_pipe[1] >= 0) + close(_daemon_retval_pipe[1]); + + _daemon_retval_pipe[0] = _daemon_retval_pipe[1] = -1; + + errno = saved_errno; +} + +int daemon_retval_send(int i) { + ssize_t r; + + if (_daemon_retval_pipe[1] < 0) { + errno = EINVAL; + return -1; + } + + r = atomic_write(_daemon_retval_pipe[1], &i, sizeof(i)); + + daemon_retval_done(); + + if (r != sizeof(i)) { + + if (r < 0) + daemon_log(LOG_ERR, "write() failed while writing return value to pipe: %s", strerror(errno)); + else { + daemon_log(LOG_ERR, "write() too short while writing return value from pipe"); + errno = EINVAL; + } + + return -1; + } + + return 0; +} + +int daemon_retval_wait(int timeout) { + ssize_t r; + int i; + + if (timeout > 0) { + struct timeval tv; + int s; + fd_set fds; + + tv.tv_sec = timeout; + tv.tv_usec = 0; + + FD_ZERO(&fds); + FD_SET(_daemon_retval_pipe[0], &fds); + + if ((s = select(FD_SETSIZE, &fds, 0, 0, &tv)) != 1) { + + if (s < 0) + daemon_log(LOG_ERR, "select() failed while waiting for return value: %s", strerror(errno)); + else { + errno = ETIMEDOUT; + daemon_log(LOG_ERR, "Timeout reached while wating for return value"); + } + + return -1; + } + } + + if ((r = atomic_read(_daemon_retval_pipe[0], &i, sizeof(i))) != sizeof(i)) { + + if (r < 0) + daemon_log(LOG_ERR, "read() failed while reading return value from pipe: %s", strerror(errno)); + else if (r == 0) { + daemon_log(LOG_ERR, "read() failed with EOF while reading return value from pipe."); + errno = EINVAL; + } else if (r > 0) { + daemon_log(LOG_ERR, "read() too short while reading return value from pipe."); + errno = EINVAL; + } + + return -1; + } + + daemon_retval_done(); + + return i; +} + +int daemon_close_all(int except_fd, ...) { + va_list ap; + int n = 0, i, r; + int *p; + int saved_errno; + + va_start(ap, except_fd); + + if (except_fd >= 0) + for (n = 1; va_arg(ap, int) >= 0; n++) + ; + + va_end(ap); + + if (!(p = malloc(sizeof(int) * (n+1)))) + return -1; + + va_start(ap, except_fd); + + i = 0; + if (except_fd >= 0) { + int fd; + p[i++] = except_fd; + + while ((fd = va_arg(ap, int)) >= 0) + p[i++] = fd; + } + p[i] = -1; + + va_end(ap); + + r = daemon_close_allv(p); + + saved_errno = errno; + free(p); + errno = saved_errno; + + return r; +} + +/** Same as daemon_close_all but takes an array of fds, terminated by -1 */ +int daemon_close_allv(const int except_fds[]) { + struct rlimit rl; + int fd, maxfd; + +#ifdef __linux__ + int saved_errno; + + DIR *d; + + if ((d = opendir("/proc/self/fd"))) { + + struct dirent *de; + + while ((de = readdir(d))) { + int found; + long l; + char *e = NULL; + int i; + + if (de->d_name[0] == '.') + continue; + + errno = 0; + l = strtol(de->d_name, &e, 10); + if (errno != 0 || !e || *e) { + closedir(d); + errno = EINVAL; + return -1; + } + + fd = (int) l; + + if ((long) fd != l) { + closedir(d); + errno = EINVAL; + return -1; + } + + if (fd < 3) + continue; + + if (fd == dirfd(d)) + continue; + + if (fd == _daemon_retval_pipe[1]) + continue; + + found = 0; + for (i = 0; except_fds[i] >= 0; i++) + if (except_fds[i] == fd) { + found = 1; + break; + } + + if (found) + continue; + + if (close(fd) < 0) { + saved_errno = errno; + closedir(d); + errno = saved_errno; + + return -1; + } + + if (fd == _daemon_retval_pipe[0]) + _daemon_retval_pipe[0] = -1; /* mark as closed */ + } + + closedir(d); + return 0; + } + +#endif + + if (getrlimit(RLIMIT_NOFILE, &rl) > 0) + maxfd = (int) rl.rlim_max; + else + maxfd = sysconf(_SC_OPEN_MAX); + + for (fd = 3; fd < maxfd; fd++) { + int i, found; + + if (fd == _daemon_retval_pipe[1]) + continue; + + found = 0; + for (i = 0; except_fds[i] >= 0; i++) + if (except_fds[i] == fd) { + found = 1; + break; + } + + if (found) + continue; + + if (close(fd) < 0 && errno != EBADF) + return -1; + + if (fd == _daemon_retval_pipe[0]) + _daemon_retval_pipe[0] = -1; /* mark as closed */ + } + + return 0; +} + +int daemon_unblock_sigs(int except, ...) { + va_list ap; + int n = 0, i, r; + int *p; + int saved_errno; + + va_start(ap, except); + + if (except >= 1) + for (n = 1; va_arg(ap, int) >= 0; n++) + ; + + va_end(ap); + + if (!(p = malloc(sizeof(int) * (n+1)))) + return -1; + + va_start(ap, except); + + i = 0; + if (except >= 1) { + int sig; + p[i++] = except; + + while ((sig = va_arg(ap, int)) >= 0) + p[i++] = sig; + } + p[i] = -1; + + va_end(ap); + + r = daemon_unblock_sigsv(p); + + saved_errno = errno; + free(p); + errno = saved_errno; + + return r; +} + +int daemon_unblock_sigsv(const int except[]) { + int i; + sigset_t ss; + + if (sigemptyset(&ss) < 0) + return -1; + + for (i = 0; except[i] > 0; i++) + if (sigaddset(&ss, except[i]) < 0) + return -1; + + return sigprocmask(SIG_SETMASK, &ss, NULL); +} + +int daemon_reset_sigs(int except, ...) { + va_list ap; + int n = 0, i, r; + int *p; + int saved_errno; + + va_start(ap, except); + + if (except >= 1) + for (n = 1; va_arg(ap, int) >= 0; n++) + ; + + va_end(ap); + + if (!(p = malloc(sizeof(int) * (n+1)))) + return -1; + + va_start(ap, except); + + i = 0; + if (except >= 1) { + int sig; + p[i++] = except; + + while ((sig = va_arg(ap, int)) >= 0) + p[i++] = sig; + } + p[i] = -1; + + va_end(ap); + + r = daemon_reset_sigsv(p); + + saved_errno = errno; + free(p); + errno = saved_errno; + + return r; +} + +int daemon_reset_sigsv(const int except[]) { + int sig; + + for (sig = 1; sig < SIGNAL_UPPER_BOUND; sig++) { + int reset = 1; + + switch (sig) { + case SIGKILL: + case SIGSTOP: + reset = 0; + break; + + default: { + int i; + + for (i = 0; except[i] > 0; i++) { + if (sig == except[i]) { + reset = 0; + break; + } + } + } + } + + if (reset) { + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = SIG_DFL; + + /* On Linux the first two RT signals are reserved by + * glibc, and sigaction() will return EINVAL for them. */ + if ((sigaction(sig, &sa, NULL) < 0)) + if (errno != EINVAL) + return -1; + } + } + + return 0; +} diff --git a/libdaemon/dfork.h b/libdaemon/dfork.h new file mode 100644 index 0000000..47b1630 --- /dev/null +++ b/libdaemon/dfork.h @@ -0,0 +1,165 @@ +#ifndef foodaemonforkhfoo +#define foodaemonforkhfoo + +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** \mainpage libdaemon + * + * libdaemon + * + * For a brief explanation of libdaemons's purpose, have a look on the + * README file. Thank you! + * + */ + +/** \example testd.c + * This is an example for the usage of libdaemon + */ + +/** \file + * + * Contains an API for doing a daemonizing fork(). + * + * You may daemonize by calling daemon_fork(), a function similar to + * the plain fork(). If you want to return a return value of the + * initialization procedure of the child from the parent, you may use + * the daemon_retval_xxx() functions. + */ + +/** Does a daemonizing fork(). For the new daemon process STDIN, + * STDOUT, STDERR are connected to /dev/null, the process is a session + * leader, the current directory is changed to /, the umask is set to + * 777. + * @return On success, the PID of the child process is returned in the + * parent's thread of execution, and a 0 is returned in the child's + * thread of execution. On failure, -1 will be returned in the + * parent's context, no child process will be created, and errno will + * be set appropriately. + */ +pid_t daemon_fork(void); + +/** Allocate and initialize resources required by the + * daemon_retval_xxx() functions. These functions allow the child to + * send a value to the parent after completing its initialisation. + * Call this in the parent before forking. + * @return zero on success, nonzero on failure. + */ +int daemon_retval_init(void); + +/** Frees the resources allocated by daemon_retval_init(). This should + * be called if neither daemon_retval_wait() nor daemon_retval_send() + * is called in the current process. The resources allocated by + * daemon_retval_init() should be freed in both parent and daemon + * process. This may be achieved by using daemon_retval_wait() + * resp. daemon_retval_send(), or by using daemon_retval_done(). + */ +void daemon_retval_done(void); + +/** Return the value sent by the child via the daemon_retval_send() + * function, but wait only the specified number of seconds before + * timing out and returning a negative number. Should be called just + * once from the parent process only. A subsequent call to + * daemon_retval_done() in the parent is ignored. + * + * @param timeout Thetimeout in seconds + * @return The integer passed daemon_retval_send() in the daemon process, or -1 on failure. + */ +int daemon_retval_wait(int timeout); + +/** Send the specified integer to the parent process. Do not send -1 + * because this signifies a library error. Should be called just once + * from the daemon process only. A subsequent call to + * daemon_retval_done() in the daemon is ignored. @param s The + * integer to pass to daemon_retval_wait() in the parent process + * @return Zero on success, nonzero on failure. + */ +int daemon_retval_send(int s); + +/** This variable is defined to 1 iff daemon_close_all() and + * daemon_close_allv() are supported. + * @since 0.11 + * @see daemon_close_all(), daemon_close_allv() */ +#define DAEMON_CLOSE_ALL_AVAILABLE 1 + +/** Close all file descriptors except those passed. List needs to be + * terminated by -1. FDs 0, 1, 2 will be kept open anyway. + * @since 0.11 + * @see DAEMON_CLOSE_ALL_AVAILABLE */ +int daemon_close_all(int except_fd, ...); + +/** Same as daemon_close_all but takes an array of fds, terminated by + * -1 + * @since 0.11 + * @see DAEMON_CLOSE_ALL_AVAILABLE */ +int daemon_close_allv(const int except_fds[]); + +/** This variable is defined to 1 iff daemon_unblock_sigs() and + * daemon_unblock_sigsv() are supported. + * @since 0.13 + * @see daemon_unblock_sigs(), daemon_unblock_sigsv()*/ +#define DAEMON_UNBLOCK_SIGS_AVAILABLE 1 + +/** Unblock all signals except those passed. List needs to be + * terminated by -1. + * @since 0.13 + * @see DAEMON_UNBLOCK_SIGS_AVAILABLE */ +int daemon_unblock_sigs(int except, ...); + +/** Same as daemon_unblock_sigs() but takes an array of signals, + * terminated by -1 + * @since 0.13 + * @see DAEMON_UNBLOCK_SIGS_AVAILABLE */ +int daemon_unblock_sigsv(const int except[]); + +/** This variable is defined to 1 iff daemon_reset_sigs() and + * daemon_reset_sigsv() are supported. + * @since 0.13 + * @see daemon_reset_sigs(), daemon_reset_sigsv() */ +#define DAEMON_RESET_SIGS_AVAILABLE 1 + +/** Reset all signal handlers except those passed. List needs to be + * terminated by -1. + * @since 0.13 + * @see DAEMON_RESET_SIGS_AVAILABLE */ +int daemon_reset_sigs(int except, ...); + +/** Same as daemon_reset_sigs() but takes an array of signals, + * terminated by -1 + * @since 0.13 + * @see DAEMON_RESET_SIGS_AVAILABLE */ +int daemon_reset_sigsv(const int except[]); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libdaemon/dlog.c b/libdaemon/dlog.c new file mode 100644 index 0000000..1cc0566 --- /dev/null +++ b/libdaemon/dlog.c @@ -0,0 +1,93 @@ +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdarg.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "dlog.h" + +enum daemon_log_flags daemon_log_use = DAEMON_LOG_AUTO|DAEMON_LOG_STDERR; +const char* daemon_log_ident = NULL; + +static int daemon_verbosity_level = LOG_INFO; + +void daemon_set_verbosity(int verbosity_prio) { + + /* Allow using negative verbosity levels to hide _all_ messages */ + if (verbosity_prio > 0 && (verbosity_prio & LOG_PRIMASK) != LOG_PRIMASK) + daemon_log(LOG_ERR, "The value %d is not a valid priority value", verbosity_prio); + + daemon_verbosity_level = verbosity_prio & LOG_PRIMASK; +} + +void daemon_logv(int prio, const char* template, va_list arglist) { + int saved_errno; + + saved_errno = errno; + + if (daemon_log_use & DAEMON_LOG_SYSLOG) { + openlog(daemon_log_ident ? daemon_log_ident : "UNKNOWN", LOG_PID, LOG_DAEMON); + vsyslog(prio | LOG_DAEMON, template, arglist); + } + + if (prio > daemon_verbosity_level) + goto end_daemon_logv; + + if (daemon_log_use & DAEMON_LOG_STDERR) { + vfprintf(stderr, template, arglist); + fprintf(stderr, "\n"); + } + + if (daemon_log_use & DAEMON_LOG_STDOUT) { + vfprintf(stdout, template, arglist); + fprintf(stdout, "\n"); + } + + end_daemon_logv: + errno = saved_errno; +} + +void daemon_log(int prio, const char* template, ...) { + va_list arglist; + + va_start(arglist, template); + daemon_logv(prio, template, arglist); + va_end(arglist); +} + +char *daemon_ident_from_argv0(char *argv0) { + char *p; + + if ((p = strrchr(argv0, '/'))) + return p+1; + + return argv0; +} diff --git a/libdaemon/dlog.h b/libdaemon/dlog.h new file mode 100644 index 0000000..deea520 --- /dev/null +++ b/libdaemon/dlog.h @@ -0,0 +1,119 @@ +#ifndef foodaemonloghfoo +#define foodaemonloghfoo + +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#include <syslog.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file + * + * Contains a robust API for logging messages + */ + +/** Specifies where to send the log messages to. The global variable daemon_log_use takes values of this type. + */ +enum daemon_log_flags { + DAEMON_LOG_SYSLOG = 1, /**< Log messages are written to syslog */ + DAEMON_LOG_STDERR = 2, /**< Log messages are written to STDERR */ + DAEMON_LOG_STDOUT = 4, /**< Log messages are written to STDOUT */ + DAEMON_LOG_AUTO = 8 /**< If this is set a daemon_fork() will + change this to DAEMON_LOG_SYSLOG in + the daemon process. */ +}; + +/** This variable is used to specify the log target(s) to + * use. Defaults to DAEMON_LOG_STDERR|DAEMON_LOG_AUTO */ +extern enum daemon_log_flags daemon_log_use; + +/** Specifies the syslog identification, use daemon_ident_from_argv0() + * to set this to a sensible value or generate your own. */ +extern const char* daemon_log_ident; + +#if defined(__GNUC__) && ! defined(DAEMON_GCC_PRINTF_ATTR) +#define DAEMON_GCC_PRINTF_ATTR(a,b) __attribute__ ((format (printf, a, b))) +#else +/** A macro for making use of GCCs printf compilation warnings */ +#define DAEMON_GCC_PRINTF_ATTR(a,b) +#endif + +/** Log a message using printf format strings using the specified syslog priority + * @param prio The syslog priority (PRIO_xxx constants) + * @param t,... The text message to log + */ +void daemon_log(int prio, const char* t, ...) DAEMON_GCC_PRINTF_ATTR(2,3); + +/** This variable is defined to 1 iff daemon_logv() is supported. + * @since 0.11 + * @see daemon_logv() + */ +#define DAEMON_LOGV_AVAILABLE 1 + +/** Same as daemon_log(), but without variadic arguments + * @since 0.11 + * @see DAEMON_LOGV_AVAILABLE + */ +void daemon_logv(int prio, const char* t, va_list ap); + +/** Return a sensible syslog identification for daemon_log_ident + * generated from argv[0]. This will return a pointer to the file name + * of argv[0], i.e. strrchr(argv[0], '\')+1 + * @param argv0 argv[0] as passed to main() + * @return The identification string + */ +char *daemon_ident_from_argv0(char *argv0); + +/** This variable is defined to 1 iff daemon_set_verbosity() is available. + * @since 0.14 + * @see daemon_set_verbosity() + */ +#define DAEMON_SET_VERBOSITY_AVAILABLE 1 + +/** Setter for the verbosity level of standard output. + * + * @param verbosity_prio Minimum priority level for messages to output + * on standard output/error + * + * Allows to decide which messages to output on standard output/error + * streams. All messages are logged to syslog and this setting does + * not influence that. + * + * The default value is LOG_WARNING. + * + * @since 0.14 + * @see DAEMON_SET_VERBOSITY_AVAILABLE + */ +void daemon_set_verbosity(int verbosity_prio); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libdaemon/dnonblock.c b/libdaemon/dnonblock.c new file mode 100644 index 0000000..003514e --- /dev/null +++ b/libdaemon/dnonblock.c @@ -0,0 +1,49 @@ +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> + +#include "dnonblock.h" + +int daemon_nonblock(int fd, int b) { + int a, c; + + if ((a = fcntl(fd, F_GETFL)) < 0) + return -1; + + if (b) + c = a | O_NONBLOCK; + else + c = a & ~O_NONBLOCK; + + if (c == a) + return 0; + + return fcntl(fd, F_SETFL, c); +} diff --git a/libdaemon/dnonblock.h b/libdaemon/dnonblock.h new file mode 100644 index 0000000..e39da4e --- /dev/null +++ b/libdaemon/dnonblock.h @@ -0,0 +1,52 @@ +#ifndef foodaemonnonblockhfoo +#define foodaemonnonblockhfoo + +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file + * + * Contains a single function used to change a file descriptor to + * non-blocking mode using fcntl(). + */ + +/** Change the passed file descriptor to non-blocking or blocking + * mode, depending on b. + * @param fd The file descriptor to manipulation + * @param b TRUE if non-blocking mode should be enabled, FALSE if it + * should be disabled + * @return Zero on success, nonzero on failure. + */ +int daemon_nonblock(int fd, int b); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libdaemon/dpid.c b/libdaemon/dpid.c new file mode 100644 index 0000000..7f66d0b --- /dev/null +++ b/libdaemon/dpid.c @@ -0,0 +1,281 @@ +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <time.h> +#include <sys/select.h> +#include <fcntl.h> +#include <stddef.h> +#include <sys/time.h> + +#include "dpid.h" +#include "dlog.h" + +#ifndef ETIME +#define ETIME ETIMEDOUT /* For FreeBSD */ +#endif + +#ifndef PATH_MAX +#define PATH_MAX 512 +#endif + +#define VARRUN LOCALSTATEDIR "/run" + +const char *daemon_pid_file_ident = NULL; +daemon_pid_file_proc_t daemon_pid_file_proc = daemon_pid_file_proc_default; + +const char *daemon_pid_file_proc_default(void) { +#ifdef HAVE_ASPRINTF + static char *fn = NULL; + free(fn); + asprintf(&fn, "%s/%s.pid", VARRUN, daemon_pid_file_ident ? daemon_pid_file_ident : "unknown"); +#else + static char fn[PATH_MAX]; + snprintf(fn, sizeof(fn), "%s/%s.pid", VARRUN, daemon_pid_file_ident ? daemon_pid_file_ident : "unknown"); +#endif + + return fn; +} + +static int lock_file(int fd, int enable) { + struct flock f; + + memset(&f, 0, sizeof(f)); + f.l_type = enable ? F_WRLCK : F_UNLCK; + f.l_whence = SEEK_SET; + f.l_start = 0; + f.l_len = 0; + + if (fcntl(fd, F_SETLKW, &f) < 0) { + + if (enable && errno == EBADF) { + f.l_type = F_RDLCK; + + if (fcntl(fd, F_SETLKW, &f) >= 0) + return 0; + } + + daemon_log(LOG_WARNING, "fcntl(F_SETLKW) failed: %s", strerror(errno)); + return -1; + } + + return 0; +} + +pid_t daemon_pid_file_is_running(void) { + const char *fn; + static char txt[256]; + int fd = -1, locked = -1; + pid_t ret = (pid_t) -1, pid; + ssize_t l; + long lpid; + char *e = NULL; + + if (!(fn = daemon_pid_file_proc())) { + errno = EINVAL; + goto finish; + } + + if ((fd = open(fn, O_RDWR, 0644)) < 0) { + if ((fd = open(fn, O_RDONLY, 0644)) < 0) { + if (errno != ENOENT) + daemon_log(LOG_WARNING, "Failed to open PID file: %s", strerror(errno)); + + goto finish; + } + } + + if ((locked = lock_file(fd, 1)) < 0) + goto finish; + + if ((l = read(fd, txt, sizeof(txt)-1)) < 0) { + int saved_errno = errno; + daemon_log(LOG_WARNING, "read(): %s", strerror(errno)); + unlink(fn); + errno = saved_errno; + goto finish; + } + + txt[l] = 0; + txt[strcspn(txt, "\r\n")] = 0; + + errno = 0; + lpid = strtol(txt, &e, 10); + pid = (pid_t) lpid; + + if (errno != 0 || !e || *e || (long) pid != lpid) { + daemon_log(LOG_WARNING, "PID file corrupt, removing. (%s)", fn); + unlink(fn); + errno = EINVAL; + goto finish; + } + + if (kill(pid, 0) != 0 && errno != EPERM) { + int saved_errno = errno; + daemon_log(LOG_WARNING, "Process %lu died: %s; trying to remove PID file. (%s)", (unsigned long) pid, strerror(errno), fn); + unlink(fn); + errno = saved_errno; + goto finish; + } + + ret = pid; + +finish: + + if (fd >= 0) { + int saved_errno = errno; + if (locked >= 0) + lock_file(fd, 0); + close(fd); + errno = saved_errno; + } + + return ret; +} + +int daemon_pid_file_kill(int s) { + pid_t pid; + + if ((pid = daemon_pid_file_is_running()) == (pid_t) -1) + return -1; + + if (kill(pid, s) < 0) + return -1; + + return 0; +} + +int daemon_pid_file_kill_wait(int s, int m) { + pid_t pid; + time_t t; + + if ((pid = daemon_pid_file_is_running()) < 0) + return -1; + + if (kill(pid, s) < 0) + return -1; + + t = time(NULL) + m; + + for (;;) { + int r; + struct timeval tv = { 0, 100000 }; + + if (time(NULL) > t) { + errno = ETIME; + return -1; + } + + if ((r = kill(pid, 0)) < 0 && errno != ESRCH) + return -1; + + if (r) + return 0; + + if (select(0, NULL, NULL, NULL, &tv) < 0) + return -1; + } +} + +int daemon_pid_file_create(void) { + const char *fn; + int fd = -1; + int ret = -1; + int locked = -1; + char t[64]; + ssize_t l; + mode_t u; + + u = umask(022); + + if (!(fn = daemon_pid_file_proc())) { + errno = EINVAL; + goto finish; + } + + if ((fd = open(fn, O_CREAT|O_RDWR|O_EXCL, 0644)) < 0) { + daemon_log(LOG_ERR, "open(%s): %s", fn, strerror(errno)); + goto finish; + } + + if ((locked = lock_file(fd, 1)) < 0) { + int saved_errno = errno; + unlink(fn); + errno = saved_errno; + goto finish; + } + + snprintf(t, sizeof(t), "%lu\n", (unsigned long) getpid()); + + l = strlen(t); + if (write(fd, t, l) != l) { + int saved_errno = errno; + daemon_log(LOG_WARNING, "write(): %s", strerror(errno)); + unlink(fn); + errno = saved_errno; + goto finish; + } + + ret = 0; + +finish: + + if (fd >= 0) { + int saved_errno = errno; + + if (locked >= 0) + lock_file(fd, 0); + + close(fd); + errno = saved_errno; + } + + umask(u); + + return ret; +} + +int daemon_pid_file_remove(void) { + const char *fn; + + if (!(fn = daemon_pid_file_proc())) { + errno = EINVAL; + return -1; + } + + return unlink(fn); +} diff --git a/libdaemon/dpid.h b/libdaemon/dpid.h new file mode 100644 index 0000000..66cdbb1 --- /dev/null +++ b/libdaemon/dpid.h @@ -0,0 +1,106 @@ +#ifndef foodaemonpidhfoo +#define foodaemonpidhfoo + +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file + * + * Contains an API for manipulating PID files. + */ + +/** Prototype of a function for generating the name of a PID file. + */ +typedef const char* (*daemon_pid_file_proc_t)(void); + +/** Identification string for the PID file name, only used when + * daemon_pid_file_proc is set to daemon_pid_file_proc_default(). Use + * daemon_ident_from_argv0() to generate an identification string from + * argv[0] + */ +extern const char *daemon_pid_file_ident; + +/** A function pointer which is used to generate the name of the PID + * file to manipulate. Points to daemon_pid_file_proc_default() by + * default. + */ +extern daemon_pid_file_proc_t daemon_pid_file_proc; + +/** A function for creating a pid file name from + * daemon_pid_file_ident + * @return The PID file path + */ +const char *daemon_pid_file_proc_default(void); + +/** Creates PID pid file for the current process + * @return zero on success, nonzero on failure + */ +int daemon_pid_file_create(void); + +/** Removes the PID file of the current process + * @return zero on success, nonzero on failure + */ +int daemon_pid_file_remove(void); + +/** Returns the PID file of a running daemon, if available + * @return The PID or negative on failure + */ +pid_t daemon_pid_file_is_running(void); + +/** Kills a running daemon, if available + * @param s The signal to send + * @return zero on success, nonzero on failure + */ +int daemon_pid_file_kill(int s); + +/** This variable is defined to 1 iff daemon_pid_file_kill_wait() is supported. + * @since 0.3 + * @see daemon_pid_file_kill_wait() */ +#define DAEMON_PID_FILE_KILL_WAIT_AVAILABLE 1 + +/** Similar to daemon_pid_file_kill() but waits until the process + * died. This functions is new in libdaemon 0.3. The macro + * DAEMON_PID_FILE_KILL_WAIT_AVAILABLE is defined iff libdaemon + * supports this function. + * + * @param s The signal to send + * @param m Seconds to wait at maximum + * @return zero on success, nonzero on failure (timeout condition is considered a failure) + * @since 0.3 + * @see DAEMON_PID_FILE_KILL_WAIT_AVAILABLE + */ +int daemon_pid_file_kill_wait(int s, int m); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libdaemon/dsignal.c b/libdaemon/dsignal.c new file mode 100644 index 0000000..e60fb38 --- /dev/null +++ b/libdaemon/dsignal.c @@ -0,0 +1,160 @@ +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <stdarg.h> +#include <signal.h> + +#include "dsignal.h" +#include "dlog.h" +#include "dnonblock.h" + +static int _signal_pipe[2] = { -1, -1 }; + +static void _sigfunc(int s) { + int saved_errno = errno; + write(_signal_pipe[1], &s, sizeof(s)); + errno = saved_errno; +} + +static int _init(void) { + + if (_signal_pipe[0] < 0 || _signal_pipe[1] < 0) { + if (pipe(_signal_pipe) < 0) { + daemon_log(LOG_ERR, "pipe(): %s", strerror(errno)); + return -1; + } + + if (daemon_nonblock(_signal_pipe[0], 1) < 0 || daemon_nonblock(_signal_pipe[1], 1) < 0) { + daemon_signal_done(); + return -1; + } + } + + return 0; +} + +int daemon_signal_install(int s){ + sigset_t ss; + struct sigaction sa; + + if (_init() < 0) + return -1; + + if (sigemptyset(&ss) < 0) { + daemon_log(LOG_ERR, "sigemptyset(): %s", strerror(errno)); + return -1; + } + + if (sigaddset(&ss, s) < 0) { + daemon_log(LOG_ERR, "sigaddset(): %s", strerror(errno)); + return -1; + } + + if (sigprocmask(SIG_UNBLOCK, &ss, NULL) < 0) { + daemon_log(LOG_ERR, "sigprocmask(): %s", strerror(errno)); + return -1; + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = _sigfunc; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + + if (sigaction(s, &sa, NULL) < 0) { + daemon_log(LOG_ERR, "sigaction(%s, ...) failed: %s", strsignal(s), strerror(errno)); + return -1; + } + + return 0; +} + +int daemon_signal_init(int s, ...) { + int sig, r = 0; + va_list ap; + + if (_init() < 0) + return -1; + + va_start(ap, s); + + sig = s; + while (sig > 0) { + if ((r = daemon_signal_install(sig)) < 0) + break; + + sig = va_arg(ap, int); + } + + va_end(ap); + + return r; +} + +void daemon_signal_done(void) { + int saved_errno = errno; + + if (_signal_pipe[0] != -1) + close(_signal_pipe[0]); + + if (_signal_pipe[1] != -1) + close(_signal_pipe[1]); + + _signal_pipe[0] = _signal_pipe[1] = -1; + + errno = saved_errno; +} + +int daemon_signal_next(void) { + int s; + ssize_t r; + + if ((r = read(_signal_pipe[0], &s, sizeof(s))) == sizeof(s)) + return s; + + if (r < 0) { + + if (errno == EAGAIN) + return 0; + else { + daemon_log(LOG_ERR, "read(signal_pipe[0], ...): %s", strerror(errno)); + return -1; + } + } + + daemon_log(LOG_ERR, "Short read() on signal pipe."); + return -1; +} + +int daemon_signal_fd(void) { + return _signal_pipe[0]; +} diff --git a/libdaemon/dsignal.h b/libdaemon/dsignal.h new file mode 100644 index 0000000..1edfdcc --- /dev/null +++ b/libdaemon/dsignal.h @@ -0,0 +1,80 @@ +#ifndef foodaemonsignalhfoo +#define foodaemonsignalhfoo + +/*** + This file is part of libdaemon. + + Copyright 2003-2008 Lennart Poettering + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE. + +***/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** \file + * + * Contains the API for serializing signals to a pipe for + * usage with select() or poll(). + * + * You should register all signals you + * wish to handle with select() in your main loop with + * daemon_signal_init() or daemon_signal_install(). After that you + * should sleep on the file descriptor returned by daemon_signal_fd() + * and get the next signal recieved with daemon_signal_next(). You + * should call daemon_signal_done() before exiting. + */ + +/** Installs signal handlers for the specified signals + * @param s, ... The signals to install handlers for. The list should be terminated by 0 + * @return zero on success, nonzero on failure + */ +int daemon_signal_init(int s, ...); + +/** Install a signal handler for the specified signal + * @param s The signalto install handler for + * @return zero onsuccess,nonzero on failure + */ +int daemon_signal_install(int s); + +/** Free resources of signal handling, should be called before daemon exit + */ +void daemon_signal_done(void); + +/** Return the next signal recieved. This function will not + * block. Instead it returns 0 if no signal is queued. + * @return The next queued signal if one is queued, zero if none is + * queued, negative on failure. + */ +int daemon_signal_next(void); + +/** Return the file descriptor the daemon should select() on for + * reading. Whenever the descriptor is ready you should call + * daemon_signal_next() to get the next signal queued. + * @return The file descriptor or negative on failure + */ +int daemon_signal_fd(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 0000000..464ba5c --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,5 @@ +libtool.m4 +lt~obsolete.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 diff --git a/m4/attributes.m4 b/m4/attributes.m4 new file mode 100644 index 0000000..e86456a --- /dev/null +++ b/m4/attributes.m4 @@ -0,0 +1,311 @@ +dnl Macros to check the presence of generic (non-typed) symbols. +dnl Copyright (c) 2006-2007 Diego Pettenò <flameeyes@gmail.com> +dnl Copyright (c) 2006-2007 xine project +dnl +dnl This program is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 2, or (at your option) +dnl any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; if not, write to the Free Software +dnl Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +dnl 02110-1301, USA. +dnl +dnl As a special exception, the copyright owners of the +dnl macro gives unlimited permission to copy, distribute and modify the +dnl configure scripts that are the output of Autoconf when processing the +dnl Macro. You need not follow the terms of the GNU General Public +dnl License when using or distributing such scripts, even though portions +dnl of the text of the Macro appear in them. The GNU General Public +dnl License (GPL) does govern all other use of the material that +dnl constitutes the Autoconf Macro. +dnl +dnl This special exception to the GPL applies to versions of the +dnl Autoconf Macro released by this project. When you make and +dnl distribute a modified version of the Autoconf Macro, you may extend +dnl this special exception to the GPL to apply to your modified version as +dnl well. + +dnl Check if the flag is supported by compiler +dnl CC_CHECK_CFLAGS_SILENT([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_CFLAGS_SILENT], [ + AC_CACHE_VAL(AS_TR_SH([cc_cv_cflags_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + AC_COMPILE_IFELSE([int a;], + [eval "AS_TR_SH([cc_cv_cflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_cflags_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl Check if the flag is supported by compiler (cacheable) +dnl CC_CHECK_CFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_CFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_cflags_$1]), + CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! + ) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl CC_CHECK_CFLAG_APPEND(FLAG, [action-if-found], [action-if-not-found]) +dnl Check for CFLAG and appends them to CFLAGS if supported +AC_DEFUN([CC_CHECK_CFLAG_APPEND], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_cflags_$1]), + CC_CHECK_CFLAGS_SILENT([$1]) dnl Don't execute actions here! + ) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_cflags_$1])[ = xyes], + [CFLAGS="$CFLAGS $1"; $2], [$3]) +]) + +dnl CC_CHECK_CFLAGS_APPEND([FLAG1 FLAG2], [action-if-found], [action-if-not]) +AC_DEFUN([CC_CHECK_CFLAGS_APPEND], [ + for flag in $1; do + CC_CHECK_CFLAG_APPEND($flag, [$2], [$3]) + done +]) + +dnl Check if the flag is supported by linker (cacheable) +dnl CC_CHECK_LDFLAGS([FLAG], [ACTION-IF-FOUND],[ACTION-IF-NOT-FOUND]) + +AC_DEFUN([CC_CHECK_LDFLAGS], [ + AC_CACHE_CHECK([if $CC supports $1 flag], + AS_TR_SH([cc_cv_ldflags_$1]), + [ac_save_LDFLAGS="$LDFLAGS" + LDFLAGS="$LDFLAGS $1" + AC_LINK_IFELSE([int main() { return 1; }], + [eval "AS_TR_SH([cc_cv_ldflags_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_ldflags_$1])="]) + LDFLAGS="$ac_save_LDFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_ldflags_$1])[ = xyes], + [$2], [$3]) +]) + +dnl define the LDFLAGS_NOUNDEFINED variable with the correct value for +dnl the current linker to avoid undefined references in a shared object. +AC_DEFUN([CC_NOUNDEFINED], [ + dnl We check $host for which systems to enable this for. + AC_REQUIRE([AC_CANONICAL_HOST]) + + case $host in + dnl FreeBSD (et al.) does not complete linking for shared objects when pthreads + dnl are requested, as different implementations are present; to avoid problems + dnl use -Wl,-z,defs only for those platform not behaving this way. + *-freebsd*) ;; + *) + dnl First of all check for the --no-undefined variant of GNU ld. This allows + dnl for a much more readable commandline, so that people can understand what + dnl it does without going to look for what the heck -z defs does. + for possible_flags in "-Wl,--no-undefined" "-Wl,-z,defs"; do + CC_CHECK_LDFLAGS([$possible_flags], [LDFLAGS_NOUNDEFINED="$possible_flags"]) + break + done + ;; + esac + + AC_SUBST([LDFLAGS_NOUNDEFINED]) +]) + +dnl Check for a -Werror flag or equivalent. -Werror is the GCC +dnl and ICC flag that tells the compiler to treat all the warnings +dnl as fatal. We usually need this option to make sure that some +dnl constructs (like attributes) are not simply ignored. +dnl +dnl Other compilers don't support -Werror per se, but they support +dnl an equivalent flag: +dnl - Sun Studio compiler supports -errwarn=%all +AC_DEFUN([CC_CHECK_WERROR], [ + AC_CACHE_CHECK( + [for $CC way to treat warnings as errors], + [cc_cv_werror], + [CC_CHECK_CFLAGS_SILENT([-Werror], [cc_cv_werror=-Werror], + [CC_CHECK_CFLAGS_SILENT([-errwarn=%all], [cc_cv_werror=-errwarn=%all])]) + ]) +]) + +AC_DEFUN([CC_CHECK_ATTRIBUTE], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports __attribute__(( ifelse([$2], , [$1], [$2]) ))], + AS_TR_SH([cc_cv_attribute_$1]), + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE([$3], + [eval "AS_TR_SH([cc_cv_attribute_$1])='yes'"], + [eval "AS_TR_SH([cc_cv_attribute_$1])='no'"]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([eval test x$]AS_TR_SH([cc_cv_attribute_$1])[ = xyes], + [AC_DEFINE( + AS_TR_CPP([SUPPORT_ATTRIBUTE_$1]), 1, + [Define this if the compiler supports __attribute__(( ifelse([$2], , [$1], [$2]) ))] + ) + $4], + [$5]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONSTRUCTOR], [ + CC_CHECK_ATTRIBUTE( + [constructor],, + [void __attribute__((constructor)) ctor() { int a; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT], [ + CC_CHECK_ATTRIBUTE( + [format], [format(printf, n, n)], + [void __attribute__((format(printf, 1, 2))) printflike(const char *fmt, ...) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_FORMAT_ARG], [ + CC_CHECK_ATTRIBUTE( + [format_arg], [format_arg(printf)], + [char *__attribute__((format_arg(1))) gettextlike(const char *fmt) { fmt = (void *)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_VISIBILITY], [ + CC_CHECK_ATTRIBUTE( + [visibility_$1], [visibility("$1")], + [void __attribute__((visibility("$1"))) $1_function() { }], + [$2], [$3]) +]) + +AC_DEFUN([CC_ATTRIBUTE_NONNULL], [ + CC_CHECK_ATTRIBUTE( + [nonnull], [nonnull()], + [void __attribute__((nonnull())) some_function(void *foo, void *bar) { foo = (void*)0; bar = (void*)0; }], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_UNUSED], [ + CC_CHECK_ATTRIBUTE( + [unused], , + [void some_function(void *foo, __attribute__((unused)) void *bar);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_SENTINEL], [ + CC_CHECK_ATTRIBUTE( + [sentinel], , + [void some_function(void *foo, ...) __attribute__((sentinel));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_DEPRECATED], [ + CC_CHECK_ATTRIBUTE( + [deprecated], , + [void some_function(void *foo, ...) __attribute__((deprecated));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIAS], [ + CC_CHECK_ATTRIBUTE( + [alias], [weak, alias], + [void other_function(void *foo) { } + void some_function(void *foo) __attribute__((weak, alias("other_function")));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_MALLOC], [ + CC_CHECK_ATTRIBUTE( + [malloc], , + [void * __attribute__((malloc)) my_alloc(int n);], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_PACKED], [ + CC_CHECK_ATTRIBUTE( + [packed], , + [struct astructure { char a; int b; long c; void *d; } __attribute__((packed));], + [$1], [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_CONST], [ + CC_CHECK_ATTRIBUTE( + [const], , + [int __attribute__((const)) twopow(int n) { return 1 << n; } ], + [$1], [$2]) +]) + +AC_DEFUN([CC_FLAG_VISIBILITY], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if $CC supports -fvisibility=hidden], + [cc_cv_flag_visibility], + [cc_flag_visibility_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + CC_CHECK_CFLAGS_SILENT([-fvisibility=hidden], + cc_cv_flag_visibility='yes', + cc_cv_flag_visibility='no') + CFLAGS="$cc_flag_visibility_save_CFLAGS"]) + + AS_IF([test "x$cc_cv_flag_visibility" = "xyes"], + [AC_DEFINE([SUPPORT_FLAG_VISIBILITY], 1, + [Define this if the compiler supports the -fvisibility flag]) + $1], + [$2]) +]) + +AC_DEFUN([CC_FUNC_EXPECT], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([if compiler has __builtin_expect function], + [cc_cv_func_expect], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + AC_COMPILE_IFELSE( + [int some_function() { + int a = 3; + return (int)__builtin_expect(a, 3); + }], + [cc_cv_func_expect=yes], + [cc_cv_func_expect=no]) + CFLAGS="$ac_save_CFLAGS" + ]) + + AS_IF([test "x$cc_cv_func_expect" = "xyes"], + [AC_DEFINE([SUPPORT__BUILTIN_EXPECT], 1, + [Define this if the compiler supports __builtin_expect() function]) + $1], + [$2]) +]) + +AC_DEFUN([CC_ATTRIBUTE_ALIGNED], [ + AC_REQUIRE([CC_CHECK_WERROR]) + AC_CACHE_CHECK([highest __attribute__ ((aligned ())) supported], + [cc_cv_attribute_aligned], + [ac_save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $cc_cv_werror" + for cc_attribute_align_try in 64 32 16 8 4 2; do + AC_COMPILE_IFELSE([ + int main() { + static char c __attribute__ ((aligned($cc_attribute_align_try))) = 0; + return c; + }], [cc_cv_attribute_aligned=$cc_attribute_align_try; break]) + done + CFLAGS="$ac_save_CFLAGS" + ]) + + if test "x$cc_cv_attribute_aligned" != "x"; then + AC_DEFINE_UNQUOTED([ATTRIBUTE_ALIGNED_MAX], [$cc_cv_attribute_aligned], + [Define the highest alignment supported]) + fi +]) diff --git a/m4/zp_lynx_doc.m4 b/m4/zp_lynx_doc.m4 new file mode 100644 index 0000000..955a6ca --- /dev/null +++ b/m4/zp_lynx_doc.m4 @@ -0,0 +1,24 @@ +dnl Macro for enabling LYNX-based documentation generation + +AC_DEFUN([ZP_LYNX_DOC], [ + AC_ARG_ENABLE(lynx, + AS_HELP_STRING([--disable-lynx], + [Turn off lynx usage for documentation generation]),, + [enable_lynx=yes]) + + case "${enable_lynx}" in + yes) + AC_CHECK_PROG(have_lynx, lynx, yes, no) + + if test x$have_lynx = xno ; then + AC_MSG_WARN([*** lynx not found, plain text README will not be built ***]) + fi + ;; + no) + have_lynx=no ;; + *) + AC_MSG_ERROR(bad value ${enableval} for --disable-lynx) ;; + esac + + AM_CONDITIONAL([USE_LYNX], [test "x$have_lynx" = xyes]) +]) diff --git a/pkgconfig/libdaemon-uninstalled.pc.in b/pkgconfig/libdaemon-uninstalled.pc.in new file mode 100644 index 0000000..3ceb71b --- /dev/null +++ b/pkgconfig/libdaemon-uninstalled.pc.in @@ -0,0 +1,8 @@ +libdir=@abs_top_builddir@/libdaemon/.libs +includedir=@abs_top_srcdir@ + +Name: libdaemon +Description: a lightweight C library that eases the writing of UNIX daemons +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -R${libdir} -ldaemon +Cflags: -D_REENTRANT -I${includedir} diff --git a/pkgconfig/libdaemon.pc.in b/pkgconfig/libdaemon.pc.in new file mode 100644 index 0000000..835dcf1 --- /dev/null +++ b/pkgconfig/libdaemon.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=${prefix} +libdir=@libdir@ +includedir=${prefix}/include + +Name: libdaemon +Description: a lightweight C library that eases the writing of UNIX daemons +Version: @PACKAGE_VERSION@ +Libs: -L${libdir} -ldaemon +Cflags: -D_REENTRANT -I${includedir} |