/*
**  OSSP lmtp2nntp - Mail to News Gateway
**  Copyright (c) 2001-2003 Ralf S. Engelschall <rse@engelschall.com>
**  Copyright (c) 2001-2003 The OSSP Project <http://www.ossp.org/>
**  Copyright (c) 2001-2003 Cable & Wireless Germany <http://www.cw.com/de/>
**
**  This file is part of OSSP lmtp2nntp, an LMTP speaking local
**  mailer which forwards mails as Usenet news articles via NNTP.
**  It can be found at http://www.ossp.org/pkg/tool/lmtp2nntp/.
**
**  This program is free software; you can redistribute it and/or
**  modify it under the terms of the GNU General Public  License
**  as published by the Free Software Foundation; either version
**  2.0 of the License, or (at your option) any later version.
**
**  This program 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
**  General Public License for more details.
**
**  You should have received a copy of the GNU General Public License
**  along with this file; if not, write to the Free Software
**  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
**  USA, or contact the OSSP project <ossp@ossp.org>.
**
**  lmtp2nntp_daemon.c: daemonize current process
*/

#include "config.h"

#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#ifdef HAVE_TERMIOS_H
#include <sys/termios.h>
#endif
#if defined(HAVE_DMALLOC_H) && defined(WITH_DMALLOC)
#include "dmalloc.h"
#endif

#include "lmtp2nntp_daemon.h"

/*
 *  See "Unix Programming Frequently Asked Questions":
 *  http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC10
 */

int daemonize(void)
{
    int fd;
    int rc;

    /*
     * if we are started from init,
     * no need to become daemon.
     */
    if (getppid() == 1)
        return 0;

    /*
     * Ignore tty related signals
     */
#ifdef  SIGTTOU
    signal(SIGTTOU, SIG_IGN);
#endif
#ifdef  SIGTTIN
    signal(SIGTTIN, SIG_IGN);
#endif
#ifdef  SIGTSTP
    signal(SIGTSTP, SIG_IGN);
#endif

    /*
     * fork so the parent can exit, this returns control to the command line
     * or shell invoking your program. This step is required so that the new
     * process is guaranteed not to be a process group leader (The next step,
     * setsid, would fail if you're a process group leader).
     */
    rc = fork();
    switch (rc) {
        case -1: return -1;
        case 0:  break;
        default: _exit(0); /* exit original process */
    }

    /*
     * setsid to become a process group and session group leader. Since a
     * controlling terminal is associated with a session, and this new session
     * has not yet acquired a controlling terminal our process now has no
     * controlling terminal, which is a Good Thing for daemons.
     */
#ifdef HAVE_SETSID
    if (setsid() == -1)
        return -1;
#else
    if (setpgid(0, getpid()) == -1)
        return -1;
#ifndef _PATH_TTY
#define _PATH_TTY "/dev/tty"
#endif
    if ((fd = open(_PATH_TTY, O_RDWR)) == -1)
        return -1;
    ioctl(fd, TIOCNOTTY, NULL);
    close(fd);
#endif

    /*
     * fork again so the parent, (the session group leader), can exit. This
     * means that we, as a non-session group leader, can never regain a
     * controlling terminal.
     */
    rc = fork();
    switch (rc) {
        case -1: return -1;
        case 0:  break;
        default: _exit(0); /* exit original process */
    }

    /*
     * chdir("/") to ensure that our process doesn't keep any directory in
     * use. Failure to do this could make it so that an administrator couldn't
     * unmount a filesystem, because it was our current directory.
     * [Equivalently, we could change to any directory containing files
     * important to the daemon's operation.]
     */
    chdir("/");

    /*
     * give us complete control over the permissions of anything we write. We
     * don't know what umask we may have inherited.  [This step is optional]
     */
    umask(0);

    /*
     * close fds 0, 1, and 2. This releases the standard in, out, and error we
     * inherited from our parent process. We have no way of knowing where
     * these fds might have been redirected to.
     */
    if ((fd = open("/dev/null", O_RDWR, 0)) != -1) {
        dup2(fd, STDIN_FILENO);
        dup2(fd, STDOUT_FILENO);
        dup2(fd, STDERR_FILENO);
        if (fd > 2)
            close(fd);
    }
    return 0;
}

