/*
 *
 *
 *    daemon.h
 *
 *    Header file for daemon class and support classes.
 *
 *    =========================================================================
 *    
 *    Copyright (C) 1999-2003 by Matt Roberts, KK5JY.
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation; either
 *    version 2.1 of the License, or (at your option) any later version.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *    =========================================================================
 *
 *    The daemon class enables a program to 'daemonize' or load and run in
 *    the background.  To automatically daemonize an application, simply
 *    declare daemon to be a public base class of your application class,
 *    and the application class will daemonize upon instantiation.
 *
 *    Optionally, a boolean value of 'false' can be passed to the daemon
 *    base class, causing it to wait for an explicit 'daemonize' call to
 *    fork off the daemon process.
 *
 *
 */


#ifndef __DAEMON_H
    #define __DAEMON_H

    // System includes
    #include <sys/types.h>
    #include <sys/stat.h>

    // Standard Unix includes
    #include <fcntl.h>
    #include <unistd.h>
    #include <errno.h>

    // Standard C/C++ includes
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <exception>


	namespace my {

		/*
		 *
		 *    class daemon
		 *
		 */

		class daemon {
			public:
				class exception : public std::exception {
					private:
						const std::string tde_what;
						const daemon *tde_obj;
						const int tde_error;

					public:
						exception (const daemon *object, const int err_no)
							: tde_what(strerror(err_no)), tde_obj(object), tde_error(err_no) { /* noop */ };
						exception (const daemon *object, const std::string &e_what)
							: tde_what(e_what), tde_obj(object), tde_error(0) { /* noop */ };
						~exception (void) throw() { /* noop */ };

						int errnum (void) const { return tde_error; };
						const char *what (void) const throw() { return tde_what.c_str(); };
				};

				enum deference {
					defer,
					no_defer
				};

			private:
				pid_t pid;
				std::string rootdir;
				bool parent;

			public:
				/*
				 *   constructors:
				 * 
				 *   A value of 'true' passed to the 'defer' argument will cause the
				 *   constructor to defer daemonization of the process.  If this is
				 *   the case, then the user process must call 'daemonize()' explicitly
				 *   to start daemonization.  The default is for the daemon to detach
				 *   at constructor startup.
				 * 
				 *   The value passed to the 'rd' parameter specifies the directory to
				 *   chdir() to before the daemonize() call returns to the child.
				 * 
				 */

				daemon (void);
				daemon (bool q_defer);
				daemon (const deference q_defer);
				daemon (const std::string &rd);
				daemon (const std::string &rd, bool defer);
				daemon (const std::string &rd, const deference q_defer);
				virtual ~daemon (void) { /* noop */ };

				/* these functions returns the pid of the child, either to the child,
				   or the parent */
				operator int() { return pid; };
				int id (void) { return pid; };


				/* these functions will tell the calling process who it is */
				bool is_parent (void) { return parent; };
				bool is_child  (void) { return !parent; };

				/* this function is called by the parent process before the parent exits */
				virtual int exit_action (pid_t child_pid) { return 0; };

				/* here's the meat of the class.  This detaches the current process. */
				void daemonize (bool doreturn = false);
		};
	}

#endif /* __DAEMON_H */
