aboutsummaryrefslogtreecommitdiffstats
path: root/daemon.c
blob: e7b9214bb218270560163f4528573404d4bf0edd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*
 * daemon.c -- turn a process into a daemon under POSIX, SYSV, BSD.
 *
 * For license terms, see the file COPYING in this directory.
 */

#include "config.h"

#include <stdio.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#else /* !HAVE_FCNTL_H */
#ifdef HAVE_SYS_FCNTL_H
#include <sys/fcntl.h>
#endif /* HAVE_SYS_FCNTL_H */
#endif /* !HAVE_FCNTL_H */
#include <sys/stat.h>	/* get umask(2) prototyped */

#if defined(HAVE_UNISTD_H)
#include <unistd.h>
#endif

#if defined(STDC_HEADERS)
#include <stdlib.h>
#endif

#if defined(QNX)
#include <unix.h>
#endif

#if !defined(HAVE_SETSID) && defined(SIGTSTP)
#if defined(HAVE_TERMIOS_H)
#  include <termios.h>		/* for TIOCNOTTY under Linux */
#endif

#if !defined(TIOCNOTTY) && defined(HAVE_SGTTY_H)
#  include <sgtty.h>		/* for TIOCNOTTY under NEXTSTEP */
#endif
#endif /* !defined(HAVE_SETSID) && defined(SIGTSTP) */

/* BSD portability hack */
#if !defined(SIGCHLD) && defined(SIGCLD)
#define SIGCHLD	SIGCLD
#endif

#include "fetchmail.h"
#include "tunable.h"

RETSIGTYPE
sigchld_handler (int sig)
/* process SIGCHLD to obtain the exit code of the terminating process */
{
    pid_t pid;

#if 	defined(HAVE_WAITPID)				/* the POSIX way */
    int status;

    while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
	continue; /* swallow 'em up. */
#elif 	defined(HAVE_WAIT3)				/* the BSD way */
#if defined(HAVE_UNION_WAIT) && !defined(__FreeBSD__)
    union wait status;
#else
    int status;
#endif

    while ((pid = wait3(&status, WNOHANG, 0)) > 0)
	continue; /* swallow 'em up. */
#else	/* Zooks! Nothing to do but wait(), and hope we don't block... */
    int status;

    wait(&status);
#endif
}

int
daemonize (const char *logfile, void (*termhook)(int))
/* detach from control TTY, become process group leader, catch SIGCHLD */
{
  int fd;
  pid_t childpid;
  RETSIGTYPE sigchld_handler();

  /* if we are started by init (process 1) via /etc/inittab we needn't 
     bother to detach from our process group context */

  if (getppid() == 1) 
    goto nottyDetach;

  /* Ignore BSD terminal stop signals */
#ifdef 	SIGTTOU
  signal(SIGTTOU, SIG_IGN);
#endif
#ifdef	SIGTTIN
  signal(SIGTTIN, SIG_IGN);
#endif
#ifdef	SIGTSTP
  signal(SIGTSTP, SIG_IGN);
#endif

  /* In case we were not started in the background, fork and let
     the parent exit.  Guarantees that the child is not a process
     group leader */

  if ((childpid = fork()) < 0) {
    error(0, errno, "fork");
    return(PS_IOERR);
  }
  else if (childpid > 0) 
    exit(0);  /* parent */

  
  /* Make ourselves the leader of a new process group with no
     controlling terminal */

#if	defined(HAVE_SETSID)		/* POSIX */
  /* POSIX makes this soooo easy to do */
  if (setsid() < 0) {
    error(0, errno, "setsid");
    return(PS_IOERR);
  }
#elif	defined(SIGTSTP)		/* BSD */
  /* change process group */
#ifndef __EMX__
  setpgrp(0, getpid());
#endif
  /* lose controlling tty */
  if ((fd = open("/dev/tty", O_RDWR)) >= 0) {
    ioctl(fd, TIOCNOTTY, (char *) 0);
    close(fd);
  }
#else					/* SVR3 and older */
  /* change process group */
#ifndef __EMX__
  setpgrp();
#endif
  
  /* lose controlling tty */
  signal(SIGHUP, SIG_IGN);
  if ((childpid = fork()) < 0) {
    error(0, errno, "fork");
    return(PS_IOERR);
  }
  else if (childpid > 0) {
    exit(0); 	/* parent */
  }
#endif

nottyDetach:

  /* Close any/all open file descriptors */
#if 	defined(HAVE_GETDTABLESIZE)
  for (fd = getdtablesize()-1;  fd >= 0;  fd--)
#elif	defined(NOFILE)
  for (fd = NOFILE-1;  fd >= 0;  fd--)
#else		/* make an educated guess */
  for (fd = 19;  fd >= 0;  fd--)
#endif
  {
    close(fd);
  }

  /* Reopen stdin descriptor on /dev/null */
  if ((fd = open("/dev/null", O_RDWR)) < 0) {   /* stdin */
    error(0, errno, "open: /dev/null");
    return(PS_IOERR);
  }

  if (logfile)
    fd = open(logfile, O_CREAT|O_WRONLY|O_APPEND, 0666);	/* stdout */
  else
    if (dup(fd) < 0) {				/* stdout */
      error(0, errno, "dup");
      return(PS_IOERR);
    }
  if (dup(fd) < 0) {				/* stderr */
    error(0, errno, "dup");
    return(PS_IOERR);
  }

  /* move to root directory, so we don't prevent filesystem unmounts */
  chdir("/");

  /* set our umask to something reasonable (we hope) */
#if defined(DEF_UMASK)
  umask(DEF_UMASK);
#else
  umask(022);
#endif

  /* set up to catch child process termination signals */ 
  signal(SIGCHLD, sigchld_handler); 
#if defined(SIGPWR)
  signal(SIGPWR, sigchld_handler); 
#endif

  return(0);
}

