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 318 : monet_hello(void)
116 : {
117 318 : double sz_mem_h;
118 318 : const char qc[] = " kMGTPE";
119 318 : int qi = 0;
120 :
121 318 : printf("# MonetDB 5 server v%s", GDKversion());
122 : {
123 : #ifdef MONETDB_RELEASE
124 : printf(" (%s)", MONETDB_RELEASE);
125 : #else
126 318 : const char *rev = mercurial_revision();
127 318 : if (strcmp(rev, "Unknown") != 0)
128 0 : printf(" (hg id: %s)", rev);
129 : #endif
130 : }
131 : #ifndef MONETDB_RELEASE
132 318 : printf("\n# This is an unreleased version");
133 : #endif
134 318 : printf("\n# Serving database '%s', using %d thread%s\n",
135 : GDKgetenv("gdk_dbname"), GDKnr_threads,
136 318 : (GDKnr_threads != 1) ? "s" : "");
137 318 : 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 318 : sz_mem_h = (double) MT_npages() * MT_pagesize();
145 1272 : while (sz_mem_h >= 1000.0 && qi < 6) {
146 954 : sz_mem_h /= 1024.0;
147 954 : qi++;
148 : }
149 318 : printf("# Found %.3f %ciB available main-memory", sz_mem_h, qc[qi]);
150 318 : sz_mem_h = (double) GDK_mem_maxsize;
151 318 : qi = 0;
152 1272 : while (sz_mem_h >= 1000.0 && qi < 6) {
153 954 : sz_mem_h /= 1024.0;
154 954 : qi++;
155 : }
156 318 : printf(" of which we use %.3f %ciB\n", sz_mem_h, qc[qi]);
157 318 : if (GDK_vm_maxsize < GDK_VM_MAXSIZE) {
158 171 : sz_mem_h = (double) GDK_vm_maxsize;
159 171 : qi = 0;
160 684 : while (sz_mem_h >= 1000.0 && qi < 6) {
161 513 : sz_mem_h /= 1024.0;
162 513 : qi++;
163 : }
164 171 : printf("# Virtual memory usage limited to %.3f %ciB\n", sz_mem_h,
165 171 : 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 318 : printf("# Copyright (c) 2024 MonetDB Foundation, all rights reserved\n");
172 318 : printf("# Visit https://www.monetdb.org/ for further information\n");
173 :
174 : // The properties shipped through the performance profiler
175 318 : (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 318 : HOST, GDKnr_threads, sz_mem_h, qc[qi], sizeof(oid) * 8);
190 318 : fflush(stdout);
191 318 : }
192 :
193 : static str
194 320 : absolute_path(const char *s)
195 : {
196 320 : 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 320 : return GDKstrdup(s);
204 : }
205 :
206 : #define BSIZE 8192
207 :
208 : static int
209 320 : 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 320 : int maj, min, patch;
214 320 : const char *version = GDKlibversion();
215 320 : sscanf(version, "%d.%d.%d", &maj, &min, &patch);
216 320 : 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 320 : version = mal_version();
224 320 : sscanf(version, "%d.%d.%d", &maj, &min, &patch);
225 320 : 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 320 : if (GDKinit(set, setlen, embedded, mercurial_revision()) != GDK_SUCCEED)
235 : return 0;
236 :
237 : #ifdef HAVE_SETSID
238 318 : setsid();
239 : #endif
240 318 : monet_hello();
241 318 : 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 317 : handler(int sig)
264 : {
265 317 : (void) sig;
266 317 : interrupted = 1;
267 317 : }
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 321 : 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 321 : 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 321 : char *prog = *av;
303 321 : opt *set = NULL;
304 321 : unsigned grpdebug = 0, debug = 0;
305 321 : int setlen = 0;
306 321 : str err = MAL_SUCCEED;
307 321 : char prmodpath[FILENAME_MAX];
308 321 : const char *modpath = NULL;
309 321 : char *binpath = NULL;
310 321 : char *dbpath = NULL;
311 321 : char *dbextra = NULL;
312 321 : char *dbtrace = NULL;
313 321 : bool inmemory = false;
314 321 : bool readpwdxit = false;
315 321 : 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 :
343 : {NULL, 0, NULL, 0}
344 : };
345 :
346 : #define MAX_MODULES 32
347 321 : char *modules[MAX_MODULES + 1];
348 321 : int mods = 0;
349 :
350 321 : modules[mods++] = "sql";
351 321 : modules[mods++] = "generator";
352 : #ifdef HAVE_GEOM
353 321 : modules[mods++] = "geom";
354 : #endif
355 : #ifdef HAVE_LIBR
356 : /* TODO check for used */
357 321 : modules[mods++] = "rapi";
358 : #endif
359 : #ifdef HAVE_LIBPY3
360 : /* TODO check for used */
361 321 : modules[mods++] = "pyapi3";
362 : #endif
363 : #ifdef HAVE_CUDF
364 321 : modules[mods++] = "capi";
365 : #endif
366 : #ifdef HAVE_FITS
367 321 : modules[mods++] = "fits";
368 : #endif
369 : #ifdef HAVE_NETCDF
370 321 : modules[mods++] = "netcdf";
371 : #endif
372 321 : modules[mods++] = "csv";
373 : #ifdef HAVE_SHP
374 321 : modules[mods++] = "shp";
375 : #endif
376 :
377 : #if defined(_MSC_VER) && defined(__cplusplus)
378 : set_terminate(mserver_abort);
379 : #endif
380 : #ifdef _MSC_VER
381 : _CrtSetReportMode(_CRT_ERROR, 0);
382 : _CrtSetReportMode(_CRT_ASSERT, 0);
383 : _set_invalid_parameter_handler(mserver_invalid_parameter_handler);
384 : #ifdef _TWO_DIGIT_EXPONENT
385 : _set_output_format(_TWO_DIGIT_EXPONENT);
386 : #endif
387 : #endif
388 321 : if (setlocale(LC_CTYPE, "") == NULL) {
389 0 : fprintf(stderr, "cannot set locale\n");
390 0 : exit(1);
391 : }
392 :
393 321 : if (MT_getcwd(monet_cwd, FILENAME_MAX - 1) == NULL) {
394 0 : perror("pwd");
395 0 : fprintf(stderr, "monet_init: could not determine current directory\n");
396 0 : exit(-1);
397 : }
398 :
399 : /* retrieve binpath early (before monet_init) because some
400 : * implementations require the working directory when the binary was
401 : * called */
402 321 : binpath = get_bin_path();
403 :
404 321 : if (!(setlen = mo_builtin_settings(&set)))
405 0 : usage(prog, -1);
406 :
407 2796 : for (;;) {
408 3117 : int option_index = 0;
409 :
410 3117 : int c = getopt_long(argc, av, "c:d::rs:t::v::?",
411 : long_options, &option_index);
412 :
413 3117 : if (c == -1)
414 : break;
415 :
416 2797 : switch (c) {
417 812 : case 0:
418 812 : if (strcmp(long_options[option_index].name, "in-memory") == 0) {
419 : inmemory = true;
420 : break;
421 : }
422 812 : if (strcmp(long_options[option_index].name, "dbpath") == 0) {
423 320 : size_t optarglen = strlen(optarg);
424 : /* remove trailing directory separator */
425 320 : while (optarglen > 0
426 320 : && (optarg[optarglen - 1] == '/'
427 320 : || optarg[optarglen - 1] == '\\'))
428 0 : optarg[--optarglen] = '\0';
429 320 : dbpath = absolute_path(optarg);
430 320 : if (dbpath == NULL)
431 0 : fprintf(stderr,
432 : "#error: can not allocate memory for dbpath\n");
433 : else
434 320 : setlen = mo_add_option(&set, setlen, opt_cmdline,
435 : "gdk_dbpath", dbpath);
436 : break;
437 : }
438 492 : if (strcmp(long_options[option_index].name, "dbextra") == 0) {
439 165 : if (dbextra)
440 0 : fprintf(stderr,
441 : "#warning: ignoring multiple --dbextra arguments\n");
442 : else
443 165 : dbextra = optarg;
444 : break;
445 : }
446 :
447 327 : if (strcmp(long_options[option_index].name, "dbtrace") == 0) {
448 0 : size_t optarglen = strlen(optarg);
449 : /* remove trailing directory separator */
450 0 : while (optarglen > 0
451 0 : && (optarg[optarglen - 1] == '/'
452 0 : || optarg[optarglen - 1] == '\\'))
453 0 : optarg[--optarglen] = '\0';
454 0 : dbtrace = absolute_path(optarg);
455 0 : if (dbtrace == NULL)
456 0 : fprintf(stderr,
457 : "#error: can not allocate memory for dbtrace\n");
458 : else
459 0 : setlen = mo_add_option(&set, setlen, opt_cmdline,
460 : "gdk_dbtrace", dbtrace);
461 : break;
462 : }
463 :
464 327 : if (strcmp(long_options[option_index].name, "single-user") == 0) {
465 0 : setlen = mo_add_option(&set, setlen, opt_cmdline,
466 : "gdk_single_user", "yes");
467 0 : break;
468 : }
469 327 : if (strcmp(long_options[option_index].name, "version") == 0) {
470 1 : monet_version();
471 1 : exit(0);
472 : }
473 : /* debugging options */
474 326 : if (strcmp(long_options[option_index].name, "algorithms") == 0) {
475 0 : grpdebug |= GRPalgorithms;
476 0 : break;
477 : }
478 326 : if (strcmp(long_options[option_index].name, "forcemito") == 0) {
479 321 : grpdebug |= GRPforcemito;
480 321 : break;
481 : }
482 5 : if (strcmp(long_options[option_index].name, "heaps") == 0) {
483 0 : grpdebug |= GRPheaps;
484 0 : break;
485 : }
486 5 : if (strcmp(long_options[option_index].name, "io") == 0) {
487 0 : grpdebug |= GRPio;
488 0 : break;
489 : }
490 5 : if (strcmp(long_options[option_index].name, "memory") == 0) {
491 0 : grpdebug |= GRPmemory;
492 0 : break;
493 : }
494 5 : if (strcmp(long_options[option_index].name, "modules") == 0) {
495 0 : grpdebug |= GRPmodules;
496 0 : break;
497 : }
498 5 : if (strcmp(long_options[option_index].name, "performance") == 0) {
499 0 : grpdebug |= GRPperformance;
500 0 : break;
501 : }
502 5 : if (strcmp(long_options[option_index].name, "properties") == 0) {
503 0 : grpdebug |= GRPproperties;
504 0 : break;
505 : }
506 5 : if (strcmp(long_options[option_index].name, "threads") == 0) {
507 0 : grpdebug |= GRPthreads;
508 0 : break;
509 : }
510 5 : if (strcmp(long_options[option_index].name, "transactions") == 0) {
511 0 : grpdebug |= GRPtransactions;
512 0 : break;
513 : }
514 5 : if (strcmp(long_options[option_index].name, "read-password-initialize-and-exit") == 0) {
515 : readpwdxit = true;
516 : break;
517 : }
518 5 : if (strcmp(long_options[option_index].name, "loadmodule") == 0) {
519 5 : if (mods < MAX_MODULES)
520 5 : modules[mods++] = optarg;
521 : else
522 0 : fprintf(stderr,
523 : "ERROR: maximum number of modules reached\n");
524 : break;
525 : }
526 0 : if (strcmp(long_options[option_index].name, "without-geom") == 0) {
527 0 : for (int i = 0; i < mods; i++) {
528 0 : if (strcmp(modules[i], "geom") == 0) {
529 0 : while (i + 1 < mods) {
530 0 : modules[i] = modules[i + 1];
531 0 : i++;
532 : }
533 0 : mods--;
534 0 : break;
535 : }
536 : }
537 : break;
538 : }
539 0 : usage(prog, -1);
540 : /* not reached */
541 0 : case 'c':
542 : /* coverity[var_deref_model] */
543 0 : setlen = mo_add_option(&set, setlen, opt_cmdline, "config", optarg);
544 0 : break;
545 320 : case 'd':
546 320 : if (optarg) {
547 320 : char *endarg;
548 320 : debug |= strtoul(optarg, &endarg, 10);
549 320 : if (*endarg != '\0') {
550 0 : fprintf(stderr, "ERROR: wrong format for --debug=%s\n",
551 : optarg);
552 0 : usage(prog, -1);
553 : }
554 : } else {
555 0 : debug |= CHECKMASK;
556 : }
557 : break;
558 3 : case 'r':
559 3 : setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_readonly",
560 : "yes");
561 3 : break;
562 1662 : case 's':{
563 : /* should add option to a list */
564 : /* coverity[var_deref_model] */
565 1662 : char *tmp = strchr(optarg, '=');
566 :
567 1662 : if (tmp) {
568 1662 : *tmp = '\0';
569 1662 : setlen = mo_add_option(&set, setlen, opt_cmdline, optarg,
570 1662 : tmp + 1);
571 : } else
572 0 : fprintf(stderr, "ERROR: wrong format %s\n", optarg);
573 : }
574 : break;
575 0 : case '?':
576 : /* a bit of a hack: look at the option that the
577 : current `c' is based on and see if we recognize
578 : it: if -? or --help, exit with 0, else with -1 */
579 0 : usage(prog, strcmp(av[optind - 1], "-?") == 0
580 0 : || strcmp(av[optind - 1], "--help") == 0 ? 0 : -1);
581 0 : default:
582 0 : fprintf(stderr,
583 : "ERROR: getopt returned character " "code '%c' 0%o\n", c,
584 : (unsigned) (uint8_t) c);
585 0 : usage(prog, -1);
586 : }
587 : }
588 :
589 320 : if (optind < argc)
590 0 : usage(prog, -1);
591 :
592 320 : if (!(setlen = mo_system_config(&set, setlen)))
593 0 : usage(prog, -1);
594 :
595 320 : if (debug)
596 320 : mo_print_options(set, setlen);
597 :
598 320 : if (dbpath && inmemory) {
599 0 : fprintf(stderr,
600 : "!ERROR: both dbpath and in-memory must not be set at the same time\n");
601 0 : exit(1);
602 : }
603 :
604 320 : if (inmemory && readpwdxit) {
605 0 : fprintf(stderr,
606 : "!ERROR: cannot have both in-memory and read-password-initialize-and-exit\n");
607 0 : exit(1);
608 : }
609 :
610 320 : if (inmemory) {
611 0 : if (BBPaddfarm(NULL, (1U << PERSISTENT) | (1U << TRANSIENT), true) !=
612 : GDK_SUCCEED) {
613 0 : fprintf(stderr, "!ERROR: cannot add in-memory farm\n");
614 0 : exit(1);
615 : }
616 : } else {
617 320 : if (dbpath == NULL) {
618 0 : dbpath = absolute_path(mo_find_option(set, setlen, "gdk_dbpath"));
619 0 : if (dbpath == NULL) {
620 0 : fprintf(stderr,
621 : "!ERROR: cannot allocate memory for database directory \n");
622 0 : exit(1);
623 : }
624 : }
625 320 : if (BBPaddfarm(dbpath, 1U << PERSISTENT, true) != GDK_SUCCEED
626 475 : || BBPaddfarm(dbextra ? dbextra : dbpath, 1U << TRANSIENT,
627 : true) != GDK_SUCCEED) {
628 0 : fprintf(stderr, "!ERROR: cannot add farm\n");
629 0 : exit(1);
630 : }
631 320 : GDKfree(dbpath);
632 : }
633 :
634 320 : if (dbtrace) {
635 : /* GDKcreatedir makes sure that all parent directories of dbtrace exist */
636 0 : if (!inmemory && GDKcreatedir(dbtrace) != GDK_SUCCEED) {
637 0 : fprintf(stderr, "!ERROR: cannot create directory for %s\n",
638 : dbtrace);
639 0 : exit(1);
640 : }
641 0 : GDKfree(dbtrace);
642 : }
643 :
644 320 : GDKsetdebug(debug | grpdebug); /* add the algorithm tracers */
645 320 : if (monet_init(set, setlen, false) == 0) {
646 2 : mo_free_options(set, setlen);
647 2 : if (GDKerrbuf && *GDKerrbuf)
648 0 : fprintf(stderr, "%s\n", GDKerrbuf);
649 2 : exit(1);
650 : }
651 318 : mo_free_options(set, setlen);
652 :
653 318 : if (GDKsetenv("monet_version", GDKversion()) != GDK_SUCCEED
654 318 : || GDKsetenv("monet_release",
655 : #ifdef MONETDB_RELEASE
656 : MONETDB_RELEASE
657 : #else
658 : "unreleased"
659 : #endif
660 : ) != GDK_SUCCEED) {
661 0 : fprintf(stderr, "!ERROR: GDKsetenv failed\n");
662 0 : exit(1);
663 : }
664 :
665 318 : if ((modpath = GDKgetenv("monet_mod_path")) == NULL) {
666 : /* start probing based on some heuristics given the binary
667 : * location:
668 : * bin/mserver5 -> ../
669 : * libX/monetdb5/lib/
670 : * probe libX = lib, lib32, lib64, lib/64 */
671 : size_t pref;
672 : /* "remove" common prefix of configured BIN and LIB
673 : * directories from LIBDIR */
674 20352 : for (pref = 0; LIBDIR[pref] != 0 && BINDIR[pref] == LIBDIR[pref];
675 20034 : pref++) ;
676 318 : const char *libdirs[] = {
677 318 : &LIBDIR[pref],
678 : "lib",
679 : "lib64",
680 : "lib/64",
681 : "lib32",
682 : NULL,
683 : };
684 318 : struct stat sb;
685 318 : if (binpath != NULL) {
686 318 : char *p = strrchr(binpath, DIR_SEP);
687 318 : if (p != NULL)
688 318 : *p = '\0';
689 318 : p = strrchr(binpath, DIR_SEP);
690 318 : if (p != NULL) {
691 318 : *p = '\0';
692 318 : for (int i = 0; libdirs[i] != NULL; i++) {
693 318 : int len = snprintf(prmodpath, sizeof(prmodpath),
694 : "%s%c%s%cmonetdb5-%s",
695 : binpath, DIR_SEP, libdirs[i], DIR_SEP,
696 : MONETDB_VERSION);
697 318 : if (len == -1 || len >= FILENAME_MAX)
698 0 : continue;
699 318 : if (MT_stat(prmodpath, &sb) == 0) {
700 : modpath = prmodpath;
701 : break;
702 : }
703 0 : len = snprintf(prmodpath, sizeof(prmodpath),
704 : "%s%c%s%cmonetdb5",
705 : binpath, DIR_SEP, libdirs[i], DIR_SEP);
706 0 : if (len == -1 || len >= FILENAME_MAX)
707 0 : continue;
708 0 : if (MT_stat(prmodpath, &sb) == 0) {
709 : modpath = prmodpath;
710 : break;
711 : }
712 : }
713 : } else {
714 0 : printf("#warning: unusable binary location, "
715 : "please use --set monet_mod_path=/path/to/... to "
716 : "allow finding modules\n");
717 0 : fflush(stdout);
718 : }
719 : } else {
720 0 : printf("#warning: unable to determine binary location, "
721 : "please use --set monet_mod_path=/path/to/... to "
722 : "allow finding modules\n");
723 0 : fflush(stdout);
724 : }
725 318 : if (modpath != NULL
726 318 : && GDKsetenv("monet_mod_path", modpath) != GDK_SUCCEED) {
727 0 : fprintf(stderr, "!ERROR: GDKsetenv failed\n");
728 0 : exit(1);
729 : }
730 : }
731 :
732 318 : if (!GDKinmemory(0)) {
733 : /* configure sabaoth to use the right dbpath and active database */
734 318 : msab_dbpathinit(GDKgetenv("gdk_dbpath"));
735 : /* wipe out all cruft, if left over */
736 318 : if ((err = msab_wildRetreat()) != NULL) {
737 : /* just swallow the error */
738 0 : free(err);
739 : }
740 : /* From this point, the server should exit cleanly. Discussion:
741 : * even earlier? Sabaoth here registers the server is starting up. */
742 318 : if ((err = msab_registerStarting()) != NULL) {
743 : /* throw the error at the user, but don't die */
744 0 : fprintf(stderr, "!%s\n", err);
745 0 : free(err);
746 : }
747 : }
748 :
749 : #ifdef HAVE_SIGACTION
750 : {
751 318 : struct sigaction sa;
752 :
753 318 : (void) sigemptyset(&sa.sa_mask);
754 318 : sa.sa_flags = 0;
755 318 : sa.sa_handler = handler;
756 318 : if (sigaction(SIGINT, &sa, NULL) == -1
757 318 : || sigaction(SIGQUIT, &sa, NULL) == -1
758 318 : || sigaction(SIGTERM, &sa, NULL) == -1) {
759 0 : fprintf(stderr, "!unable to create signal handlers\n");
760 : }
761 318 : (void) sigemptyset(&sa.sa_mask);
762 318 : sa.sa_flags = 0;
763 318 : sa.sa_handler = handler_usr1;
764 318 : if (sigaction(SIGUSR1, &sa, NULL) == -1) {
765 0 : fprintf(stderr, "!unable to create signal handler for SIGUSR1\n");
766 : }
767 : }
768 : #else
769 : #ifdef _MSC_VER
770 : if (!SetConsoleCtrlHandler(winhandler, TRUE))
771 : fprintf(stderr, "!unable to create console control handler\n");
772 : #else
773 : if (signal(SIGINT, handler) == SIG_ERR)
774 : fprintf(stderr, "!unable to create signal handlers\n");
775 : #ifdef SIGQUIT
776 : if (signal(SIGQUIT, handler) == SIG_ERR)
777 : fprintf(stderr, "!unable to create signal handlers\n");
778 : #endif
779 : if (signal(SIGTERM, handler) == SIG_ERR)
780 : fprintf(stderr, "!unable to create signal handlers\n");
781 : if (signal(SIGUSR1, handler_usr1) == SIG_ERR)
782 : fprintf(stderr, "!unable to create signal handler for SIGUSR1\n");
783 : #endif
784 : #endif
785 :
786 318 : if (!GDKinmemory(0)) {
787 318 : str lang = "mal";
788 : /* we inited mal before, so publish its existence */
789 318 : if ((err = msab_marchScenario(lang)) != NULL) {
790 : /* throw the error at the user, but don't die */
791 0 : fprintf(stderr, "!%s\n", err);
792 0 : free(err);
793 : }
794 : }
795 :
796 318 : char secret[1024];
797 : {
798 : /* unlock the vault, first see if we can find the file which
799 : * holds the secret */
800 318 : FILE *secretf;
801 318 : size_t len;
802 :
803 318 : if (GDKinmemory(0) || GDKgetenv("monet_vault_key") == NULL) {
804 : /* use a default (hard coded, non safe) key */
805 147 : snprintf(secret, sizeof(secret), "%s", "Xas632jsi2whjds8");
806 : } else {
807 171 : if ((secretf = MT_fopen(GDKgetenv("monet_vault_key"), "r")) == NULL) {
808 0 : fprintf(stderr, "unable to open vault_key_file %s: %s\n",
809 0 : GDKgetenv("monet_vault_key"), strerror(errno));
810 : /* don't show this as a crash */
811 0 : msab_registerStop();
812 0 : exit(1);
813 : }
814 171 : len = fread(secret, 1, sizeof(secret), secretf);
815 171 : secret[len] = '\0';
816 171 : len = strlen(secret); /* secret can contain null-bytes */
817 171 : if (len == 0) {
818 0 : fprintf(stderr, "vault key has zero-length!\n");
819 : /* don't show this as a crash */
820 0 : msab_registerStop();
821 0 : exit(1);
822 171 : } else if (len < 5) {
823 0 : fprintf(stderr,
824 : "#warning: your vault key is too short "
825 : "(%zu), enlarge your vault key!\n", len);
826 : }
827 171 : fclose(secretf);
828 : }
829 318 : if ((err = AUTHunlockVault(secret)) != MAL_SUCCEED) {
830 : /* don't show this as a crash */
831 0 : if (!GDKinmemory(0))
832 0 : msab_registerStop();
833 0 : fprintf(stderr, "%s\n", err);
834 0 : freeException(err);
835 0 : exit(1);
836 : }
837 318 : if (readpwdxit) {
838 0 : char *secretp;
839 0 : if (fgets(secret, (int) sizeof(secret), stdin) == NULL) {
840 0 : fprintf(stderr, "!ERROR: no password read\n");
841 0 : exit(1);
842 : }
843 0 : if ((secretp = strchr(secret, '\n')) == NULL) {
844 0 : fprintf(stderr, "!ERROR: password too long\n");
845 0 : exit(1);
846 : }
847 0 : *secretp = '\0';
848 : }
849 : }
850 :
851 318 : modules[mods++] = 0;
852 636 : if (mal_init(modules, false, readpwdxit ? secret : NULL, mercurial_revision())) {
853 : /* don't show this as a crash */
854 0 : if (!GDKinmemory(0))
855 0 : msab_registerStop();
856 0 : return 1;
857 : }
858 317 : if (readpwdxit) {
859 0 : msab_registerStop();
860 0 : return 0;
861 : }
862 :
863 317 : emergencyBreakpoint();
864 :
865 317 : if (!GDKinmemory(0) && (err = msab_registerStarted()) != NULL) {
866 : /* throw the error at the user, but don't die */
867 0 : fprintf(stderr, "!%s\n", err);
868 0 : free(err);
869 : }
870 :
871 : /* return all our free bats to global pool */
872 317 : BBPrelinquishbats();
873 :
874 : #ifdef _MSC_VER
875 : printf("# MonetDB server is started. To stop server press Ctrl-C.\n");
876 : fflush(stdout);
877 : #endif
878 :
879 : /* why busy wait ? */
880 15729 : while (!interrupted && !GDKexiting()) {
881 15412 : if (usr1_interrupted) {
882 116 : usr1_interrupted = 0;
883 : /* print some useful information */
884 116 : GDKprintinfo();
885 116 : fflush(stdout);
886 : }
887 15412 : MT_sleep_ms(100); /* pause(), except for sys.shutdown() */
888 : }
889 :
890 : /* mal_exit calls exit, so statements after this call will
891 : * never get reached */
892 317 : mal_exit(0);
893 :
894 : return 0;
895 : }
|