13fdc90d75cac0f989a311faaa4c890ffa032f9b
[rrdd.git] / src / rrdd.c
1 /**
2  * collectd - src/rrdd.c
3  * Copyright (C) 2008 Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; only version 2 of the License is applicable.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
17  *
18  * Authors:
19  *   Florian octo Forster <octo at verplant.org>
20  **/
21
22 #include "rrdd.h"
23
24 /*
25  * Types
26  */
27 struct listen_socket_s
28 {
29   int fd;
30   char path[PATH_MAX + 1];
31 };
32 typedef struct listen_socket_s listen_socket_t;
33
34 /*
35  * Variables
36  */
37 static listen_socket_t *listen_fds = NULL;
38 static size_t listen_fds_num = 0;
39
40 static int do_shutdown = 0;
41
42 static pthread_t queue_thread;
43
44 /* 
45  * Functions
46  */
47 static void *queue_thread_main (void *args) /* {{{ */
48 {
49   while (do_shutdown == 0)
50   {
51     syslog (LOG_DEBUG, "queue_thread_main: Just woke up.");
52     sleep (1);
53   } /* while (do_shutdown == 0) */
54
55   syslog (LOG_DEBUG, "queue_thread_main: Exiting.");
56
57   return (NULL);
58 } /* }}} void *queue_thread_main */
59
60 static void sig_int_handler (int signal) /* {{{ */
61 {
62   do_shutdown++;
63 } /* }}} void sig_int_handler */
64
65 static void sig_term_handler (int signal) /* {{{ */
66 {
67   do_shutdown++;
68 } /* }}} void sig_term_handler */
69
70 static int open_listen_socket (const char *path) /* {{{ */
71 {
72   int fd;
73   struct sockaddr_un sa;
74   listen_socket_t *temp;
75   int status;
76
77   temp = (listen_socket_t *) realloc (listen_fds,
78       sizeof (listen_fds[0]) * (listen_fds_num + 1));
79   if (temp == NULL)
80   {
81     syslog (LOG_ERR, "open_listen_socket: realloc failed.\n");
82     return (-1);
83   }
84   listen_fds = temp;
85   memset (listen_fds + listen_fds_num, 0, sizeof (listen_fds[0]));
86
87   fd = socket (PF_UNIX, SOCK_STREAM, /* protocol = */ 0);
88   if (fd < 0)
89   {
90     syslog (LOG_ERR, "open_listen_socket: socket(2) failed.\n");
91     return (-1);
92   }
93
94   memset (&sa, 0, sizeof (sa));
95   sa.sun_family = AF_UNIX;
96   strncpy (sa.sun_path, path, sizeof (sa.sun_path) - 1);
97
98   status = bind (fd, (struct sockaddr *) &sa, sizeof (sa));
99   if (status != 0)
100   {
101     syslog (LOG_ERR, "open_listen_socket: bind(2) failed.\n");
102     close (fd);
103     return (-1);
104   }
105   
106   listen_fds[listen_fds_num].fd = fd;
107   strncpy (listen_fds[listen_fds_num].path, path,
108       sizeof (listen_fds[listen_fds_num].path) - 1);
109   listen_fds_num++;
110
111   return (0);
112 } /* }}} int open_listen_socket */
113
114 static int close_listen_sockets (void) /* {{{ */
115 {
116   size_t i;
117
118   for (i = 0; i < listen_fds_num; i++)
119   {
120     close (listen_fds[i].fd);
121     unlink (listen_fds[i].path);
122   }
123
124   free (listen_fds);
125   listen_fds = NULL;
126   listen_fds_num = 0;
127
128   return (0);
129 } /* }}} int close_listen_sockets */
130
131 static void *listen_thread_main (void *args) /* {{{ */
132 {
133   char buffer[4096];
134   int status;
135
136   status = open_listen_socket (RRDD_SOCK_PATH);
137   if (status != 0)
138   {
139     syslog (LOG_ERR, "listen_thread_main: open_listen_socket failed.");
140     return (NULL);
141   }
142
143   while (do_shutdown == 0)
144   {
145     syslog (LOG_DEBUG, "listen_thread_main: Just woke up.");
146
147     status = recv (listen_fds[0].fd, buffer, sizeof (buffer),
148         /* flags = */ 0);
149     if (status == 0)
150     {
151       continue;
152     }
153     else if (status < 0)
154     {
155       if (errno == EINTR)
156         continue;
157       else
158       {
159         syslog (LOG_ERR, "listen_thread_main: recv failed.");
160         continue;
161       }
162     }
163
164     syslog (LOG_DEBUG, "listen_thread_main: Received %i bytes.\n", status);
165   } /* while (do_shutdown == 0) */
166
167   close_listen_sockets ();
168
169   syslog (LOG_DEBUG, "listen_thread_main: Exiting.");
170
171   return (NULL);
172 } /* }}} void *listen_thread_main */
173
174 static int daemonize (void) /* {{{ */
175 {
176   pid_t child;
177   int status;
178
179   child = fork ();
180   if (child < 0)
181   {
182     fprintf (stderr, "daemonize: fork(2) failed.\n");
183     return (-1);
184   }
185   else if (child > 0)
186   {
187     return (1);
188   }
189
190   /* Change into the /tmp directory. */
191   chdir ("/tmp");
192
193   /* Become session leader */
194   setsid ();
195
196   /* Open the first three file descriptors to /dev/null */
197   close (2);
198   close (1);
199   close (0);
200
201   open ("/dev/null", O_RDWR);
202   dup (0);
203   dup (0);
204
205   {
206     struct sigaction sa;
207
208     memset (&sa, 0, sizeof (sa));
209     sa.sa_handler = sig_int_handler;
210     sigaction (SIGINT, &sa, NULL);
211
212     memset (&sa, 0, sizeof (sa));
213     sa.sa_handler = sig_term_handler;
214     sigaction (SIGINT, &sa, NULL);
215   }
216
217   openlog ("rrdd", LOG_PID, LOG_DAEMON);
218
219   memset (&queue_thread, 0, sizeof (queue_thread));
220   status = pthread_create (&queue_thread, /* attr = */ NULL,
221       queue_thread_main, /* args = */ NULL);
222   if (status != 0)
223   {
224     syslog (LOG_ERR, "daemonize: pthread_create failed.");
225     return (-1);
226   }
227
228   return (0);
229 } /* }}} int daemonize */
230
231 static int cleanup (void) /* {{{ */
232 {
233   do_shutdown++;
234
235   pthread_join (queue_thread, /* return = */ NULL);
236
237   closelog ();
238
239   return (0);
240 } /* }}} int cleanup */
241
242 int main (int argc, char **argv)
243 {
244   int status;
245
246   printf ("%s by Florian Forster, Version %s\n",
247       PACKAGE_NAME, PACKAGE_VERSION);
248
249   status = daemonize ();
250   if (status == 1)
251   {
252     struct sigaction sigchld;
253
254     memset (&sigchld, 0, sizeof (sigchld));
255     sigchld.sa_handler = SIG_IGN;
256     sigaction (SIGCHLD, &sigchld, NULL);
257
258     return (0);
259   }
260   else if (status != 0)
261   {
262     fprintf (stderr, "daemonize failed, exiting.\n");
263     return (1);
264   }
265
266   listen_thread_main (NULL);
267
268   cleanup ();
269
270   return (0);
271 } /* int main */
272
273 /*
274  * vim: set sw=2 sts=2 ts=8 et fdm=marker :
275  */