Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : #include "monetdb_config.h"
14 : #include <string.h> /* strerror */
15 : #include <locale.h>
16 : #include "monet_options.h"
17 : #include "mal.h"
18 : #include "mal_session.h"
19 : #include "mal_import.h"
20 : #include "mal_client.h"
21 : #include "mal_function.h"
22 : #include "monet_version.h"
23 : #include "mal_authorize.h"
24 : #include "msabaoth.h"
25 : #include "mutils.h"
26 :
27 : #ifndef HAVE_GETOPT_LONG
28 : # include "monet_getopt.h"
29 : #else
30 : # ifdef HAVE_GETOPT_H
31 : # include "getopt.h"
32 : # endif
33 : #endif
34 :
35 : #ifdef _MSC_VER
36 : #include <Psapi.h> /* for GetModuleFileName */
37 : #include <crtdbg.h> /* for _CRT_ERROR, _CRT_ASSERT */
38 : #endif
39 :
40 : #ifdef _CRTDBG_MAP_ALLOC
41 : /* Windows only:
42 : our definition of new and delete clashes with the one if
43 : _CRTDBG_MAP_ALLOC is defined.
44 : */
45 : #undef _CRTDBG_MAP_ALLOC
46 : #endif
47 :
48 : /* NEEDED? */
49 : #if defined(_MSC_VER) && defined(__cplusplus)
50 : #include <eh.h>
51 : void
52 : mserver_abort()
53 : {
54 : fprintf(stderr, "\n! mserver_abort() was called by terminate(). !\n");
55 : fflush(stderr);
56 : exit(0);
57 : }
58 : #endif
59 :
60 : #ifdef _MSC_VER
61 : static void
62 : mserver_invalid_parameter_handler(const wchar_t *expression,
63 : const wchar_t *function, const wchar_t *file,
64 : unsigned int line, uintptr_t reserved)
65 : {
66 : (void) expression;
67 : (void) function;
68 : (void) file;
69 : (void) line;
70 : (void) reserved;
71 : /* the essential bit of this function is that it returns:
72 : * we don't want the server to quit when a function is called
73 : * with an invalid parameter */
74 : }
75 : #endif
76 :
77 : static _Noreturn void usage(char *prog, int xit);
78 :
79 : static void
80 0 : usage(char *prog, int xit)
81 : {
82 0 : fprintf(stderr, "Usage: %s [options]\n", prog);
83 0 : fprintf(stderr, " --dbpath=<directory> Specify database location\n");
84 0 : fprintf(stderr, " --dbextra=<directory> Directory for transient BATs\n");
85 0 : fprintf(stderr, " --dbtrace=<file> File for produced traces\n");
86 0 : fprintf(stderr, " --in-memory Run database in-memory only\n");
87 0 : fprintf(stderr, " --config=<config_file> Use config_file to read options from\n");
88 0 : fprintf(stderr, " --single-user Allow only one user at a time\n");
89 0 : fprintf(stderr, " --readonly Safeguard database\n");
90 0 : fprintf(stderr, " --set <option>=<value> Set configuration option\n");
91 0 : fprintf(stderr, " --loadmodule=<module> Load extra <module> from lib/monetdb5\n");
92 0 : fprintf(stderr, " --help Print this list of options\n");
93 0 : fprintf(stderr, " --version Print version and compile time info\n");
94 :
95 0 : fprintf(stderr, "The debug, testing & trace options:\n");
96 0 : fprintf(stderr, " --algorithms\n");
97 0 : fprintf(stderr, " --forcemito\n");
98 0 : fprintf(stderr, " --heaps\n");
99 0 : fprintf(stderr, " --io\n");
100 0 : fprintf(stderr, " --memory\n");
101 0 : fprintf(stderr, " --modules\n");
102 0 : fprintf(stderr, " --performance\n");
103 0 : fprintf(stderr, " --properties\n");
104 0 : fprintf(stderr, " --threads\n");
105 0 : fprintf(stderr, " --transactions\n");
106 0 : fprintf(stderr, " --debug=<bitmask>\n");
107 :
108 0 : exit(xit);
109 : }
110 :
111 : /*
112 : * Collect some global system properties to relate performance results later
113 : */
114 : static void
115 303 : monet_hello(void)
116 : {
117 303 : double sz_mem_h;
118 303 : const char qc[] = " kMGTPE";
119 303 : int qi = 0;
120 :
121 303 : printf("# MonetDB 5 server v%s", GDKversion());
122 : {
123 : #ifdef MONETDB_RELEASE
124 : printf(" (%s)", MONETDB_RELEASE);
125 : #else
126 303 : const char *rev = mercurial_revision();
127 303 : if (strcmp(rev, "Unknown") != 0)
128 0 : printf(" (hg id: %s)", rev);
129 : #endif
130 : }
131 : #ifndef MONETDB_RELEASE
132 303 : printf("\n# This is an unreleased version");
133 : #endif
134 303 : printf("\n# Serving database '%s', using %d thread%s\n",
135 : GDKgetenv("gdk_dbname"), GDKnr_threads,
136 303 : (GDKnr_threads != 1) ? "s" : "");
137 303 : printf("# Compiled for %s/%zubit%s\n", HOST, sizeof(ptr) * 8,
138 : #ifdef HAVE_HGE
139 : " with 128bit integers"
140 : #else
141 : ""
142 : #endif
143 : );
144 303 : sz_mem_h = (double) MT_npages() * MT_pagesize();
145 1212 : while (sz_mem_h >= 1000.0 && qi < 6) {
146 909 : sz_mem_h /= 1024.0;
147 909 : qi++;
148 : }
149 303 : printf("# Found %.3f %ciB available main-memory", sz_mem_h, qc[qi]);
150 303 : sz_mem_h = (double) GDK_mem_maxsize;
151 303 : qi = 0;
152 1212 : while (sz_mem_h >= 1000.0 && qi < 6) {
153 909 : sz_mem_h /= 1024.0;
154 909 : qi++;
155 : }
156 303 : printf(" of which we use %.3f %ciB\n", sz_mem_h, qc[qi]);
157 303 : if (GDK_vm_maxsize < GDK_VM_MAXSIZE) {
158 155 : sz_mem_h = (double) GDK_vm_maxsize;
159 155 : qi = 0;
160 620 : while (sz_mem_h >= 1000.0 && qi < 6) {
161 465 : sz_mem_h /= 1024.0;
162 465 : qi++;
163 : }
164 155 : printf("# Virtual memory usage limited to %.3f %ciB\n", sz_mem_h,
165 155 : qc[qi]);
166 : }
167 : #ifdef MONET_GLOBAL_DEBUG
168 : printf("# Database path:%s\n", GDKgetenv("gdk_dbpath"));
169 : printf("# Module path:%s\n", GDKgetenv("monet_mod_path"));
170 : #endif
171 303 : printf("# Copyright (c) 2024 MonetDB Foundation, all rights reserved\n");
172 303 : printf("# Visit https://www.monetdb.org/ for further information\n");
173 :
174 : // The properties shipped through the performance profiler
175 303 : (void) snprintf(monet_characteristics, sizeof(monet_characteristics),
176 : "{\n" "\"version\":\"%s\",\n" "\"release\":\"%s\",\n"
177 : "\"host\":\"%s\",\n" "\"threads\":\"%d\",\n"
178 : "\"memory\":\"%.3f %cB\",\n" "\"oid\":\"%zu\",\n"
179 : "\"packages\":["
180 : #ifdef HAVE_HGE
181 : "\"huge\""
182 : #endif
183 : "]\n}", GDKversion(),
184 : #ifdef MONETDB_RELEASE
185 : MONETDB_RELEASE,
186 : #else
187 : "unreleased",
188 : #endif
189 303 : HOST, GDKnr_threads, sz_mem_h, qc[qi], sizeof(oid) * 8);
190 303 : fflush(stdout);
191 303 : }
192 :
193 : static str
194 305 : absolute_path(const char *s)
195 : {
196 305 : if (!MT_path_absolute(s)) {
197 0 : str ret = (str) GDKmalloc(strlen(s) + strlen(monet_cwd) + 2);
198 :
199 0 : if (ret)
200 0 : sprintf(ret, "%s%c%s", monet_cwd, DIR_SEP, s);
201 0 : return ret;
202 : }
203 305 : return GDKstrdup(s);
204 : }
205 :
206 : #define BSIZE 8192
207 :
208 : static int
209 305 : monet_init(opt *set, int setlen, bool embedded)
210 : {
211 : /* check that library that we're linked against is compatible with
212 : * the one we were compiled with */
213 305 : int maj, min, patch;
214 305 : const char *version = GDKlibversion();
215 305 : sscanf(version, "%d.%d.%d", &maj, &min, &patch);
216 305 : if (maj != GDK_VERSION_MAJOR || min < GDK_VERSION_MINOR) {
217 0 : fprintf(stderr,
218 : "Linked GDK library not compatible with the one this was compiled with\n");
219 0 : fprintf(stderr, "Linked version: %s, compiled version: %s\n", version,
220 : GDK_VERSION);
221 0 : return 0;
222 : }
223 305 : version = mal_version();
224 305 : sscanf(version, "%d.%d.%d", &maj, &min, &patch);
225 305 : if (maj != MONETDB5_VERSION_MAJOR || min < MONETDB5_VERSION_MINOR) {
226 0 : fprintf(stderr,
227 : "Linked MonetDB5 library not compatible with the one this was compiled with\n");
228 0 : fprintf(stderr, "Linked version: %s, compiled version: %s\n", version,
229 : MONETDB5_VERSION);
230 0 : return 0;
231 : }
232 :
233 : /* determine Monet's kernel settings */
234 305 : if (GDKinit(set, setlen, embedded, mercurial_revision()) != GDK_SUCCEED)
235 : return 0;
236 :
237 : #ifdef HAVE_SETSID
238 303 : setsid();
239 : #endif
240 303 : monet_hello();
241 303 : return 1;
242 : }
243 :
244 : static void
245 : emergencyBreakpoint(void)
246 : {
247 : /* just a handle to break after system initialization for GDB */
248 : }
249 :
250 : static volatile sig_atomic_t interrupted = 0;
251 : static volatile sig_atomic_t usr1_interrupted = 0;
252 :
253 : #ifdef _MSC_VER
254 : static BOOL WINAPI
255 : winhandler(DWORD type)
256 : {
257 : (void) type;
258 : interrupted = 1;
259 : return TRUE;
260 : }
261 : #else
262 : static void
263 286 : handler(int sig)
264 : {
265 286 : (void) sig;
266 286 : interrupted = 1;
267 286 : }
268 : static void
269 116 : handler_usr1(int sig)
270 : {
271 116 : (void) sig;
272 116 : usr1_interrupted = 1;
273 116 : }
274 : #endif
275 :
276 : int
277 : #ifdef _MSC_VER
278 : wmain(int argc, wchar_t **argv)
279 : #else
280 306 : main(int argc, char **av)
281 : #endif
282 : {
283 : /* make sure stdout is line buffered, even when not to a terminal;
284 : * note, on Windows _IOLBF is interpreted as _IOFBF, but all
285 : * relevant calls to print to stdout are followed by a fflush
286 : * anyway */
287 306 : setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
288 : #ifdef _MSC_VER
289 : char **av = malloc((argc + 1) * sizeof(char *));
290 : if (av == NULL) {
291 : fprintf(stderr, "cannot allocate memory for argument conversion\n");
292 : exit(1);
293 : }
294 : for (int i = 0; i < argc; i++) {
295 : if ((av[i] = wchartoutf8(argv[i])) == NULL) {
296 : fprintf(stderr, "cannot convert argument to UTF-8\n");
297 : exit(1);
298 : }
299 : }
300 : av[argc] = NULL;
301 : #endif
302 306 : char *prog = *av;
303 306 : opt *set = NULL;
304 306 : unsigned grpdebug = 0, debug = 0;
305 306 : int setlen = 0;
306 306 : str err = MAL_SUCCEED;
307 306 : char prmodpath[FILENAME_MAX];
308 306 : const char *modpath = NULL;
309 306 : char *binpath = NULL;
310 306 : char *dbpath = NULL;
311 306 : char *dbextra = NULL;
312 306 : char *dbtrace = NULL;
313 306 : bool inmemory = false;
314 306 : bool readpwdxit = false;
315 306 : static const struct option long_options[] = {
316 : {"config", required_argument, NULL, 'c'},
317 : {"dbextra", required_argument, NULL, 0},
318 : {"dbpath", required_argument, NULL, 0},
319 : {"dbtrace", required_argument, NULL, 0},
320 : {"debug", optional_argument, NULL, 'd'},
321 : {"help", no_argument, NULL, '?'},
322 : {"in-memory", no_argument, NULL, 0},
323 : {"readonly", no_argument, NULL, 'r'},
324 : {"set", required_argument, NULL, 's'},
325 : {"single-user", no_argument, NULL, 0},
326 : {"version", no_argument, NULL, 0},
327 :
328 : {"algorithms", no_argument, NULL, 0},
329 : {"forcemito", no_argument, NULL, 0},
330 : {"heaps", no_argument, NULL, 0},
331 : {"io", no_argument, NULL, 0},
332 : {"memory", no_argument, NULL, 0},
333 : {"modules", no_argument, NULL, 0},
334 : {"performance", no_argument, NULL, 0},
335 : {"properties", no_argument, NULL, 0},
336 : {"threads", no_argument, NULL, 0},
337 : {"transactions", no_argument, NULL, 0},
338 :
339 : {"read-password-initialize-and-exit", no_argument, NULL, 0},
340 : {"loadmodule", required_argument, NULL, 0},
341 : {"without-geom", no_argument, NULL, 0},
342 : {"process-wal-and-exit", no_argument, NULL, 0},
343 :
344 : {NULL, 0, NULL, 0}
345 : };
346 :
347 : #define MAX_MODULES 32
348 306 : char *modules[MAX_MODULES + 1];
349 306 : int mods = 0;
350 :
351 306 : modules[mods++] = "sql";
352 306 : modules[mods++] = "generator";
353 : #ifdef HAVE_GEOM
354 306 : modules[mods++] = "geom";
355 : #endif
356 : #ifdef HAVE_LIBR
357 : /* TODO check for used */
358 306 : modules[mods++] = "rapi";
359 : #endif
360 : #ifdef HAVE_LIBPY3
361 : /* TODO check for used */
362 306 : modules[mods++] = "pyapi3";
363 : #endif
364 : #ifdef HAVE_CUDF
365 306 : modules[mods++] = "capi";
366 : #endif
367 : #ifdef HAVE_FITS
368 306 : modules[mods++] = "fits";
369 : #endif
370 : #ifdef HAVE_NETCDF
371 306 : modules[mods++] = "netcdf";
372 : #endif
373 306 : modules[mods++] = "csv";
374 : #ifdef HAVE_SHP
375 306 : modules[mods++] = "shp";
376 : #endif
377 :
378 : #if defined(_MSC_VER) && defined(__cplusplus)
379 : set_terminate(mserver_abort);
380 : #endif
381 : #ifdef _MSC_VER
382 : _CrtSetReportMode(_CRT_ERROR, 0);
383 : _CrtSetReportMode(_CRT_ASSERT, 0);
384 : _set_invalid_parameter_handler(mserver_invalid_parameter_handler);
385 : #ifdef _TWO_DIGIT_EXPONENT
386 : _set_output_format(_TWO_DIGIT_EXPONENT);
387 : #endif
388 : #endif
389 306 : if (setlocale(LC_CTYPE, "") == NULL) {
390 0 : fprintf(stderr, "cannot set locale\n");
391 0 : exit(1);
392 : }
393 :
394 306 : if (MT_getcwd(monet_cwd, FILENAME_MAX - 1) == NULL) {
395 0 : perror("pwd");
396 0 : fprintf(stderr, "monet_init: could not determine current directory\n");
397 0 : exit(-1);
398 : }
399 :
400 : /* retrieve binpath early (before monet_init) because some
401 : * implementations require the working directory when the binary was
402 : * called */
403 306 : binpath = get_bin_path();
404 :
405 306 : if (!(setlen = mo_builtin_settings(&set)))
406 0 : usage(prog, -1);
407 :
408 2956 : for (;;) {
409 3262 : int option_index = 0;
410 :
411 3262 : int c = getopt_long(argc, av, "c:d::rs:t::v::?",
412 : long_options, &option_index);
413 :
414 3262 : if (c == -1)
415 : break;
416 :
417 2957 : switch (c) {
418 766 : case 0:
419 766 : if (strcmp(long_options[option_index].name, "in-memory") == 0) {
420 : inmemory = true;
421 : break;
422 : }
423 766 : if (strcmp(long_options[option_index].name, "dbpath") == 0) {
424 305 : size_t optarglen = strlen(optarg);
425 : /* remove trailing directory separator */
426 305 : while (optarglen > 0
427 305 : && (optarg[optarglen - 1] == '/'
428 305 : || optarg[optarglen - 1] == '\\'))
429 0 : optarg[--optarglen] = '\0';
430 305 : dbpath = absolute_path(optarg);
431 305 : if (dbpath == NULL)
432 0 : fprintf(stderr,
433 : "#error: can not allocate memory for dbpath\n");
434 : else
435 305 : setlen = mo_add_option(&set, setlen, opt_cmdline,
436 : "gdk_dbpath", dbpath);
437 : break;
438 : }
439 461 : if (strcmp(long_options[option_index].name, "dbextra") == 0) {
440 149 : if (dbextra)
441 0 : fprintf(stderr,
442 : "#warning: ignoring multiple --dbextra arguments\n");
443 : else
444 149 : dbextra = optarg;
445 : break;
446 : }
447 :
448 312 : if (strcmp(long_options[option_index].name, "dbtrace") == 0) {
449 0 : size_t optarglen = strlen(optarg);
450 : /* remove trailing directory separator */
451 0 : while (optarglen > 0
452 0 : && (optarg[optarglen - 1] == '/'
453 0 : || optarg[optarglen - 1] == '\\'))
454 0 : optarg[--optarglen] = '\0';
455 0 : dbtrace = absolute_path(optarg);
456 0 : if (dbtrace == NULL)
457 0 : fprintf(stderr,
458 : "#error: can not allocate memory for dbtrace\n");
459 : else
460 0 : setlen = mo_add_option(&set, setlen, opt_cmdline,
461 : "gdk_dbtrace", dbtrace);
462 : break;
463 : }
464 :
465 312 : if (strcmp(long_options[option_index].name, "single-user") == 0) {
466 0 : setlen = mo_add_option(&set, setlen, opt_cmdline,
467 : "gdk_single_user", "yes");
468 0 : break;
469 : }
470 312 : if (strcmp(long_options[option_index].name, "version") == 0) {
471 1 : monet_version();
472 1 : exit(0);
473 : }
474 : /* debugging options */
475 311 : if (strcmp(long_options[option_index].name, "algorithms") == 0) {
476 0 : grpdebug |= GRPalgorithms;
477 0 : break;
478 : }
479 311 : if (strcmp(long_options[option_index].name, "forcemito") == 0) {
480 306 : grpdebug |= GRPforcemito;
481 306 : break;
482 : }
483 5 : if (strcmp(long_options[option_index].name, "heaps") == 0) {
484 0 : grpdebug |= GRPheaps;
485 0 : break;
486 : }
487 5 : if (strcmp(long_options[option_index].name, "io") == 0) {
488 0 : grpdebug |= GRPio;
489 0 : break;
490 : }
491 5 : if (strcmp(long_options[option_index].name, "memory") == 0) {
492 0 : grpdebug |= GRPmemory;
493 0 : break;
494 : }
495 5 : if (strcmp(long_options[option_index].name, "modules") == 0) {
496 0 : grpdebug |= GRPmodules;
497 0 : break;
498 : }
499 5 : if (strcmp(long_options[option_index].name, "performance") == 0) {
500 0 : grpdebug |= GRPperformance;
501 0 : break;
502 : }
503 5 : if (strcmp(long_options[option_index].name, "properties") == 0) {
504 0 : grpdebug |= GRPproperties;
505 0 : break;
506 : }
507 5 : if (strcmp(long_options[option_index].name, "threads") == 0) {
508 0 : grpdebug |= GRPthreads;
509 0 : break;
510 : }
511 5 : if (strcmp(long_options[option_index].name, "transactions") == 0) {
512 0 : grpdebug |= GRPtransactions;
513 0 : break;
514 : }
515 5 : if (strcmp(long_options[option_index].name, "read-password-initialize-and-exit") == 0) {
516 : readpwdxit = true;
517 : break;
518 : }
519 5 : if (strcmp(long_options[option_index].name, "process-wal-and-exit") == 0) {
520 0 : setlen = mo_add_option(&set, setlen, opt_cmdline,
521 : "process-wal-and-exit", "yes");
522 0 : break;
523 : }
524 5 : if (strcmp(long_options[option_index].name, "loadmodule") == 0) {
525 5 : if (mods < MAX_MODULES)
526 5 : modules[mods++] = optarg;
527 : else
528 0 : fprintf(stderr,
529 : "ERROR: maximum number of modules reached\n");
530 : break;
531 : }
532 0 : if (strcmp(long_options[option_index].name, "without-geom") == 0) {
533 0 : for (int i = 0; i < mods; i++) {
534 0 : if (strcmp(modules[i], "geom") == 0) {
535 0 : while (i + 1 < mods) {
536 0 : modules[i] = modules[i + 1];
537 0 : i++;
538 : }
539 0 : mods--;
540 0 : break;
541 : }
542 : }
543 : break;
544 : }
545 0 : usage(prog, -1);
546 : /* not reached */
547 0 : case 'c':
548 : /* coverity[var_deref_model] */
549 0 : setlen = mo_add_option(&set, setlen, opt_cmdline, "config", optarg);
550 0 : break;
551 610 : case 'd':
552 610 : if (optarg) {
553 610 : char *endarg;
554 610 : debug |= strtoul(optarg, &endarg, 10);
555 610 : if (*endarg != '\0') {
556 0 : fprintf(stderr, "ERROR: wrong format for --debug=%s\n",
557 : optarg);
558 0 : usage(prog, -1);
559 : }
560 : } else {
561 0 : debug |= CHECKMASK;
562 : }
563 : break;
564 3 : case 'r':
565 3 : setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_readonly",
566 : "yes");
567 3 : break;
568 1578 : case 's':{
569 : /* should add option to a list */
570 : /* coverity[var_deref_model] */
571 1578 : char *tmp = strchr(optarg, '=');
572 :
573 1578 : if (tmp) {
574 1578 : *tmp = '\0';
575 1578 : setlen = mo_add_option(&set, setlen, opt_cmdline, optarg,
576 1578 : tmp + 1);
577 : } else
578 0 : fprintf(stderr, "ERROR: wrong format %s\n", optarg);
579 : }
580 : break;
581 0 : case '?':
582 : /* a bit of a hack: look at the option that the
583 : current `c' is based on and see if we recognize
584 : it: if -? or --help, exit with 0, else with -1 */
585 0 : usage(prog, strcmp(av[optind - 1], "-?") == 0
586 0 : || strcmp(av[optind - 1], "--help") == 0 ? 0 : -1);
587 0 : default:
588 0 : fprintf(stderr,
589 : "ERROR: getopt returned character " "code '%c' 0%o\n", c,
590 : (unsigned) (uint8_t) c);
591 0 : usage(prog, -1);
592 : }
593 : }
594 :
595 305 : if (optind < argc)
596 0 : usage(prog, -1);
597 :
598 305 : if (!(setlen = mo_system_config(&set, setlen)))
599 0 : usage(prog, -1);
600 :
601 305 : if (debug)
602 305 : mo_print_options(set, setlen);
603 :
604 305 : if (dbpath && inmemory) {
605 0 : fprintf(stderr,
606 : "!ERROR: both dbpath and in-memory must not be set at the same time\n");
607 0 : exit(1);
608 : }
609 :
610 305 : if (inmemory && readpwdxit) {
611 0 : fprintf(stderr,
612 : "!ERROR: cannot have both in-memory and read-password-initialize-and-exit\n");
613 0 : exit(1);
614 : }
615 :
616 305 : if (inmemory) {
617 0 : if (BBPaddfarm(NULL, (1U << PERSISTENT) | (1U << TRANSIENT), true) !=
618 : GDK_SUCCEED) {
619 0 : fprintf(stderr, "!ERROR: cannot add in-memory farm\n");
620 0 : exit(1);
621 : }
622 : } else {
623 305 : if (dbpath == NULL) {
624 0 : dbpath = absolute_path(mo_find_option(set, setlen, "gdk_dbpath"));
625 0 : if (dbpath == NULL) {
626 0 : fprintf(stderr,
627 : "!ERROR: cannot allocate memory for database directory \n");
628 0 : exit(1);
629 : }
630 : }
631 305 : if (BBPaddfarm(dbpath, 1U << PERSISTENT, true) != GDK_SUCCEED
632 461 : || BBPaddfarm(dbextra ? dbextra : dbpath, 1U << TRANSIENT,
633 : true) != GDK_SUCCEED) {
634 0 : fprintf(stderr, "!ERROR: cannot add farm\n");
635 0 : exit(1);
636 : }
637 305 : GDKfree(dbpath);
638 : }
639 :
640 305 : if (dbtrace) {
641 : /* GDKcreatedir makes sure that all parent directories of dbtrace exist */
642 0 : if (!inmemory && GDKcreatedir(dbtrace) != GDK_SUCCEED) {
643 0 : fprintf(stderr, "!ERROR: cannot create directory for %s\n",
644 : dbtrace);
645 0 : exit(1);
646 : }
647 0 : GDKfree(dbtrace);
648 : }
649 :
650 305 : GDKsetdebug(debug | grpdebug); /* add the algorithm tracers */
651 305 : if (monet_init(set, setlen, false) == 0) {
652 2 : mo_free_options(set, setlen);
653 2 : if (GDKerrbuf && *GDKerrbuf)
654 0 : fprintf(stderr, "%s\n", GDKerrbuf);
655 2 : exit(1);
656 : }
657 303 : mo_free_options(set, setlen);
658 :
659 303 : if (GDKsetenv("monet_version", GDKversion()) != GDK_SUCCEED
660 303 : || GDKsetenv("monet_release",
661 : #ifdef MONETDB_RELEASE
662 : MONETDB_RELEASE
663 : #else
664 : "unreleased"
665 : #endif
666 : ) != GDK_SUCCEED) {
667 0 : fprintf(stderr, "!ERROR: GDKsetenv failed\n");
668 0 : exit(1);
669 : }
670 :
671 303 : if ((modpath = GDKgetenv("monet_mod_path")) == NULL) {
672 : /* start probing based on some heuristics given the binary
673 : * location:
674 : * bin/mserver5 -> ../
675 : * libX/monetdb5/lib/
676 : * probe libX = lib, lib32, lib64, lib/64 */
677 : size_t pref;
678 : /* "remove" common prefix of configured BIN and LIB
679 : * directories from LIBDIR */
680 19392 : for (pref = 0; LIBDIR[pref] != 0 && BINDIR[pref] == LIBDIR[pref];
681 19089 : pref++) ;
682 303 : const char *libdirs[] = {
683 303 : &LIBDIR[pref],
684 : "lib",
685 : "lib64",
686 : "lib/64",
687 : "lib32",
688 : NULL,
689 : };
690 303 : struct stat sb;
691 303 : if (binpath != NULL) {
692 303 : char *p = strrchr(binpath, DIR_SEP);
693 303 : if (p != NULL)
694 303 : *p = '\0';
695 303 : p = strrchr(binpath, DIR_SEP);
696 303 : if (p != NULL) {
697 303 : *p = '\0';
698 303 : for (int i = 0; libdirs[i] != NULL; i++) {
699 303 : int len = snprintf(prmodpath, sizeof(prmodpath),
700 : "%s%c%s%cmonetdb5-%s",
701 : binpath, DIR_SEP, libdirs[i], DIR_SEP,
702 : MONETDB_VERSION);
703 303 : if (len == -1 || len >= FILENAME_MAX)
704 0 : continue;
705 303 : if (MT_stat(prmodpath, &sb) == 0) {
706 : modpath = prmodpath;
707 : break;
708 : }
709 0 : len = snprintf(prmodpath, sizeof(prmodpath),
710 : "%s%c%s%cmonetdb5",
711 : binpath, DIR_SEP, libdirs[i], DIR_SEP);
712 0 : if (len == -1 || len >= FILENAME_MAX)
713 0 : continue;
714 0 : if (MT_stat(prmodpath, &sb) == 0) {
715 : modpath = prmodpath;
716 : break;
717 : }
718 : }
719 : } else {
720 0 : printf("#warning: unusable binary location, "
721 : "please use --set monet_mod_path=/path/to/... to "
722 : "allow finding modules\n");
723 0 : fflush(stdout);
724 : }
725 : } else {
726 0 : printf("#warning: unable to determine binary location, "
727 : "please use --set monet_mod_path=/path/to/... to "
728 : "allow finding modules\n");
729 0 : fflush(stdout);
730 : }
731 303 : if (modpath != NULL
732 303 : && GDKsetenv("monet_mod_path", modpath) != GDK_SUCCEED) {
733 0 : fprintf(stderr, "!ERROR: GDKsetenv failed\n");
734 0 : exit(1);
735 : }
736 : }
737 :
738 303 : if (!GDKinmemory(0)) {
739 : /* configure sabaoth to use the right dbpath and active database */
740 303 : msab_dbpathinit(GDKgetenv("gdk_dbpath"));
741 : /* wipe out all cruft, if left over */
742 303 : if ((err = msab_wildRetreat()) != NULL) {
743 : /* just swallow the error */
744 0 : free(err);
745 : }
746 : /* From this point, the server should exit cleanly. Discussion:
747 : * even earlier? Sabaoth here registers the server is starting up. */
748 303 : if ((err = msab_registerStarting()) != NULL) {
749 : /* throw the error at the user, but don't die */
750 0 : fprintf(stderr, "!%s\n", err);
751 0 : free(err);
752 : }
753 : }
754 :
755 : #ifdef HAVE_SIGACTION
756 : {
757 303 : struct sigaction sa;
758 :
759 303 : (void) sigemptyset(&sa.sa_mask);
760 303 : sa.sa_flags = 0;
761 303 : sa.sa_handler = handler;
762 303 : if (sigaction(SIGINT, &sa, NULL) == -1
763 303 : || sigaction(SIGQUIT, &sa, NULL) == -1
764 303 : || sigaction(SIGTERM, &sa, NULL) == -1) {
765 0 : fprintf(stderr, "!unable to create signal handlers\n");
766 : }
767 303 : (void) sigemptyset(&sa.sa_mask);
768 303 : sa.sa_flags = 0;
769 303 : sa.sa_handler = handler_usr1;
770 303 : if (sigaction(SIGUSR1, &sa, NULL) == -1) {
771 0 : fprintf(stderr, "!unable to create signal handler for SIGUSR1\n");
772 : }
773 : }
774 : #else
775 : #ifdef _MSC_VER
776 : if (!SetConsoleCtrlHandler(winhandler, TRUE))
777 : fprintf(stderr, "!unable to create console control handler\n");
778 : #else
779 : if (signal(SIGINT, handler) == SIG_ERR)
780 : fprintf(stderr, "!unable to create signal handlers\n");
781 : #ifdef SIGQUIT
782 : if (signal(SIGQUIT, handler) == SIG_ERR)
783 : fprintf(stderr, "!unable to create signal handlers\n");
784 : #endif
785 : if (signal(SIGTERM, handler) == SIG_ERR)
786 : fprintf(stderr, "!unable to create signal handlers\n");
787 : if (signal(SIGUSR1, handler_usr1) == SIG_ERR)
788 : fprintf(stderr, "!unable to create signal handler for SIGUSR1\n");
789 : #endif
790 : #endif
791 :
792 303 : if (!GDKinmemory(0)) {
793 303 : str lang = "mal";
794 : /* we inited mal before, so publish its existence */
795 303 : if ((err = msab_marchScenario(lang)) != NULL) {
796 : /* throw the error at the user, but don't die */
797 0 : fprintf(stderr, "!%s\n", err);
798 0 : free(err);
799 : }
800 : }
801 :
802 303 : char secret[1024];
803 : {
804 : /* unlock the vault, first see if we can find the file which
805 : * holds the secret */
806 303 : FILE *secretf;
807 303 : size_t len;
808 :
809 303 : if (GDKinmemory(0) || GDKgetenv("monet_vault_key") == NULL) {
810 : /* use a default (hard coded, non safe) key */
811 140 : snprintf(secret, sizeof(secret), "%s", "Xas632jsi2whjds8");
812 : } else {
813 163 : if ((secretf = MT_fopen(GDKgetenv("monet_vault_key"), "r")) == NULL) {
814 0 : fprintf(stderr, "unable to open vault_key_file %s: %s\n",
815 0 : GDKgetenv("monet_vault_key"), strerror(errno));
816 : /* don't show this as a crash */
817 0 : msab_registerStop();
818 0 : exit(1);
819 : }
820 163 : len = fread(secret, 1, sizeof(secret), secretf);
821 163 : secret[len] = '\0';
822 163 : len = strlen(secret); /* secret can contain null-bytes */
823 163 : if (len == 0) {
824 0 : fprintf(stderr, "vault key has zero-length!\n");
825 : /* don't show this as a crash */
826 0 : msab_registerStop();
827 0 : exit(1);
828 163 : } else if (len < 5) {
829 0 : fprintf(stderr,
830 : "#warning: your vault key is too short "
831 : "(%zu), enlarge your vault key!\n", len);
832 : }
833 163 : fclose(secretf);
834 : }
835 303 : if ((err = AUTHunlockVault(secret)) != MAL_SUCCEED) {
836 : /* don't show this as a crash */
837 0 : if (!GDKinmemory(0))
838 0 : msab_registerStop();
839 0 : fprintf(stderr, "%s\n", err);
840 0 : freeException(err);
841 0 : exit(1);
842 : }
843 303 : if (readpwdxit) {
844 0 : char *secretp;
845 0 : if (fgets(secret, (int) sizeof(secret), stdin) == NULL) {
846 0 : fprintf(stderr, "!ERROR: no password read\n");
847 0 : exit(1);
848 : }
849 0 : if ((secretp = strchr(secret, '\n')) == NULL) {
850 0 : fprintf(stderr, "!ERROR: password too long\n");
851 0 : exit(1);
852 : }
853 0 : *secretp = '\0';
854 : }
855 : }
856 :
857 303 : modules[mods++] = 0;
858 606 : if (mal_init(modules, false, readpwdxit ? secret : NULL, mercurial_revision())) {
859 : /* don't show this as a crash */
860 0 : if (!GDKinmemory(0))
861 0 : msab_registerStop();
862 0 : return 1;
863 : }
864 286 : if (readpwdxit) {
865 0 : msab_registerStop();
866 0 : return 0;
867 : }
868 :
869 286 : emergencyBreakpoint();
870 :
871 286 : if (!GDKinmemory(0) && (err = msab_registerStarted()) != NULL) {
872 : /* throw the error at the user, but don't die */
873 0 : fprintf(stderr, "!%s\n", err);
874 0 : free(err);
875 : }
876 :
877 : /* return all our free bats to global pool */
878 286 : BBPrelinquishbats();
879 :
880 : #ifdef _MSC_VER
881 : printf("# MonetDB server is started. To stop server press Ctrl-C.\n");
882 : fflush(stdout);
883 : #endif
884 :
885 15266 : while (!interrupted && !GDKexiting()) {
886 14980 : if (usr1_interrupted) {
887 116 : usr1_interrupted = 0;
888 : /* print some useful information */
889 116 : GDKprintinfo();
890 116 : fflush(stdout);
891 : }
892 14980 : MT_sleep_ms(100); /* pause(), except for sys.shutdown() */
893 : }
894 :
895 : /* mal_exit calls exit, so statements after this call will
896 : * never get reached */
897 286 : mal_exit(0);
898 :
899 : return 0;
900 : }
|