Add to git.
[rws.git] / main.c
1 /* RWS main program.
2  * - by Richard W.M. Jones <rich@annexia.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * $Id: main.c,v 1.16 2002/11/27 18:45:23 rich Exp $
19  */
20
21 #include "config.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #ifdef HAVE_UNISTD_H
27 #include <unistd.h>
28 #endif
29
30 #ifdef HAVE_SIGNAL_H
31 #include <signal.h>
32 #endif
33
34 #ifdef HAVE_STRING_H
35 #include <string.h>
36 #endif
37
38 #ifdef HAVE_SYS_TYPES_H
39 #include <sys/types.h>
40 #endif
41
42 #ifdef HAVE_SYS_WAIT_H
43 #include <sys/wait.h>
44 #endif
45
46 #ifdef HAVE_FCNTL_H
47 #include <fcntl.h>
48 #endif
49
50 #include <pool.h>
51 #include <pstring.h>
52 #include <pre.h>
53
54 #include <pthr_http.h>
55 #include <pthr_server.h>
56
57 #include "cfg.h"
58 #include "file.h"
59 #include "exec_so.h"
60 #include "mime_types.h"
61 #include "process_rq.h"
62 #include "rewrite.h"
63 #include "re.h"
64
65 static void startup (int argc, char *argv[]);
66 static void start_thread (int sock, void *data);
67 static void catch_reload_signal (int sig);
68 static void catch_quit_signal (int sig);
69 static void catch_child_signal (int sig);
70 static void reload_config (void);
71
72 const char *config_path = "/etc/rws";
73 FILE *access_log;
74
75 const pcre *re_alias_start,
76   *re_alias_end,
77   *re_begin,
78   *re_conf_line,
79   *re_ext,
80   *re_icon,
81   *re_so,
82   *re_ws,
83   *re_comma;
84
85 int
86 main (int argc, char *argv[])
87 {
88   const char *user, *name, *stderr_file;
89   int c, stack_size;
90   struct sigaction sa;
91   int foreground = 0;
92   int debug = 0;
93
94   /* Initialise various shared regular expressions. */
95   re_alias_start = precomp (global_pool, "^alias[[:space:]]+(.*)$", 0);
96   re_alias_end = precomp (global_pool, "^end[[:space:]]+alias$", 0);
97   re_begin = precomp (global_pool, "^begin[[:space:]]+(.*):?[[:space:]]*$", 0);
98   re_conf_line = precomp (global_pool, "^(.*):[[:space:]]*(.*)?$", 0);
99   re_ext = precomp (global_pool, "\\.([^.]+)$", 0);
100   re_icon = precomp (global_pool,
101     "([^[:space:]]+)[[:space:]]+([0-9]+)x([0-9]+)[[:space:]]+\"(.*)\"", 0);
102   re_so = precomp (global_pool, "\\.so$", 0);
103   re_ws = precomp (global_pool, "[ \t]+", 0);
104   re_comma = precomp (global_pool, "[,;]+", 0);
105
106   while ((c = getopt (argc, argv, "C:p:a:fd")) != -1)
107     {
108       switch (c)
109         {
110         case 'p':
111           /* ignore */
112           break;
113  
114         case 'a':
115           /* ignore */
116           break;
117
118         case 'C':
119           config_path = optarg;
120           break;
121
122         case 'f':
123           foreground = 1;
124           break;
125  
126         case 'd':
127           debug = 1;
128           break;
129
130         default:
131           fprintf (stderr, "usage: rws [-d] [-f] [-a address] [-p port] [-C configpath]\n");
132           exit (1);
133         }
134     }
135
136   /* Read configuration file. Do this early so we have configuration
137    * data available for other initializations.
138    */
139   reload_config ();
140
141   /* Change the thread stack size? */
142   stack_size = cfg_get_int (0, 0, "stack size", 0);
143   if (stack_size)
144     pseudothread_set_stack_size (stack_size * 1024);
145
146   /* Initialize the file cache. */
147   file_init ();
148
149   /* Initialize the shared object script cache. */
150   exec_so_init ();
151
152   /* Intercept signals. */
153   memset (&sa, 0, sizeof sa);
154   sa.sa_handler = catch_reload_signal;
155   sa.sa_flags = SA_RESTART;
156   sigaction (SIGHUP, &sa, 0);
157
158   sa.sa_handler = catch_quit_signal;
159   sigaction (SIGINT, &sa, 0);
160   sigaction (SIGQUIT, &sa, 0);
161   sigaction (SIGTERM, &sa, 0);
162
163   sa.sa_handler = catch_child_signal;
164   sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
165   sigaction (SIGCHLD, &sa, 0);
166
167   /* ... but ignore SIGPIPE errors. */
168   sa.sa_handler = SIG_IGN;
169   sa.sa_flags = SA_RESTART;
170   sigaction (SIGPIPE, &sa, 0);
171
172   /* Change user on startup. */
173   user = cfg_get_string (0, 0, "user", "nobody");
174   pthr_server_username (user);
175
176   if (foreground)
177     {
178       pthr_server_disable_chdir ();
179       pthr_server_disable_fork ();
180     }
181
182   if (debug)
183     pthr_server_disable_close ();
184   else
185     {
186       /* Errors to error log file. */
187       stderr_file = cfg_get_string (0, 0, "error log", "/tmp/error_log");
188       pthr_server_stderr_file (stderr_file);
189
190       /* Enable stack trace on SIGSEGV. */
191       pthr_server_enable_stack_trace_on_segv ();
192     }
193
194   /* Set server name. */
195   name = psprintf (global_pool,
196                    PACKAGE "/" VERSION " %s",
197                    http_get_servername ());
198   http_set_servername (name);
199
200   /* Extra startup. */
201   pthr_server_startup_fn (startup);
202
203   /* Start up the server. */
204   pthr_server_main_loop (argc, argv, start_thread);
205
206   exit (0);
207 }
208
209 static void
210 startup (int argc, char *argv[])
211 {
212   FILE *access_log;
213
214   /* Open the access log. */
215   access_log
216     = fopen (cfg_get_string (0, 0, "access log", "/tmp/access_log"), "a");
217   if (access_log == 0)
218     {
219       perror ("open: access log");
220       exit (1);
221     }
222   if (fcntl (fileno (access_log), F_SETFD, FD_CLOEXEC) < 0)
223     { perror ("fcntl"); exit (1); }
224
225   http_set_log_file (access_log);
226 }
227
228 static void
229 start_thread (int sock, void *data)
230 {
231   (void) new_process_rq (sock);
232 }
233
234 static void
235 catch_reload_signal (int sig)
236 {
237   reload_config ();
238 }
239
240 static void
241 catch_quit_signal (int sig)
242 {
243   /* Exit gracefully (how!?!) XXX */
244   exit (0);
245 }
246
247 static void
248 catch_child_signal (int sig)
249 {
250   /* Clean up the child process. */
251   wait (0);
252 }
253
254 static void
255 reload_config ()
256 {
257   /* Reread configuration file. */
258   cfg_reread_config (config_path);
259
260   /* Read /etc/mime.types file. */
261   mime_types_reread_config (cfg_get_string (0, 0, "mime types file",
262                                             "/etc/mime.types"));
263
264   /* Reset rewrite rules. */
265   rewrite_reset_rules ();
266 }