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