/* * The MonetDB server uses a startup script to boot the system. * This script is an ordinary MAL program, but will mostly * consist of include statements to load modules of general interest. * The startup script is run as user Admin. */ int malBootstrap(void) { Client c; str msg, bootfile = "mal_init", s; c = MCinitClient((oid) 0, 0, 0); assert(c != NULL); c->nspace = newModule(NULL, putName("user", 4)); initLibraries(); if ( (msg = defaultScenario(c)) ) { GDKfree(msg); GDKerror("Failed to initialise default scenario"); return 0; } MSinitClientPrg(c, "user", "main"); (void) MCinitClientThread(c); s = malInclude(c, bootfile, 0); if (s != NULL) { mnstr_printf(GDKout, "!%s\n", s); GDKfree(s); return 0; } pushEndInstruction(c->curprg->def); chkProgram(c->fdout, c->nspace, c->curprg->def); if (c->curprg->def->errors) showErrors(c); s = MALengine(c); if (s) GDKfree(s); return 1; }
int main(int argc, char **av) { char *prog = *av; opt *set = NULL; int i, grpdebug = 0, debug = 0, setlen = 0, listing = 0; str err = MAL_SUCCEED; char prmodpath[FILENAME_MAX]; const char *modpath = NULL; char *binpath = NULL; str *monet_script; char *dbpath = NULL; char *dbextra = NULL; int verbosity = 0; static struct option long_options[] = { { "config", required_argument, NULL, 'c' }, { "dbpath", required_argument, NULL, 0 }, { "dbextra", required_argument, NULL, 0 }, { "daemon", required_argument, NULL, 0 }, { "debug", optional_argument, NULL, 'd' }, { "help", no_argument, NULL, '?' }, { "version", no_argument, NULL, 0 }, { "verbose", optional_argument, NULL, 'v' }, { "readonly", no_argument, NULL, 'r' }, { "single-user", no_argument, NULL, 0 }, { "set", required_argument, NULL, 's' }, { "threads", no_argument, NULL, 0 }, { "memory", no_argument, NULL, 0 }, { "properties", no_argument, NULL, 0 }, { "io", no_argument, NULL, 0 }, { "transactions", no_argument, NULL, 0 }, { "trace", optional_argument, NULL, 't' }, { "modules", no_argument, NULL, 0 }, { "algorithms", no_argument, NULL, 0 }, { "optimizers", no_argument, NULL, 0 }, { "performance", no_argument, NULL, 0 }, { "forcemito", no_argument, NULL, 0 }, { "heaps", no_argument, NULL, 0 }, { NULL, 0, NULL, 0 } }; #if defined(_MSC_VER) && defined(__cplusplus) set_terminate(mserver_abort); #endif #ifdef _MSC_VER _CrtSetReportMode(_CRT_ERROR, 0); _CrtSetReportMode(_CRT_ASSERT, 0); _set_invalid_parameter_handler(mserver_invalid_parameter_handler); #ifdef _TWO_DIGIT_EXPONENT _set_output_format(_TWO_DIGIT_EXPONENT); #endif #endif if (setlocale(LC_CTYPE, "") == NULL) { fprintf(stderr, "cannot set locale\n"); exit(1); } if (getcwd(monet_cwd, FILENAME_MAX - 1) == NULL) { perror("pwd"); fprintf(stderr,"monet_init: could not determine current directory\n"); exit(-1); } /* retrieve binpath early (before monet_init) because some * implementations require the working directory when the binary was * called */ binpath = get_bin_path(); if (!(setlen = mo_builtin_settings(&set))) usage(prog, -1); for (;;) { int option_index = 0; int c = getopt_long(argc, av, "c:d::rs:t::v::?", long_options, &option_index); if (c == -1) break; switch (c) { case 0: if (strcmp(long_options[option_index].name, "dbpath") == 0) { size_t optarglen = strlen(optarg); /* remove trailing directory separator */ while (optarglen > 0 && (optarg[optarglen - 1] == '/' || optarg[optarglen - 1] == '\\')) optarg[--optarglen] = '\0'; dbpath = absolute_path(optarg); if( dbpath == NULL) fprintf(stderr, "#error: can not allocate memory for dbpath\n"); else setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_dbpath", dbpath); break; } if (strcmp(long_options[option_index].name, "dbextra") == 0) { if (dbextra) fprintf(stderr, "#warning: ignoring multiple --dbextra arguments\n"); else dbextra = optarg; break; } #ifdef HAVE_CONSOLE if (strcmp(long_options[option_index].name, "daemon") == 0) { setlen = mo_add_option(&set, setlen, opt_cmdline, "monet_daemon", optarg); break; } #endif if (strcmp(long_options[option_index].name, "single-user") == 0) { setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_single_user", "yes"); break; } if (strcmp(long_options[option_index].name, "version") == 0) { monet_version(); exit(0); } /* debugging options */ if (strcmp(long_options[option_index].name, "properties") == 0) { grpdebug |= GRPproperties; break; } if (strcmp(long_options[option_index].name, "algorithms") == 0) { grpdebug |= GRPalgorithms; break; } if (strcmp(long_options[option_index].name, "optimizers") == 0) { grpdebug |= GRPoptimizers; break; } if (strcmp(long_options[option_index].name, "forcemito") == 0) { grpdebug |= GRPforcemito; break; } if (strcmp(long_options[option_index].name, "performance") == 0) { grpdebug |= GRPperformance; break; } if (strcmp(long_options[option_index].name, "io") == 0) { grpdebug |= GRPio; break; } if (strcmp(long_options[option_index].name, "memory") == 0) { grpdebug |= GRPmemory; break; } if (strcmp(long_options[option_index].name, "modules") == 0) { grpdebug |= GRPmodules; break; } if (strcmp(long_options[option_index].name, "transactions") == 0) { grpdebug |= GRPtransactions; break; } if (strcmp(long_options[option_index].name, "threads") == 0) { grpdebug |= GRPthreads; break; } if (strcmp(long_options[option_index].name, "trace") == 0) { mal_trace = 1; break; } if (strcmp(long_options[option_index].name, "heaps") == 0) { grpdebug |= GRPheaps; break; } usage(prog, -1); /* not reached */ case 'c': /* coverity[var_deref_model] */ setlen = mo_add_option(&set, setlen, opt_cmdline, "config", optarg); break; case 'd': if (optarg) { char *endarg; debug |= strtol(optarg, &endarg, 10); if (*endarg != '\0') { fprintf(stderr, "ERROR: wrong format for --debug=%s\n", optarg); usage(prog, -1); } } else { debug |= 1; } break; case 'r': setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_readonly", "yes"); break; case 's': { /* should add option to a list */ /* coverity[var_deref_model] */ char *tmp = strchr(optarg, '='); if (tmp) { *tmp = '\0'; setlen = mo_add_option(&set, setlen, opt_cmdline, optarg, tmp + 1); } else fprintf(stderr, "ERROR: wrong format %s\n", optarg); } break; case 't': mal_trace = 1; break; case 'v': if (optarg) { char *endarg; verbosity = (int) strtol(optarg, &endarg, 10); if (*endarg != '\0') { fprintf(stderr, "ERROR: wrong format for --verbose=%s\n", optarg); usage(prog, -1); } } else { verbosity++; } break; case '?': /* a bit of a hack: look at the option that the current `c' is based on and see if we recognize it: if -? or --help, exit with 0, else with -1 */ usage(prog, strcmp(av[optind - 1], "-?") == 0 || strcmp(av[optind - 1], "--help") == 0 ? 0 : -1); default: fprintf(stderr, "ERROR: getopt returned character " "code '%c' 0%o\n", c, (uint8_t) c); usage(prog, -1); } } if (!(setlen = mo_system_config(&set, setlen))) usage(prog, -1); GDKsetdebug(debug | grpdebug); /* add the algorithm tracers */ if (debug) mo_print_options(set, setlen); GDKsetverbose(verbosity); monet_script = (str *) malloc(sizeof(str) * (argc + 1)); if (monet_script == NULL) { fprintf(stderr, "!ERROR: cannot allocate memory for script \n"); exit(1); } i = 0; while (optind < argc) { monet_script[i] = absolute_path(av[optind]); if (monet_script[i] == NULL) { fprintf(stderr, "!ERROR: cannot allocate memory for script \n"); exit(1); } i++; optind++; } monet_script[i] = NULL; if (!dbpath) { dbpath = absolute_path(mo_find_option(set, setlen, "gdk_dbpath")); if (!dbpath) { fprintf(stderr, "!ERROR: cannot allocate memory for database directory \n"); exit(1); } } if (BBPaddfarm(dbpath, 1 << PERSISTENT) != GDK_SUCCEED || BBPaddfarm(dbextra ? dbextra : dbpath, 1 << TRANSIENT) != GDK_SUCCEED) { fprintf(stderr, "!ERROR: cannot add farm\n"); exit(1); } if (GDKcreatedir(dbpath) != GDK_SUCCEED) { fprintf(stderr, "!ERROR: cannot create directory for %s\n", dbpath); exit(1); } GDKfree(dbpath); if (monet_init(set, setlen) == 0) { mo_free_options(set, setlen); if (GDKerrbuf && *GDKerrbuf) fprintf(stderr, "%s\n", GDKerrbuf); exit(1); } mo_free_options(set, setlen); if (GDKsetenv("monet_version", GDKversion()) != GDK_SUCCEED || GDKsetenv("monet_release", #ifdef MONETDB_RELEASE MONETDB_RELEASE #else "unreleased" #endif ) != GDK_SUCCEED) { fprintf(stderr, "!ERROR: GDKsetenv failed\n"); exit(1); } if ((modpath = GDKgetenv("monet_mod_path")) == NULL) { /* start probing based on some heuristics given the binary * location: * bin/mserver5 -> ../ * libX/monetdb5/lib/ * probe libX = lib, lib32, lib64, lib/64 */ size_t pref; /* "remove" common prefix of configured BIN and LIB * directories from LIBDIR */ for (pref = 0; LIBDIR[pref] != 0 && BINDIR[pref] == LIBDIR[pref]; pref++) ; const char *libdirs[] = { &LIBDIR[pref], "lib", "lib64", "lib/64", "lib32", NULL, }; struct stat sb; if (binpath != NULL) { char *p = strrchr(binpath, DIR_SEP); if (p != NULL) *p = '\0'; p = strrchr(binpath, DIR_SEP); if (p != NULL) { *p = '\0'; for (i = 0; libdirs[i] != NULL; i++) { int len = snprintf(prmodpath, sizeof(prmodpath), "%s%c%s%cmonetdb5", binpath, DIR_SEP, libdirs[i], DIR_SEP); if (len == -1 || len >= FILENAME_MAX) continue; if (stat(prmodpath, &sb) == 0) { modpath = prmodpath; break; } } } else { printf("#warning: unusable binary location, " "please use --set monet_mod_path=/path/to/... to " "allow finding modules\n"); fflush(NULL); } } else { printf("#warning: unable to determine binary location, " "please use --set monet_mod_path=/path/to/... to " "allow finding modules\n"); fflush(NULL); } if (modpath != NULL && GDKsetenv("monet_mod_path", modpath) != GDK_SUCCEED) { fprintf(stderr, "!ERROR: GDKsetenv failed\n"); exit(1); } } /* configure sabaoth to use the right dbpath and active database */ msab_dbpathinit(GDKgetenv("gdk_dbpath")); /* wipe out all cruft, if left over */ if ((err = msab_wildRetreat()) != NULL) { /* just swallow the error */ free(err); } /* From this point, the server should exit cleanly. Discussion: * even earlier? Sabaoth here registers the server is starting up. */ if ((err = msab_registerStarting()) != NULL) { /* throw the error at the user, but don't die */ fprintf(stderr, "!%s\n", err); free(err); } #ifdef HAVE_SIGACTION { struct sigaction sa; (void) sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; if (sigaction(SIGINT, &sa, NULL) == -1 || sigaction(SIGQUIT, &sa, NULL) == -1 || sigaction(SIGTERM, &sa, NULL) == -1) { fprintf(stderr, "!unable to create signal handlers\n"); } } #else #ifdef _MSC_VER if (!SetConsoleCtrlHandler(winhandler, TRUE)) fprintf(stderr, "!unable to create console control handler\n"); #else if(signal(SIGINT, handler) == SIG_ERR) fprintf(stderr, "!unable to create signal handlers\n"); #ifdef SIGQUIT if(signal(SIGQUIT, handler) == SIG_ERR) fprintf(stderr, "!unable to create signal handlers\n"); #endif if(signal(SIGTERM, handler) == SIG_ERR) fprintf(stderr, "!unable to create signal handlers\n"); #endif #endif { str lang = "mal"; /* we inited mal before, so publish its existence */ if ((err = msab_marchScenario(lang)) != NULL) { /* throw the error at the user, but don't die */ fprintf(stderr, "!%s\n", err); free(err); } } { /* unlock the vault, first see if we can find the file which * holds the secret */ char secret[1024]; char *secretp = secret; FILE *secretf; size_t len; if (GDKgetenv("monet_vault_key") == NULL) { /* use a default (hard coded, non safe) key */ snprintf(secret, sizeof(secret), "%s", "Xas632jsi2whjds8"); } else { if ((secretf = fopen(GDKgetenv("monet_vault_key"), "r")) == NULL) { fprintf(stderr, "unable to open vault_key_file %s: %s\n", GDKgetenv("monet_vault_key"), strerror(errno)); /* don't show this as a crash */ msab_registerStop(); exit(1); } len = fread(secret, 1, sizeof(secret), secretf); secret[len] = '\0'; len = strlen(secret); /* secret can contain null-bytes */ if (len == 0) { fprintf(stderr, "vault key has zero-length!\n"); /* don't show this as a crash */ msab_registerStop(); exit(1); } else if (len < 5) { fprintf(stderr, "#warning: your vault key is too short " "(%zu), enlarge your vault key!\n", len); } fclose(secretf); } if ((err = AUTHunlockVault(secretp)) != MAL_SUCCEED) { /* don't show this as a crash */ msab_registerStop(); fprintf(stderr, "%s\n", err); freeException(err); exit(1); } } /* make sure the authorisation BATs are loaded */ if ((err = AUTHinitTables(NULL)) != MAL_SUCCEED) { /* don't show this as a crash */ msab_registerStop(); fprintf(stderr, "%s\n", err); freeException(err); exit(1); } if (mal_init()) { /* don't show this as a crash */ msab_registerStop(); return 0; } if((err = MSinitClientPrg(mal_clients, "user", "main")) != MAL_SUCCEED) { msab_registerStop(); fprintf(stderr, "%s\n", err); freeException(err); exit(1); } emergencyBreakpoint(); for (i = 0; monet_script[i]; i++) { str msg = evalFile(monet_script[i], listing); /* check for internal exception message to terminate */ if (msg) { if (strcmp(msg, "MALException:client.quit:Server stopped.") == 0) mal_exit(0); fprintf(stderr, "#%s: %s\n", monet_script[i], msg); freeException(msg); } GDKfree(monet_script[i]); monet_script[i] = 0; } free(monet_script); if ((err = msab_registerStarted()) != NULL) { /* throw the error at the user, but don't die */ fprintf(stderr, "!%s\n", err); free(err); } #ifdef HAVE_CONSOLE if (!monet_daemon) { MSserveClient(mal_clients); } else #endif while (!interrupted && !GDKexiting()) { MT_sleep_ms(100); } /* mal_exit calls exit, so statements after this call will * never get reached */ mal_exit(0); return 0; }
int main(int argc, char **av) { char *prog = *av; opt *set = NULL; int idx = 0, grpdebug = 0, debug = 0, setlen = 0, listing = 0, i = 0; str dbinit = NULL; str err = MAL_SUCCEED; char prmodpath[1024]; char *modpath = NULL; char *binpath = NULL; str *monet_script; static struct option long_options[] = { { "config", 1, 0, 'c' }, { "dbpath", 1, 0, 0 }, { "dbinit", 1, 0, 0 }, { "debug", 2, 0, 'd' }, { "help", 0, 0, '?' }, { "version", 0, 0, 0 }, { "readonly", 0, 0, 'r' }, { "set", 1, 0, 's' }, { "threads", 0, 0, 0 }, { "memory", 0, 0, 0 }, { "properties", 0, 0, 0 }, { "io", 0, 0, 0 }, { "transactions", 0, 0, 0 }, { "trace", 2, 0, 't' }, { "modules", 0, 0, 0 }, { "algorithms", 0, 0, 0 }, { "optimizers", 0, 0, 0 }, { "performance", 0, 0, 0 }, #if 0 { "xproperties", 0, 0, 0 }, #endif { "forcemito", 0, 0, 0 }, { "heaps", 0, 0, 0 }, { 0, 0, 0, 0 } }; #if defined(_MSC_VER) && defined(__cplusplus) set_terminate(mserver_abort); #endif if (setlocale(LC_CTYPE, "") == NULL) { GDKfatal("cannot set locale\n"); } #ifdef HAVE_MALLOPT if (malloc_init) { /* for (Red Hat) Linux (6.2) unused and ignored at least as of glibc-2.1.3-15 */ /* for (Red Hat) Linux (8) used at least as of glibc-2.2.93-5 */ if (mallopt(M_MXFAST, 192)) { fprintf(stderr, "!monet: mallopt(M_MXFAST,192) fails.\n"); } #ifdef M_BLKSZ if (mallopt(M_BLKSZ, 8 * 1024)) { fprintf(stderr, "!monet: mallopt(M_BLKSZ,8*1024) fails.\n"); } #endif } malloc_init = 0; #else (void) malloc_init; /* still unused */ #endif if (getcwd(monet_cwd, PATHLENGTH - 1) == NULL) { perror("pwd"); GDKfatal("monet_init: could not determine current directory\n"); } /* retrieve binpath early (before monet_init) because some * implementations require the working directory when the binary was * called */ binpath = get_bin_path(); if (!(setlen = mo_builtin_settings(&set))) usage(prog, -1); setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_single_user", "yes"); for (;;) { int option_index = 0; int c = getopt_long(argc, av, "c:d::rs:t::?", long_options, &option_index); if (c == -1) break; switch (c) { case 0: if (strcmp(long_options[option_index].name, "dbpath") == 0) { size_t optarglen = strlen(optarg); /* remove trailing directory separator */ while (optarglen > 0 && (optarg[optarglen - 1] == '/' || optarg[optarglen - 1] == '\\')) optarg[--optarglen] = '\0'; setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_dbpath", optarg); break; } if (strcmp(long_options[option_index].name, "dbinit") == 0) { if (dbinit) fprintf(stderr, "#warning: ignoring multiple --dbinit argument\n"); else dbinit = optarg; break; } if (strcmp(long_options[option_index].name, "version") == 0) { monet_version(); exit(0); } /* debugging options */ if (strcmp(long_options[option_index].name, "properties") == 0) { grpdebug |= GRPproperties; break; } if (strcmp(long_options[option_index].name, "algorithms") == 0) { grpdebug |= GRPalgorithms; break; } if (strcmp(long_options[option_index].name, "optimizers") == 0) { grpdebug |= GRPoptimizers; break; } #if 0 if (strcmp(long_options[option_index].name, "xproperties") == 0) { grpdebug |= GRPxproperties; break; } #endif if (strcmp(long_options[option_index].name, "forcemito") == 0) { grpdebug |= GRPforcemito; break; } if (strcmp(long_options[option_index].name, "performance") == 0) { grpdebug |= GRPperformance; break; } if (strcmp(long_options[option_index].name, "io") == 0) { grpdebug |= GRPio; break; } if (strcmp(long_options[option_index].name, "memory") == 0) { grpdebug |= GRPmemory; break; } if (strcmp(long_options[option_index].name, "modules") == 0) { grpdebug |= GRPmodules; break; } if (strcmp(long_options[option_index].name, "transactions") == 0) { grpdebug |= GRPtransactions; break; } if (strcmp(long_options[option_index].name, "threads") == 0) { grpdebug |= GRPthreads; break; } if (strcmp(long_options[option_index].name, "trace") == 0) { mal_trace = optarg? optarg:"ISTest"; break; } if (strcmp(long_options[option_index].name, "heaps") == 0) { grpdebug |= GRPheaps; break; } usage(prog, -1); /* not reached */ case 'c': setlen = mo_add_option(&set, setlen, opt_cmdline, "config", optarg); break; case 'd': if (optarg) { debug |= strtol(optarg, NULL, 10); } else { debug |= 1; } break; case 'r': setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_readonly", "yes"); break; case 's': { /* should add option to a list */ char *tmp = strchr(optarg, '='); if (tmp) { *tmp = '\0'; setlen = mo_add_option(&set, setlen, opt_cmdline, optarg, tmp + 1); } else fprintf(stderr, "ERROR: wrong format %s\n", optarg); } break; case 't': mal_trace = optarg? optarg:"ISTest"; break; case '?': /* a bit of a hack: look at the option that the current `c' is based on and see if we recognize it: if -? or --help, exit with 0, else with -1 */ usage(prog, strcmp(av[optind - 1], "-?") == 0 || strcmp(av[optind - 1], "--help") == 0 ? 0 : -1); default: fprintf(stderr, "ERROR: getopt returned character " "code '%c' 0%o\n", c, c); usage(prog, -1); } } if (!(setlen = mo_system_config(&set, setlen))) usage(prog, -1); if (debug || grpdebug) { long_str buf; if (debug) mo_print_options(set, setlen); debug |= grpdebug; /* add the algorithm tracers */ snprintf(buf, sizeof(long_str) - 1, "%d", debug); setlen = mo_add_option(&set, setlen, opt_cmdline, "gdk_debug", buf); } #ifdef RDEBUG printf("parameter ok\n"); #endif monet_script = (str *) malloc(sizeof(str) * (argc + 1)); if (monet_script) { monet_script[idx] = NULL; while (optind < argc) { monet_script[idx] = absolute_path(av[optind]); monet_script[idx + 1] = NULL; optind++; idx++; } } if (monet_init(set, setlen) == 0) { mo_free_options(set, setlen); return 0; } mo_free_options(set, setlen); #ifdef RDEBUG printf("monet_init ok\n"); #endif GDKsetenv("monet_version", VERSION); GDKsetenv("monet_release", MONETDB_RELEASE); if ((modpath = GDKgetenv("monet_mod_path")) == NULL) { /* start probing based on some heuristics given the binary * location: * bin/mserver5 -> ../ * libX/monetdb5/lib/ * probe libX = lib, lib32, lib64, lib/64 */ char *libdirs[] = { "lib", "lib64", "lib/64", "lib32", NULL }; size_t i; struct stat sb; if (binpath != NULL) { char *p = strrchr(binpath, DIR_SEP); if (p != NULL) *p = '\0'; p = strrchr(binpath, DIR_SEP); if (p != NULL) { *p = '\0'; for (i = 0; libdirs[i] != NULL; i++) { snprintf(prmodpath, sizeof(prmodpath), "%s%c%s%cmonetdb5", binpath, DIR_SEP, libdirs[i], DIR_SEP); if (stat(prmodpath, &sb) == 0) { modpath = prmodpath; break; } } } else { printf("#warning: unusable binary location, " "please use --set monet_mod_path=/path/to/... to " "allow finding modules\n"); fflush(NULL); } } else { printf("#warning: unable to determine binary location, " "please use --set monet_mod_path=/path/to/... to " "allow finding modules\n"); fflush(NULL); } if (modpath != NULL) GDKsetenv("monet_mod_path", modpath); } #ifdef RDEBUG printf("modpath ok\n"); #endif /* configure sabaoth to use the right dbpath and active database */ msab_dbpathinit(GDKgetenv("gdk_dbpath")); /* wipe out all cruft, if left over */ if ((err = msab_wildRetreat()) != NULL) { /* just swallow the error */ free(err); } /* From this point, the server should exit cleanly. Discussion: * even earlier? Sabaoth here registers the server is starting up. */ if ((err = msab_registerStarting()) != NULL) { /* throw the error at the user, but don't die */ fprintf(stderr, "!%s\n", err); free(err); } #ifdef RDEBUG printf("some stuff\n"); #endif #ifdef HAVE_SIGACTION { struct sigaction sa; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = handler; if ( sigaction(SIGINT, &sa, NULL) == -1 || sigaction(SIGQUIT, &sa, NULL) == -1 || sigaction(SIGTERM, &sa, NULL) == -1) { fprintf(stderr, "!unable to create signal handlers\n"); } } #else signal(SIGINT, handler); #ifdef SIGQUIT signal(SIGQUIT, handler); #endif signal(SIGTERM, handler); #endif { str lang = "mal"; /* we inited mal before, so publish its existence */ if ((err = msab_marchScenario(lang)) != NULL) { /* throw the error at the user, but don't die */ fprintf(stderr, "!%s\n", err); free(err); } } #ifdef RDEBUG printf("scenario ok\n"); #endif { /* unlock the vault, first see if we can find the file which * holds the secret */ char secret[1024]; char *secretp = secret; FILE *secretf; size_t len; if (GDKgetenv("monet_vault_key") == NULL) { /* use a default (hard coded, non safe) key */ snprintf(secret, sizeof(secret), "%s", "Xas632jsi2whjds8"); } else { if ((secretf = fopen(GDKgetenv("monet_vault_key"), "r")) == NULL) { snprintf(secret, sizeof(secret), "unable to open vault_key_file %s: %s", GDKgetenv("monet_vault_key"), strerror(errno)); /* don't show this as a crash */ msab_registerStop(); GDKfatal("%s", secret); } len = fread(secret, 1, sizeof(secret), secretf); secret[len] = '\0'; len = strlen(secret); /* secret can contain null-bytes */ if (len == 0) { snprintf(secret, sizeof(secret), "vault key has zero-length!"); /* don't show this as a crash */ msab_registerStop(); GDKfatal("%s", secret); } else if (len < 5) { fprintf(stderr, "#warning: your vault key is too short " "(" SZFMT "), enlarge your vault key!\n", len); } fclose(secretf); } if ((err = AUTHunlockVault(&secretp)) != MAL_SUCCEED) { /* don't show this as a crash */ msab_registerStop(); GDKfatal("%s", err); } } /* make sure the authorisation BATs are loaded */ if ((err = AUTHinitTables()) != MAL_SUCCEED) { /* don't show this as a crash */ msab_registerStop(); GDKfatal("%s", err); } #ifdef RDEBUG printf("vaultkey ok\n"); #endif if (mal_init()) { /* don't show this as a crash */ msab_registerStop(); return 0; } #ifdef RDEBUG printf("mal_init ok\n"); #endif #if (0) if (!loadLibrary("lib_leaker", TRUE)) return 42; #endif #ifdef RDEBUG printf("lib_leaker ok\n"); #endif if (GDKgetenv("mal_listing")) sscanf(GDKgetenv("mal_listing"), "%d", &listing); MSinitClientPrg(mal_clients, "user", "main"); if (dbinit == NULL) dbinit = GDKgetenv("dbinit"); if (dbinit) callString(mal_clients, dbinit, listing); #ifdef RDEBUG printf("MSinitClientPrg ok\n"); #endif emergencyBreakpoint(); if ((err = compileOptimizer(mal_clients, "leaker_pipe")) != MAL_SUCCEED) mnstr_printf(mal_clients->fdout, "OPT_COMPILE: %s\n", err); //callString(mal_clients, "sql.start();\n", 0); if (monet_script) for (i = 0; monet_script[i]; i++) { str msg = evalFile(mal_clients, monet_script[i], listing); /* check for internal exception message to terminate */ if (msg) { if (strcmp(msg, "MALException:client.quit:Server stopped.") == 0) mal_exit(); fprintf(stderr, "#%s: %s\n", monet_script[i], msg); GDKfree(msg); } GDKfree(monet_script[i]); monet_script[i] = 0; } if ((err = msab_registerStarted()) != NULL) { /* throw the error at the user, but don't die */ fprintf(stderr, "!%s\n", err); free(err); } if (monet_script) free(monet_script); MSserveClient(mal_clients); /* mal_exit calls MT_global_exit, so statements after this call will * never get reached */ mal_exit(); return 0; }
/* * BEWARE: SQLstatementIntern only commits after all statements found * in expr are executed, when autocommit mode is enabled. * * The tricky part for this statement is to ensure that the SQL statement * is executed within the client context specified. This leads to context juggling. */ str SQLstatementIntern(Client c, str *expr, str nme, int execute, bit output, res_table **result) { int status = 0; int err = 0; mvc *o, *m; int ac, sizevars, topvars; sql_var *vars; int oldvtop, oldstop = 1; buffer *b; char *n; stream *buf; str msg = MAL_SUCCEED; backend *be, *sql = (backend *) c->sqlcontext; size_t len = strlen(*expr); #ifdef _SQL_COMPILE mnstr_printf(c->fdout, "#SQLstatement:%s\n", *expr); #endif if (!sql) { msg = SQLinitEnvironment(c, NULL, NULL, NULL); sql = (backend *) c->sqlcontext; } if (msg){ GDKfree(msg); throw(SQL, "SQLstatement", "Catalogue not available"); } initSQLreferences(); m = sql->mvc; ac = m->session->auto_commit; o = MNEW(mvc); if (!o) throw(SQL, "SQLstatement", "Out of memory"); *o = *m; /* create private allocator */ m->sa = NULL; SQLtrans(m); status = m->session->status; m->type = Q_PARSE; be = sql; sql = backend_create(m, c); sql->output_format = be->output_format; m->qc = NULL; m->caching = 0; m->user_id = m->role_id = USER_MONETDB; if (result) m->reply_size = -2; /* do not cleanup, result tables */ /* mimick a client channel on which the query text is received */ b = (buffer *) GDKmalloc(sizeof(buffer)); n = GDKmalloc(len + 1 + 1); strncpy(n, *expr, len); n[len] = '\n'; n[len + 1] = 0; len++; buffer_init(b, n, len); buf = buffer_rastream(b, "sqlstatement"); scanner_init(&m->scanner, bstream_create(buf, b->len), NULL); m->scanner.mode = LINE_N; bstream_next(m->scanner.rs); m->params = NULL; m->argc = 0; m->session->auto_commit = 0; if (!m->sa) m->sa = sa_create(); /* * System has been prepared to parse it and generate code. * Scan the complete string for SQL statements, stop at the first error. */ c->sqlcontext = sql; while (msg == MAL_SUCCEED && m->scanner.rs->pos < m->scanner.rs->len) { sql_rel *r; stmt *s; MalStkPtr oldglb = c->glb; if (!m->sa) m->sa = sa_create(); m->sym = NULL; if ((err = sqlparse(m)) || /* Only forget old errors on transaction boundaries */ (mvc_status(m) && m->type != Q_TRANS) || !m->sym) { if (!err) err = mvc_status(m); if (*m->errstr) msg = createException(PARSE, "SQLparser", "%s", m->errstr); *m->errstr = 0; sqlcleanup(m, err); execute = 0; if (!err) continue; assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; goto endofcompile; } /* * We have dealt with the first parsing step and advanced the input reader * to the next statement (if any). * Now is the time to also perform the semantic analysis, * optimize and produce code. * We don't search the cache for a previous incarnation yet. */ MSinitClientPrg(c, "user", nme); oldvtop = c->curprg->def->vtop; oldstop = c->curprg->def->stop; r = sql_symbol2relation(m, m->sym); s = sql_relation2stmt(m, r); #ifdef _SQL_COMPILE mnstr_printf(c->fdout, "#SQLstatement:\n"); #endif scanner_query_processed(&(m->scanner)); if (s == 0 || (err = mvc_status(m))) { msg = createException(PARSE, "SQLparser", "%s", m->errstr); handle_error(m, c->fdout, status); sqlcleanup(m, err); /* restore the state */ MSresetInstructions(c->curprg->def, oldstop); freeVariables(c, c->curprg->def, c->glb, oldvtop); c->curprg->def->errors = 0; assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; goto endofcompile; } /* generate MAL code */ if (backend_callinline(sql, c, s, 1) == 0) addQueryToCache(c); else err = 1; if (err ||c->curprg->def->errors) { /* restore the state */ MSresetInstructions(c->curprg->def, oldstop); freeVariables(c, c->curprg->def, c->glb, oldvtop); c->curprg->def->errors = 0; msg = createException(SQL, "SQLparser", "Errors encountered in query"); assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; goto endofcompile; } #ifdef _SQL_COMPILE mnstr_printf(c->fdout, "#result of sql.eval()\n"); printFunction(c->fdout, c->curprg->def, 0, c->listing); #endif if (execute) { MalBlkPtr mb = c->curprg->def; if (!output) sql->out = NULL; /* no output */ msg = runMAL(c, mb, 0, 0); MSresetInstructions(mb, oldstop); freeVariables(c, mb, NULL, oldvtop); } sqlcleanup(m, 0); if (!execute) { assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; goto endofcompile; } #ifdef _SQL_COMPILE mnstr_printf(c->fdout, "#parse/execute result %d\n", err); #endif assert(c->glb == 0 || c->glb == oldglb); /* detect leak */ c->glb = oldglb; } if (m->results && result) { /* return all results sets */ *result = m->results; m->results = NULL; } /* * We are done; a MAL procedure resides in the cache. */ endofcompile: if (execute) MSresetInstructions(c->curprg->def, 1); c->sqlcontext = be; backend_destroy(sql); GDKfree(n); GDKfree(b); bstream_destroy(m->scanner.rs); if (m->sa) sa_destroy(m->sa); m->sa = NULL; m->sym = NULL; /* variable stack maybe resized, ie we need to keep the new stack */ status = m->session->status; sizevars = m->sizevars; topvars = m->topvars; vars = m->vars; *m = *o; _DELETE(o); m->sizevars = sizevars; m->topvars = topvars; m->vars = vars; m->session->status = status; m->session->auto_commit = ac; return msg; }
void MSscheduleClient(str command, str challenge, bstream *fin, stream *fout) { char *user = command, *algo = NULL, *passwd = NULL, *lang = NULL; char *database = NULL, *s, *dbname; Client c; /* decode BIG/LIT:user:{cypher}passwordchal:lang:database: line */ /* byte order */ s = strchr(user, ':'); if (s) { *s = 0; mnstr_set_byteorder(fin->s, strcmp(user, "BIG") == 0); user = s + 1; } else { mnstr_printf(fout, "!incomplete challenge '%s'\n", user); exit_streams(fin, fout); GDKfree(command); return; } /* passwd */ s = strchr(user, ':'); if (s) { *s = 0; passwd = s + 1; /* decode algorithm, i.e. {plain}mypasswordchallenge */ if (*passwd != '{') { mnstr_printf(fout, "!invalid password entry\n"); exit_streams(fin, fout); GDKfree(command); return; } algo = passwd + 1; s = strchr(algo, '}'); if (!s) { mnstr_printf(fout, "!invalid password entry\n"); exit_streams(fin, fout); GDKfree(command); return; } *s = 0; passwd = s + 1; } else { mnstr_printf(fout, "!incomplete challenge '%s'\n", user); exit_streams(fin, fout); GDKfree(command); return; } /* lang */ s = strchr(passwd, ':'); if (s) { *s = 0; lang = s + 1; } else { mnstr_printf(fout, "!incomplete challenge, missing language\n"); exit_streams(fin, fout); GDKfree(command); return; } /* database */ s = strchr(lang, ':'); if (s) { *s = 0; database = s + 1; /* we can have stuff following, make it void */ s = strchr(database, ':'); if (s) *s = 0; } dbname = GDKgetenv("gdk_dbname"); if (database != NULL && database[0] != '\0' && strcmp(database, dbname) != 0) { mnstr_printf(fout, "!request for database '%s', " "but this is database '%s', " "did you mean to connect to monetdbd instead?\n", database, dbname); /* flush the error to the client, and abort further execution */ exit_streams(fin, fout); GDKfree(command); return; } else { str err; oid uid; sabdb *stats = NULL; Client root = &mal_clients[0]; /* access control: verify the credentials supplied by the user, * no need to check for database stuff, because that is done per * database itself (one gets a redirect) */ err = AUTHcheckCredentials(&uid, root, &user, &passwd, &challenge, &algo); if (err != MAL_SUCCEED) { mnstr_printf(fout, "!%s\n", err); exit_streams(fin, fout); GDKfree(err); GDKfree(command); return; } err = SABAOTHgetMyStatus(&stats); if (err != MAL_SUCCEED) { /* this is kind of awful, but we need to get rid of this * message */ fprintf(stderr, "!SABAOTHgetMyStatus: %s\n", err); if (err != M5OutOfMemory) GDKfree(err); mnstr_printf(fout, "!internal server error, " "please try again later\n"); exit_streams(fin, fout); GDKfree(command); return; } if (stats->locked == 1) { if (uid == 0) { mnstr_printf(fout, "#server is running in " "maintenance mode\n"); } else { mnstr_printf(fout, "!server is running in " "maintenance mode, please try again later\n"); exit_streams(fin, fout); SABAOTHfreeStatus(&stats); GDKfree(command); return; } } SABAOTHfreeStatus(&stats); c = MCinitClient(uid, fin, fout); if (c == NULL) { if ( MCshutdowninprogress()) mnstr_printf(fout, "!system shutdown in progress, please try again later\n"); else mnstr_printf(fout, "!maximum concurrent client limit reached " "(%d), please try again later\n", MAL_MAXCLIENTS); exit_streams(fin, fout); GDKfree(command); return; } /* move this back !! */ if (c->nspace == 0) { c->nspace = newModule(NULL, putName("user", 4)); c->nspace->outer = mal_clients[0].nspace->outer; } if ((s = setScenario(c, lang)) != NULL) { mnstr_printf(c->fdout, "!%s\n", s); mnstr_flush(c->fdout); GDKfree(s); c->mode = FINISHCLIENT; } if (!GDKgetenv_isyes(mal_enableflag) && (strncasecmp("sql", lang, 3) != 0 && uid != 0)) { mnstr_printf(fout, "!only the 'monetdb' user can use non-sql languages. " "run mserver5 with --set %s=yes to change this.\n", mal_enableflag); exit_streams(fin, fout); GDKfree(command); return; } } MSinitClientPrg(c, "user", "main"); GDKfree(command); /* NOTE ABOUT STARTING NEW THREADS * At this point we have conducted experiments (Jun 2012) with * reusing threads. The implementation used was a lockless array of * semaphores to wake up threads to do work. Experimentation on * Linux, Solaris and Darwin showed no significant improvements, in * most cases no improvements at all. Hence the following * conclusion: thread reuse doesn't save up on the costs of just * forking new threads. Since the latter means no difficulties of * properly maintaining a pool of threads and picking the workers * out of them, it is favourable just to start new threads on * demand. */ /* fork a new thread to handle this client */ mnstr_settimeout(c->fdin->s, 50, GDKexiting); MSserveClient(c); }