1 /*
2  * serveez.c - main module
3  *
4  * Copyright (C) 2011-2013 Thien-Thi Nguyen
5  * Copyright (C) 2000, 2001, 2003 Stefan Jahn <stefan@lkcc.org>
6  * Copyright (C) 2000 Raimund Jacob <raimi@lkcc.org>
7  * Copyright (C) 1999 Martin Grabmueller <mgrabmue@cs.tu-berlin.de>
8  *
9  * This is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 3, or (at your option)
12  * any later version.
13  *
14  * This software is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this package.  If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include "config.h"
24 
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <time.h>
29 #include <errno.h>
30 #include <libguile.h>
31 #if HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
34 
35 #include "networking-headers.h"
36 #include "libserveez.h"
37 #include "misc-macros.h"
38 #include "cfgfile.h"
39 #include "option.h"
40 #include "guile-api.h"
41 #include "guile.h"
42 #include "guile-server.h"
43 #include "unused.h"
44 
45 /* Command line option structure.  */
46 option_t *options = NULL;
47 
48 /* This is for ‘serveez-nuke’ to set.  */
49 int global_exit_value;
50 
51 /* Our private launch pad.  */
52 void
guile_launch_pad(void * closure,int argc,char ** argv)53 guile_launch_pad (void *closure, int argc, char **argv)
54 {
55   void (* entry) (int, char **) = (void (*) (int, char **)) closure;
56 
57   global_exit_value = EXIT_SUCCESS;
58   entry (argc, argv);
59   exit (global_exit_value);
60 }
61 
62 #if ENABLE_CONTROL_PROTO
63 extern char *control_protocol_password;
64 #endif
65 
66 /*
67  * This is the entry point for the guile interface.
68  */
69 static void
guile_entry(UNUSED int argc,UNUSED char ** argv)70 guile_entry (UNUSED int argc, UNUSED char **argv)
71 {
72   /* Detect operating system.  */
73   svz_log (SVZ_LOG_NOTICE, "%s\n", svz_sys_version ());
74 
75   /* Start loading the configuration file.  */
76   if (guile_load_config (options->cfgfile) == -1)
77     {
78       svz_log (SVZ_LOG_ERROR, "error loading config file\n");
79       exit (3);
80     }
81 
82   /*
83    * Make command line arguments overriding the configuration
84    * file settings.
85    */
86   if (options->verbosity != -1)
87     SVZ_RUNPARM_X (VERBOSITY, options->verbosity);
88 
89   if (options->sockets != -1)
90     SVZ_RUNPARM_X (MAX_SOCKETS, options->sockets);
91 
92 #if ENABLE_CONTROL_PROTO
93   if (options->pass)
94     {
95       svz_free (control_protocol_password);
96       /* Transfer: set destination and reset source.  */
97       control_protocol_password = options->pass;
98       options->pass = NULL;
99     }
100 #endif
101 
102 #if ENABLE_DEBUG
103   svz_log (SVZ_LOG_NOTICE, "serveez starting, debugging enabled\n");
104 #endif /* ENABLE_DEBUG */
105 
106   svz_openfiles (SVZ_RUNPARM (MAX_SOCKETS));
107   svz_log (SVZ_LOG_NOTICE, "using %d socket descriptors\n",
108            SVZ_RUNPARM (MAX_SOCKETS));
109 
110   /* Startup the internal coservers here.  */
111   if (svz_updn_all_coservers (options->coservers) == -1)
112     {
113       exit (4);
114     }
115 
116   /* Initialize server instances.  */
117   if (svz_updn_all_servers (1) == -1)
118     {
119       exit (6);
120     }
121 
122   svz_loop ();
123 
124   /* Run the finalizers.  */
125   svz_updn_all_servers (0);
126 
127   /* Disconnect the previously invoked internal coservers.  */
128   svz_log (SVZ_LOG_NOTICE, "destroying internal coservers\n");
129   svz_updn_all_coservers (0);
130 
131 #if ENABLE_GUILE_SERVER
132   guile_server_finalize ();
133 #endif /* ENABLE_GUILE_SERVER */
134 
135 #if ENABLE_CONTROL_PROTO
136   svz_free_and_zero (control_protocol_password);
137 #endif
138   svz_halt ();
139 
140 #if ENABLE_DEBUG
141   {
142     size_t cur[2];
143 
144     svz_get_curalloc (cur);
145     svz_log (SVZ_LOG_DEBUG, "%d byte(s) of memory in %d block(s) wasted\n",
146              cur[0], cur[1]);
147   }
148 
149 #if DEBUG_MEMORY_LEAKS
150   svz_heap ();
151 #endif
152 #endif /* ENABLE_DEBUG */
153 
154 #ifdef __MINGW32__
155   if (options->daemon)
156     {
157       svz_windoze_daemon_control (NULL);
158     }
159 #endif
160 
161   svz_log (SVZ_LOG_NOTICE, "serveez terminating\n");
162 
163   /* FIXME: Serveez leaks because of a open logfile handle.  */
164   if (options->loghandle != stderr)
165     svz_fclose (options->loghandle);
166 }
167 
168 #if 0
169 static int
170 dump_servertype (const svz_servertype_t *stype, void *closure)
171 {
172   int *num = closure;
173   svz_config_prototype_t *prototype = &stype->config_prototype;
174   int i;
175 
176   printf ("[%d] - %s\n"
177           "\t`detect_proto' at %p\n"
178           "\t`connect_socket' at %p\n",
179           (*num)++, stype->description,
180           (void *) stype->detect_proto,
181           (void *) stype->connect_socket);
182 
183   if (prototype->start != NULL)
184     {
185       printf ("  configuration prototype %s (%d byte at %p): \n",
186               prototype->description, prototype->size, prototype->start);
187 
188       for (i = 0; prototype->items[i].type != SVZ_ITEM_END; i++)
189         {
190           long offset = (char *) prototype->items[i].address -
191             (char *) prototype->start;
192 
193           printf ("   variable `%s' at offset %ld, %sdefaultable: ",
194                   prototype->items[i].name, offset,
195                   prototype->items[i].defaultable ? "" : "not ");
196 
197           switch (prototype->items[i].type)
198             {
199             case SVZ_ITEM_BOOL:
200               printf ("bool\n");
201               break;
202             case SVZ_ITEM_INT:
203               printf ("int\n");
204               break;
205             case SVZ_ITEM_INTARRAY:
206               printf ("int array\n");
207               break;
208             case SVZ_ITEM_STR:
209               printf ("string\n");
210               break;
211             case SVZ_ITEM_STRARRAY:
212               printf ("string array\n");
213               break;
214             case SVZ_ITEM_HASH:
215               printf ("hash\n");
216               break;
217             case SVZ_ITEM_PORTCFG:
218               printf ("port configuration\n");
219               break;
220             default:
221               printf ("invalid\n");
222             }
223         }
224     }
225   else
226     {
227       printf ("  no configuration option\n");
228     }
229   return 0;
230 }
231 #endif
232 
233 /*
234  * Main entry point.
235  */
236 int
main(int argc,char * argv[])237 main (int argc, char *argv[])
238 {
239   /* Initialize the the core library.  */
240   svz_boot (argv[0]);
241   svz_envblock_setup ();
242 
243   /* Handle command line arguments.  */
244   options = handle_options (argc, argv);
245 
246   /* Send all logging messages to the log handle.  */
247   if (options->logfile && options->logfile[0])
248     options->loghandle = svz_fopen (options->logfile, "w");
249   if (!options->loghandle)
250     options->loghandle = stderr;
251   svz_log_setfile (options->loghandle);
252 
253   /* Setup verbosity once.  */
254   if (options->verbosity != -1)
255     SVZ_RUNPARM_X (VERBOSITY, options->verbosity);
256 
257   /* Start as daemon, not as foreground application.  */
258   if (options->daemon)
259     {
260 #ifndef __MINGW32__
261       int pid;
262 
263       if ((pid = fork ()) == -1)
264         {
265           svz_log_sys_error ("fork");
266           exit (EXIT_FAILURE);
267         }
268       else if (pid != 0)
269         {
270           exit (EXIT_SUCCESS);
271         }
272       /* Close the log file if necessary.  */
273       if (options->loghandle == stderr)
274         svz_log_setfile (NULL);
275       /* Close stdin, stdout and stderr.  */
276       if (isatty (fileno (stdin)))
277         close (fileno (stdin));
278       if (isatty (fileno (stdout)))
279         close (fileno (stdout));
280       if (isatty (fileno (stderr)))
281         close (fileno (stderr));
282 #else /* __MINGW32__ */
283       if (svz_windoze_daemon_control (argv[0]) == -1)
284         exit (EXIT_FAILURE);
285       if (options->loghandle == stderr)
286         svz_log_setfile (NULL);
287       svz_closehandle (GetStdHandle (STD_INPUT_HANDLE));
288       svz_closehandle (GetStdHandle (STD_OUTPUT_HANDLE));
289       svz_closehandle (GetStdHandle (STD_ERROR_HANDLE));
290 #endif /* __MINGW32__ */
291     }
292 
293   /* Initialize the static server types.  */
294   init_server_definitions ();
295 #if 0
296   {
297     int num = 0;
298 
299     svz_foreach_servertype (dump_servertype, &num);
300   }
301 #endif
302 
303   /* Enter the main guile function.  */
304   scm_boot_guile (argc, argv, guile_launch_pad, (void *) guile_entry);
305   /* Never reached.  */
306   return 0;
307 }
308