Esempio n. 1
0
/*
 * 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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
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;
}
Esempio n. 4
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;
}
Esempio n. 5
0
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);
}