/* daemon.c ends here */
n class="p">> </ul> <h2>2.0 and earlier versions:</h2> <ul> <li>Support POP2, APOP, RPOP, IMAP2, IMAP2bis, IMAP3, IMAP4, IMAP4rev1. .</li> <li>Support for Kerberos V4 user authentication (either MIT or Cygnus).</li> <li>Host is auto-probed for a working server if no protocol is specified for the connection. Thus you don't need to know what servers are running on your mail host in advance; the verbose option will tell you which one succeeds.</li> <li>Delivery via SMTP to the client machine's port 25. This means the retrieved mail automatically goes to the system default MDA as if it were normal sender-initiated SMTP mail.</li> <li>Configurable timeout to detect if server connection is dropped.</li> <li>Support for retrieving and forwarding from multi-drop mailboxes that is guaranteed not to cause mail loops.</li> <li>Large user community -- fetchmail has a large user base (the author's beta list includes well over two hundred people). This means feedback is rapid, bugs get found and fixed rapidly.</li> <li>Carefully written, comprehensive and up-to-date man page describing not only modes of operation but also how to diagnose the most common kinds of problems and what to do about deficient servers.</li> <li>Rugged, simple, and well-tested code -- the author relies on it every day and it has never lost mail, not even in experimental versions. (In the project's entire history there has only been one recorded instance of lost mail, and that was due to a quirk in some Microsoft code.)</li> <li>Strict conformance to relevant RFCs and good debugging options. You could use fetchmail to test and debug server implementatations.</li> <li>For anybody who cares, fetchmail is Y2K safe.</li> </ul> <h2>Features in common with other remote-mail retrieval programs:</h2> The other programs I have checked include fetchpop1.9, PopTart-0.9.3, get-mail, gwpop, pimp-1.0, pop-perl5-1.2, popc, popmail-1.6 and upop. <ul> <li>Support for POP3.</li> <li>Easy control via command line or free-format run control file.</li> <li>Daemon mode -- fetchmail can be run in background to poll one or more hosts at a specified interval.</li> <li>From:, To:, Cc:, and Reply-To: headers are rewritten so that usernames relative to the fetchmail host become fully-qualified Internet addresses. This enables replies to work correctly. (Would be unique to fetchmail if I hadn't added it to fetchpop.)</li> <li>Message and header processing are 8-bit clean.</li> </ul> <hr /> <table width="100%" cellpadding="0" summary="Canned page footer"> <tr> <td width="30%">Back to <a href="index.html">Fetchmail Home Page</a></td> <td width="30%" align="center">To <a href="/~esr/sitemap.html">Site Map</a></td> <td width="30%" align="right">$Date: 2002/09/09 13:59:55 $</td> </tr> </table> <br clear="left" /> <address>Eric S. Raymond <a href="mailto:esr@thyrsus.com">&lt;esr@snark.thyrsus.com&gt;</a></address> </body> </html>