metaproxy 1.22.1
metaproxy_prog.cpp
Go to the documentation of this file.
1/* This file is part of Metaproxy.
2 Copyright (C) Index Data
3
4Metaproxy is free software; you can redistribute it and/or modify it under
5the terms of the GNU General Public License as published by the Free
6Software Foundation; either version 2, or (at your option) any later
7version.
8
9Metaproxy is distributed in the hope that it will be useful, but WITHOUT ANY
10WARRANTY; without even the implied warranty of MERCHANTABILITY or
11FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12for more details.
13
14You should have received a copy of the GNU General Public License
15along with this program; if not, write to the Free Software
16Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17*/
18
19#include "config.hpp"
20
21#if HAVE_GETRLIMIT
22#include <sys/resource.h>
23#endif
24
25#include <yaz/log.h>
26#include <yaz/options.h>
27#include <yaz/daemon.h>
28
29#include <yaz/sc.h>
30#include <yaz/backtrace.h>
31#include <iostream>
32#include <stdexcept>
33#include <libxml/xinclude.h>
34
35#include <metaproxy/filter.hpp>
36#include <metaproxy/package.hpp>
37#include <metaproxy/util.hpp>
38#include <metaproxy/router_xml.hpp>
39
40#include <stdlib.h>
41#if HAVE_UNISTD_H
42#include <unistd.h>
43#endif
44#include <signal.h>
45#ifdef WIN32
46#include <direct.h>
47#include <io.h>
48#include <process.h>
49#endif
50
51namespace mp = metaproxy_1;
52
53mp::RouterXML *routerp = 0;
54
55static void set_log_prefix(void)
56{
57#if HAVE_UNISTD_H
58 char str[80];
59
60 sprintf(str, "%lld", (long long) getpid());
61 yaz_log_init_prefix(str);
62#endif
63}
64
65#if HAVE_UNISTD_H
66static pid_t process_group = 0;
67static int sig_received = 0;
68static pid_t my_pid = 0;
69
70static void sig_x_handler(int signo)
71{
72 if (sig_received)
73 return;
74 if ( getpid() != my_pid ) // can happen in unlikely cases
75 return; // when the sig hits a child just after fork(), before it
76 // clears its sighandler. MP-559.
77 sig_received = signo;
78 if (routerp)
79 routerp->stop(signo);
80 if (signo == SIGTERM)
81 kill(-process_group, SIGTERM); /* kill all children processes as well */
82}
83#endif
84
85static void work_common(void *data)
86{
88#if HAVE_UNISTD_H
89 process_group = getpgid(0); // save process group ID
90 my_pid = getpid();
91
92 signal(SIGTERM, sig_x_handler);
93 signal(SIGUSR1, sig_x_handler);
94#endif
95 routerp = (mp::RouterXML*) data;
96 routerp->start();
97
98 mp::Package pack;
99 pack.router(*routerp).move();
100 yaz_log(YLOG_LOG, "metaproxy stop");
101 delete routerp;
102 routerp = 0;
103 _exit(0);
104}
105
106static void work_debug(void *data)
107{
108 work_common(data);
109}
110
111static void work_normal(void *data)
112{
113#if HAVE_UNISTD_H
114 /* make the current working process group leader */
115 setpgid(0, 0);
116#endif
117 work_common(data);
118}
119
120static int sc_main(
121 yaz_sc_t s,
122 int argc, char **argv)
123{
124 bool test_config = false;
125 const char *fname = 0;
126 int ret;
127 char *arg;
128 unsigned mode = 0;
129 const char *pidfile = 0;
130 const char *uid = 0;
131#if HAVE_GETRLIMIT
132 const char *socket_limit = 0;
133#endif
134
135 yaz_enable_panic_backtrace(argv[0]);
137
138 while ((ret = options("c{config}:Dh{help}l:m:p:s:tu:v:V{version}w:X",
139 argv, argc, &arg)) != -2)
140 {
141 switch (ret)
142 {
143 case 'c':
144 fname = arg;
145 break;
146 case 'D':
147 mode = YAZ_DAEMON_FORK|YAZ_DAEMON_KEEPALIVE;
148 break;
149 case 'h':
150 std::cerr << "metaproxy\n"
151 " -h|--help help\n"
152 " -V|--version version\n"
153 " -v level\n"
154 " -c|--config f config filename\n"
155 " -D daemon and keepalive operation\n"
156 " -l f log file f\n"
157 " -m logformat log time format (strftime)\n"
158 " -p f pid file f\n"
159 " -s n socket limit\n"
160 " -t test configuration\n"
161 " -u id change uid to id\n"
162 " -w dir changes working directory to dir\n"
163 " -X debug mode (no fork/daemon mode)\n"
164#ifdef WIN32
165 " -install install windows service\n"
166 " -remove remove windows service\n"
167#endif
168
169 << std::endl;
170 break;
171 case 'l':
172 yaz_log_init_file(arg);
173 break;
174 case 'm':
175 yaz_log_time_format(arg);
176 break;
177 case 'p':
178 pidfile = arg;
179 break;
180 case 's':
181#if HAVE_GETRLIMIT
182 socket_limit = arg;
183#else
184 yaz_log(YLOG_WARN, "Option -s unsuppoted on this platform");
185#endif
186 break;
187 case 't':
188 test_config = true;
189 break;
190 case 'u':
191 uid = arg;
192 break;
193 case 'v':
194 yaz_log_init_level(yaz_log_mask_str(arg));
195 break;
196 case 'V':
197 std::cout << VERSION;
198#ifdef VERSION_SHA1
199 std::cout << " " VERSION_SHA1;
200#endif
201 std::cout << "\n";
202 return 0;
203 break;
204 case 'w':
205 if (
206#ifdef WIN32
207 _chdir(arg)
208#else
209 chdir(arg)
210#endif
211 )
212 {
213 std::cerr << "chdir " << arg << " failed" << std::endl;
214 return 1;
215 }
216 case 'X':
217 mode = YAZ_DAEMON_DEBUG;
218 break;
219 case -1:
220 std::cerr << "bad option: " << arg << std::endl;
221 return 1;
222 }
223 }
224 if (!fname)
225 {
226 std::cerr << "No configuration given; use -h for help\n";
227 return 1;
228 }
229
230 yaz_log(YLOG_LOG, "metaproxy %s " VERSION
231#ifdef VERSION_SHA1
232 " " VERSION_SHA1
233#endif
234 , test_config ? "test" : "start"
235 );
236
237 char yaz_version_str[20];
238 char yaz_sha1_str[41];
239 yaz_version(yaz_version_str, yaz_sha1_str);
240 yaz_log(YLOG_LOG, "YAZ %s %s", yaz_version_str, yaz_sha1_str);
241
242 xmlInitParser();
243 LIBXML_TEST_VERSION
244
245 yaz_log_xml_errors(0, YLOG_LOG);
246 xmlDocPtr doc = xmlReadFile(fname,
247 NULL,
248 XML_PARSE_XINCLUDE + XML_PARSE_NOBLANKS
249 + XML_PARSE_NSCLEAN + XML_PARSE_NONET );
250
251 if (!doc)
252 {
253 yaz_log(YLOG_FATAL,"XML parsing failed");
254 return 1;
255 }
256 // and perform Xinclude then
257 int r = xmlXIncludeProcess(doc);
258 if (r == -1)
259 {
260 yaz_log(YLOG_FATAL, "XInclude processing failed");
261 return 1;
262 }
263 mp::wrbuf base_path;
264 const char *last_p = strrchr(fname,
265#ifdef WIN32
266 '\\'
267#else
268 '/'
269#endif
270 );
271 if (last_p)
272 wrbuf_write(base_path, fname, last_p - fname);
273 else
274 wrbuf_puts(base_path, ".");
275 ret = 0;
276 try {
277 mp::RouterXML *router =
278 new mp::RouterXML(doc, test_config, wrbuf_cstr(base_path));
279 if (!test_config)
280 {
281#if HAVE_GETRLIMIT
282 if (socket_limit)
283 {
284 struct rlimit limit_data;
285 limit_data.rlim_cur = atoi(socket_limit);
286 limit_data.rlim_max = atoi(socket_limit);
287 int r = setrlimit(RLIMIT_NOFILE, &limit_data);
288 if (r)
289 {
290 yaz_log(YLOG_FATAL,"setrlimit: %s", strerror(errno));
291 return 1;
292 }
293
294 }
295#endif
296 yaz_sc_running(s);
297
298 yaz_daemon("metaproxy", mode | YAZ_DAEMON_LOG_REOPEN,
299 (mode & YAZ_DAEMON_FORK) ? work_normal : work_debug,
300 router, pidfile, uid);
301 }
302 delete router;
303 }
304 catch (std::logic_error &e) {
305 yaz_log(YLOG_FATAL,"std::logic error: %s" , e.what() );
306 ret = 1;
307 }
308 catch (std::runtime_error &e) {
309 yaz_log(YLOG_FATAL, "std::runtime error: %s" , e.what() );
310 ret = 1;
311 }
312 catch ( ... ) {
313 yaz_log(YLOG_FATAL, "Unknown Exception");
314 ret = 1;
315 }
316 xmlFreeDoc(doc);
317 if (test_config)
318 yaz_log(YLOG_LOG, "metaproxy test exit code %d", ret);
319 return ret;
320}
321
322static void sc_stop(yaz_sc_t s)
323{
324 return;
325}
326
327int main(int argc, char **argv)
328{
329 int ret;
330 yaz_sc_t s = yaz_sc_create("metaproxy", "metaproxy");
331
332 ret = yaz_sc_program(s, argc, argv, sc_main, sc_stop);
333
334 yaz_sc_destroy(&s);
335 exit(ret);
336}
337
338/*
339 * Local variables:
340 * c-basic-offset: 4
341 * c-file-style: "Stroustrup"
342 * indent-tabs-mode: nil
343 * End:
344 * vim: shiftwidth=4 tabstop=8 expandtab
345 */
346
#define VERSION_SHA1
Definition config.hpp:91
#define VERSION
Definition config.hpp:88
static void work_normal(void *data)
int main(int argc, char **argv)
static void work_common(void *data)
static void set_log_prefix(void)
mp::RouterXML * routerp
static int sc_main(yaz_sc_t s, int argc, char **argv)
static void sc_stop(yaz_sc_t s)
static void work_debug(void *data)