Beispiel #1
0
/**
 * Helper function for commands in their most general form: no option
 * flags and just pushing all (database) arguments over to merovingian
 * for performing merocmd action.
 */
static void
simple_command(int argc, char *argv[], char *merocmd, char *successmsg, char glob)
{
	int i;
	sabdb *orig = NULL;
	sabdb *stats = NULL;
	char *e;

	if (argc == 1) {
		/* print help message for this command */
		command_help(2, &argv[-1]);
		exit(1);
	}
	
	/* walk through the arguments and hunt for "options" */
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "--") == 0) {
			argv[i] = NULL;
			break;
		}
		if (argv[i][0] == '-') {
			fprintf(stderr, "%s: unknown option: %s\n", argv[0], argv[i]);
			command_help(argc + 1, &argv[-1]);
			exit(1);
		}
	}

	if (glob) {
		if ((e = MEROgetStatus(&orig, NULL)) != NULL) {
			fprintf(stderr, "%s: %s\n", argv[0], e);
			free(e);
			exit(2);
		}
		stats = globMatchDBS(argc, argv, &orig, argv[0]);
		msab_freeStatus(&orig);
		orig = stats;

		if (orig == NULL)
			exit(1);
	} else {
		for (i = 1; i < argc; i++) {
			if (argv[i] != NULL) {
				/* maintain input order */
				if (orig == NULL) {
					stats = orig = calloc(1, sizeof(sabdb));
				} else {
					stats = stats->next = calloc(1, sizeof(sabdb));
				}
				stats->dbname = strdup(argv[i]);
			}
		}
	}

	simple_argv_cmd(argv[0], orig, merocmd, successmsg, NULL);
	msab_freeStatus(&orig);
}
Beispiel #2
0
char* db_destroy(char* dbname) {
	sabdb* stats;
	char* e;
	char buf[8096];

	if (dbname[0] == '\0')
		return(strdup("database name should not be an empty string"));

	/* the argument is the database to destroy, see what Sabaoth can
	 * tell us about it */
	if ((e = msab_getStatus(&stats, dbname)) != NULL) {
		snprintf(buf, sizeof(buf), "internal error: %s", e);
		free(e);
		return(strdup(buf));
	}

	if (stats == NULL) {
		snprintf(buf, sizeof(buf), "no such database: %s", dbname);
		return(strdup(buf));
	}

	if (stats->state == SABdbRunning) {
		snprintf(buf, sizeof(buf), "database '%s' is still running, "
				"please stop database first", dbname);
		msab_freeStatus(&stats);
		return(strdup(buf));
	}

	/* annoyingly we have to delete file by file, and
	 * directories recursively... */
	if ((e = deletedir(stats->path)) != NULL) {
		snprintf(buf, sizeof(buf), "failed to destroy '%s': %s",
				dbname, e);
		free(e);
		msab_freeStatus(&stats);
		return(strdup(buf));
	}
	msab_freeStatus(&stats);

	return(NULL);
}
Beispiel #3
0
static void
command_startstop(int argc, char *argv[], startstop mode)
{
	int doall = 0;
	int i;
	char *e;
	sabdb *orig = NULL;
	sabdb *stats;
	sabdb *prev;
	char *type = NULL;
	char *action = NULL;
	char *p;
	char *nargv[64];

	switch (mode) {
		case START:
			type = "start";
			action = "starting database";
		break;
		case STOP:
			type = "stop";
			action = "stopping database";
		break;
		case KILL:
			type = "kill";
			action = "killing database";
		break;
	}

	if (argc == 1) {
		/* print help message for this command */
		command_help(2, &argv[-1]);
		exit(1);
	} else if (argc == 0) {
		exit(2);
	}

	/* time to collect some option flags */
	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			for (p = argv[i] + 1; *p != '\0'; p++) {
				switch (*p) {
					case 'a':
						doall = 1;
					break;
					case '-':
						if (p[1] == '\0') {
							if (argc - 1 > i) 
								doall = 0;
							i = argc;
							break;
						}
					default:
						fprintf(stderr, "%s: unknown option: -%c\n", type, *p);
						command_help(2, &argv[-1]);
						exit(1);
					break;
				}
			}
			/* make this option no longer available, for easy use
			 * lateron */
			argv[i] = NULL;
		}
	}

	if ((e = MEROgetStatus(&orig, NULL)) != NULL) {
		fprintf(stderr, "%s: %s\n", type, e);
		free(e);
		exit(2);
	}
	if (doall != 1) {
		stats = globMatchDBS(argc, argv, &orig, type);
		msab_freeStatus(&orig);
		orig = stats;
	}

	argv = nargv;
	i = 0;
	argv[i++] = type;

	stats = orig;
	prev = NULL;
	while (stats != NULL) {
		/* When -a was given, we're supposed to start all known
		 * databases.  In this mode we should omit starting already
		 * started databases, so we need to check first. */

		if (doall == 1 && (
				((mode == STOP || mode == KILL) && (stats->state != SABdbRunning && stats->state != SABdbStarting))
				|| (mode == START && stats->state == SABdbRunning)))
		{
			/* needs not to be started/stopped, remove from list */
			if (prev == NULL) {
				orig = stats->next;
			} else {
				prev->next = stats->next;
			}
			stats->next = NULL;
			msab_freeStatus(&stats);
			if (prev == NULL) {
				stats = orig;
				continue;
			}
			stats = prev;
		}
		prev = stats;
		stats = stats->next;
	}

	if (orig != NULL) {
		simple_argv_cmd(argv[0], orig, type, NULL, action);
		msab_freeStatus(&orig);
	}

	return;
}
Beispiel #4
0
static void
command_status(int argc, char *argv[])
{
	int doall = 1; /* we default to showing all */
	int mode = 1;  /* 0=crash, 1=short, 2=long */
	char *state = "rbscl"; /* contains states to show */
	int i;
	char *p;
	char *e;
	sabdb *stats;
	sabdb *orig;
	sabdb *prev;
	sabdb *neworig = NULL;
	int t;
	int twidth = TERMWIDTH;
	int dbwidth = 0;
	int uriwidth = 0;

	if (argc == 0) {
		exit(2);
	}

	/* time to collect some option flags */
	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			for (p = argv[i] + 1; *p != '\0'; p++) {
				switch (*p) {
					case 'c':
						mode = 0;
					break;
					case 'l':
						mode = 2;
					break;
					case 's':
						if (*(p + 1) != '\0') {
							state = ++p;
						} else if (i + 1 < argc && argv[i + 1][0] != '-') {
							state = argv[++i];
						} else {
							fprintf(stderr, "status: -s needs an argument\n");
							command_help(2, &argv[-1]);
							exit(1);
						}
						for (p = state; *p != '\0'; p++) {
							switch (*p) {
								case 'b': /* booting (starting up) */
								case 'r': /* running (started) */
								case 's': /* stopped */
								case 'c': /* crashed */
								case 'l': /* locked */
								break;
								default:
									fprintf(stderr, "status: unknown flag for -s: -%c\n", *p);
									command_help(2, &argv[-1]);
									exit(1);
							}
						}
						p--;
					break;
					case '-':
						if (p[1] == '\0') {
							if (argc - 1 > i) 
								doall = 0;
							i = argc;
							break;
						}
					default:
						fprintf(stderr, "status: unknown option: -%c\n", *p);
						command_help(2, &argv[-1]);
						exit(1);
				}
			}
			/* make this option no longer available, for easy use
			 * lateron */
			argv[i] = NULL;
		} else {
			doall = 0;
		}
	}

	if ((e = MEROgetStatus(&orig, NULL)) != NULL) {
		fprintf(stderr, "status: %s\n", e);
		free(e);
		exit(2);
	}

	/* look at the arguments and evaluate them based on a glob (hence we
	 * listed all databases before) */
	if (doall != 1) {
		stats = globMatchDBS(argc, argv, &orig, "status");
		msab_freeStatus(&orig);
		orig = stats;
	}

	/* perform selection based on state (and order at the same time) */
	for (p = &state[strlen(state) - 1]; p >= state; p--) {
		int curLock = 0;
		SABdbState curMode = SABdbIllegal;
		switch (*p) {
			case 'b':
				curMode = SABdbStarting;
			break;
			case 'r':
				curMode = SABdbRunning;
			break;
			case 's':
				curMode = SABdbInactive;
			break;
			case 'c':
				curMode = SABdbCrashed;
			break;
			case 'l':
				curLock = 1;
			break;
		}
		stats = orig;
		prev = NULL;
		while (stats != NULL) {
			if (stats->locked == curLock &&
					(curLock == 1 || 
					 (curLock == 0 && stats->state == curMode)))
			{
				sabdb *next = stats->next;
				stats->next = neworig;
				neworig = stats;
				if (prev == NULL) {
					orig = next;
				} else {
					prev->next = next;
				}
				stats = next;
			} else {
				prev = stats;
				stats = stats->next;
			}
		}
	}
	msab_freeStatus(&orig);
	orig = neworig;

	if (mode == 1 && orig != NULL) {
		int len = 0;

		/* calculate dbwidth and uriwidth */
		for (stats = orig; stats != NULL; stats = stats->next) {
			if ((t = strlen(stats->dbname)) > dbwidth)
				dbwidth = t;
			if (stats->uri != NULL && (t = strlen(stats->uri)) > uriwidth)
				uriwidth = t;
			if (uriwidth < 32)
				uriwidth = 32;
		}

		/* Ultra Condensed State(tm) since Feb2013:
		state
		R  6s     (Running)
		R 14w
		R 99y     (purely hypothetical)
		B  3s     (Booting: in practice cannot be observed yet due to lock)
		S  1w     (Stopped)
		LR12h     (Locked/Running)
		LS        (Locked/Stopped)
		C         (Crashed)
		      = 5 chars
		*/

		/* health
		 health
		100% 12d
		 42%  4s
		         = 8 chars
		*/

		len = (dbwidth < 4 ? 4 : dbwidth) + 2 + 5 + 2 + 8 + 2 + uriwidth;
		if (twidth > 0 && len > twidth) {
			if (len - twidth < 10) {
				uriwidth -= len - twidth;
				if (dbwidth < 4)
					dbwidth = 4;
			} else {
				/* reduce relative to usage */
				if (dbwidth < 4) {
					dbwidth = 4;
				} else {
					dbwidth = (int)(dbwidth * 1.0 / (dbwidth + uriwidth) * (len - twidth));
					if (dbwidth < 4)
						dbwidth = 4;
				}
				uriwidth = twidth - (dbwidth + 2 + 5 + 2 + 8 + 2);
				if (uriwidth < 8)
					uriwidth = 8;
			}
		} else {
			if (dbwidth < 4)
				dbwidth = 4;
		}

		/* print header */
		printf("%*sname%*s  state   health   %*sremarks\n",
				(dbwidth - 4) / 2, "", (dbwidth - 4 + 1) / 2, "",
				(uriwidth - 7) / 2, "");
	}

	for (stats = orig; stats != NULL; stats = stats->next)
		printStatus(stats, mode, dbwidth, uriwidth);

	if (orig != NULL)
		msab_freeStatus(&orig);
}
Beispiel #5
0
static void
command_destroy(int argc, char *argv[])
{
	int i;
	int force = 0;    /* ask for confirmation */
	char *e;
	sabdb *orig = NULL;
	sabdb *stats = NULL;

	if (argc == 1) {
		/* print help message for this command */
		command_help(argc + 1, &argv[-1]);
		exit(1);
	}

	/* walk through the arguments and hunt for "options" */
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "--") == 0) {
			argv[i] = NULL;
			break;
		}
		if (argv[i][0] == '-') {
			if (argv[i][1] == 'f') {
				force = 1;
				argv[i] = NULL;
			} else {
				fprintf(stderr, "destroy: unknown option: %s\n", argv[i]);
				command_help(argc + 1, &argv[-1]);
				exit(1);
			}
		}
	}

	if ((e = MEROgetStatus(&orig, NULL)) != NULL) {
		fprintf(stderr, "destroy: %s\n", e);
		free(e);
		exit(2);
	}
	stats = globMatchDBS(argc, argv, &orig, "destroy");
	msab_freeStatus(&orig);
	orig = stats;

	if (orig == NULL)
		exit(1);

	if (force == 0) {
		char answ;
		printf("you are about to remove database%s ", orig->next != NULL ? "s" : "");
		for (stats = orig; stats != NULL; stats = stats->next)
			printf("%s'%s'", stats != orig ? ", " : "", stats->dbname);
		printf("\nALL data in %s will be lost, are you sure? [y/N] ",
				orig->next != NULL ? "these databases" : "this database");
		if (scanf("%c", &answ) >= 1 &&
				(answ == 'y' || answ == 'Y'))
		{
			/* do it! */
		} else {
			printf("aborted\n");
			exit(1);
		}
	} else {
		char *ret;
		char *out;
		for (stats = orig; stats != NULL; stats = stats->next) {
			if (stats->state == SABdbRunning || stats->state == SABdbStarting) {
				ret = control_send(&out, mero_host, mero_port,
						stats->dbname, "stop", 0, mero_pass);
				if (ret != NULL)
					free(ret);
			}
		}
	}

	simple_argv_cmd(argv[0], orig, "destroy", "destroyed database", NULL);
	msab_freeStatus(&orig);
}
Beispiel #6
0
static void
command_create(int argc, char *argv[])
{
	int i;
	char *mfunnel = NULL;
	char *password = NULL;
	sabdb *orig = NULL;
	sabdb *stats = NULL;

	if (argc == 1) {
		/* print help message for this command */
		command_help(argc + 1, &argv[-1]);
		exit(1);
	}

	/* walk through the arguments and hunt for "options" */
	for (i = 1; i < argc; i++) {
		if (strcmp(argv[i], "--") == 0) {
			argv[i] = NULL;
			break;
		}
		if (argv[i][0] == '-') {
			if (argv[i][1] == 'm') {
				if (argv[i][2] != '\0') {
					mfunnel = &argv[i][2];
					argv[i] = NULL;
				} else if (i + 1 < argc && argv[i + 1][0] != '-') {
					argv[i] = NULL;
					mfunnel = argv[++i];
					argv[i] = NULL;
				} else {
					fprintf(stderr, "create: -m needs an argument\n");
					command_help(2, &argv[-1]);
					exit(1);
				}
			} else if (argv[i][1] == 'p') {
				if (argv[i][2] != '\0') {
					password = &argv[i][2];
					argv[i] = NULL;
				} else if (i + 1 < argc && argv[i + 1][0] != '-') {
					argv[i] = NULL;
					password = argv[++i];
					argv[i] = NULL;
				} else {
					fprintf(stderr, "create: -p needs an argument\n");
					command_help(2, &argv[-1]);
					exit(1);
				}
			} else {
				fprintf(stderr, "create: unknown option: %s\n", argv[i]);
				command_help(argc + 1, &argv[-1]);
				exit(1);
			}
		}
	}

	for (i = 1; i < argc; i++) {
		if (argv[i] != NULL) {
			/* maintain input order */
			if (orig == NULL) {
				stats = orig = calloc(1, sizeof(sabdb));
			} else {
				stats = stats->next = calloc(1, sizeof(sabdb));
			}
			stats->dbname = strdup(argv[i]);
		}
	}

	if (mfunnel != NULL) {
		size_t len = strlen("create mfunnel=") + strlen(mfunnel) + 1;
		char *cmd = malloc(len);
		snprintf(cmd, len, "create mfunnel=%s", mfunnel);
		simple_argv_cmd(argv[0], orig, cmd, 
				"created multiplex-funnel in maintenance mode", NULL);
		free(cmd);
	} else if (password != NULL) {
		size_t len = strlen("create password="******"create password=%s", password);
		simple_argv_cmd(argv[0], orig, cmd, 
				"created database with password for monetdb user", NULL);
		free(cmd);
	} else {
		simple_argv_cmd(argv[0], orig, "create", 
				"created database in maintenance mode", NULL);
	}
	msab_freeStatus(&orig);
}
Beispiel #7
0
static void
command_get(int argc, char *argv[])
{
	char doall = 1;
	char *p;
	char *property = NULL;
	char propall = 0;
	char vbuf[512];
	char *buf = 0;
	char *e;
	int i;
	sabdb *orig, *stats;
	int twidth = TERMWIDTH;
	char *source, *value = NULL;
	confkeyval *kv;
	confkeyval *defprops = getDefaultProps();
	confkeyval *props = getDefaultProps();

	if (argc == 1) {
		/* print help message for this command */
		command_help(2, &argv[-1]);
		exit(1);
	} else if (argc == 0) {
		exit(2);
	}

	/* time to collect some option flags */
	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			for (p = argv[i] + 1; *p != '\0'; p++) {
				switch (*p) {
					case '-':
						if (p[1] == '\0') {
							if (argc - 1 > i) 
								doall = 0;
							i = argc;
							break;
						}
					default:
						fprintf(stderr, "get: unknown option: -%c\n", *p);
						command_help(2, &argv[-1]);
						exit(1);
					break;
				}
			}
			/* make this option no longer available, for easy use
			 * lateron */
			argv[i] = NULL;
		} else if (property == NULL) {
			/* first non-option is property, rest is database */
			property = argv[i];
			argv[i] = NULL;
			if (strcmp(property, "all") == 0)
				propall = 1;
		} else {
			doall = 0;
		}
	}

	if (property == NULL) {
		fprintf(stderr, "get: need a property argument\n");
		command_help(2, &argv[-1]);
		exit(1);
	}
	if ((e = MEROgetStatus(&orig, NULL)) != NULL) {
		fprintf(stderr, "get: %s\n", e);
		free(e);
		exit(2);
	}

	/* look at the arguments and evaluate them based on a glob (hence we
	 * listed all databases before) */
	if (doall != 1) {
		stats = globMatchDBS(argc, argv, &orig, "get");
		msab_freeStatus(&orig);
		orig = stats;
	}

	/* avoid work when there are no results */
	if (orig == NULL) {
		free(props);
		free(defprops);
		return;
	}

	e = control_send(&buf, mero_host, mero_port,
			"#defaults", "get", 1, mero_pass);
	if (e != NULL) {
		fprintf(stderr, "get: %s\n", e);
		free(e);
		exit(2);
	} else if ( buf && strncmp(buf, "OK\n", 3) != 0) {
		fprintf(stderr, "get: %s\n", buf);
		free(buf);
		exit(1);
	}
	readPropsBuf(defprops, buf + 3);
	if( buf) 
		free(buf);

	if (twidth > 0) {
		/* name = 15 */
		/* prop = 8 */
		/* source = 7 */
		twidth -= 15 + 2 + 8 + 2 + 7 + 2;
		if (twidth < 6)
			twidth = 6;
		value = malloc(sizeof(char) * twidth + 1);
	}
	stats = orig;
	while (stats != NULL) {
		e = control_send(&buf, mero_host, mero_port,
				stats->dbname, "get", 1, mero_pass);
		if (e != NULL) {
			fprintf(stderr, "get: %s\n", e);
			free(e);
			exit(2);
		} else if (strncmp(buf, "OK\n", 3) != 0) {
			fprintf(stderr, "get: %s\n", buf);
			free(buf);
			exit(1);
		}
		readPropsBuf(props, buf + 3);
		free(buf);

		if (propall == 1) {
			size_t off = 0;
			kv = props;
			off += snprintf(vbuf, sizeof(vbuf), "name");
			while (kv->key != NULL) {
				off += snprintf(vbuf + off, sizeof(vbuf) - off,
						",%s", kv->key);
				kv++;
			}
		} else {
			/* check validity of properties before printing them */
			if (stats == orig) {
				snprintf(vbuf, sizeof(vbuf), "%s", property);
				buf = vbuf;
				while ((p = strtok(buf, ",")) != NULL) {
					buf = NULL;
					if (strcmp(p, "name") == 0)
						continue;
					kv = findConfKey(props, p);
					if (kv == NULL)
						fprintf(stderr, "get: no such property: %s\n", p);
				}
			}
			snprintf(vbuf, sizeof(vbuf), "%s", property);
		}
		buf = vbuf;
		/* print header after errors */
		if (stats == orig)
			printf("     name          prop     source           value\n");

		while ((p = strtok(buf, ",")) != NULL) {
			buf = NULL;

			/* filter properties based on object type */
			kv = findConfKey(props, "type");
			if (kv != NULL && kv->val != NULL) {
				if (strcmp(kv->val, "mfunnel") == 0) {
					if (strcmp(p, "name") != 0 &&
							strcmp(p, "type") != 0 &&
							strcmp(p, "mfunnel") != 0 &&
							strcmp(p, "shared") != 0)
						continue;
				}
			} else { /* no type == database (default) */
				if (strcmp(p, "mfunnel") == 0)
					continue;
			}

			/* special virtual case */
			if (strcmp(p, "name") == 0) {
				source = "-";
				if (twidth > 0) {
					abbreviateString(value, stats->dbname, twidth);
				} else {
					value = stats->dbname;
				}
			} else {
				kv = findConfKey(props, p);
				if (kv == NULL)
					continue;
				if (kv->val == NULL) {
					char *y = NULL;
					kv = findConfKey(defprops, p);
					source = "default";
					y = kv != NULL && kv->val != NULL ? kv->val : "<unknown>";
					if (twidth > 0) {
						abbreviateString(value, y, twidth);
					} else {
						value = y;
					}
				} else {
					source = "local";
					if (twidth > 0) {
						abbreviateString(value, kv->val, twidth);
					} else {
						value = kv->val;
					}
				}
			}

			printf("%-15s  %-8s  %-7s  %s\n",
					stats->dbname, p, source, value);
		}

		freeConfFile(props);
		stats = stats->next;
	}

	if (twidth > 0)
		free(value);
	msab_freeStatus(&orig);
	free(props);
	free(defprops);
}
Beispiel #8
0
static void
command_set(int argc, char *argv[], meroset type)
{
	char *p = NULL;
	char property[24] = "";
	int i;
	int state = 0;
	char *res;
	char *out;
	sabdb *orig = NULL;
	sabdb *stats = NULL;
	char *e;

	if (argc >= 1 && argc <= 2) {
		/* print help message for this command */
		command_help(2, &argv[-1]);
		exit(1);
	} else if (argc == 0) {
		exit(2);
	}

	/* time to collect some option flags */
	for (i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			for (p = argv[i] + 1; *p != '\0'; p++) {
				switch (*p) {
					case '-':
						if (p[1] == '\0') {
							i = argc;
							break;
						}
					default:
						fprintf(stderr, "%s: unknown option: -%c\n",
								argv[0], *p);
						command_help(2, &argv[-1]);
						exit(1);
					break;
				}
			}
			/* make this option no longer available, for easy use
			 * lateron */
			argv[i] = NULL;
		} else if (property[0] == '\0') {
			/* first non-option is property, rest is database */
			p = argv[i];
			if (type == SET) {
				if ((p = strchr(argv[i], '=')) == NULL) {
					fprintf(stderr, "set: need property=value\n");
					command_help(2, &argv[-1]);
					exit(1);
				}
				*p = '\0';
				snprintf(property, sizeof(property), "%s", argv[i]);
				*p++ = '=';
				p = argv[i];
			} else {
				snprintf(property, sizeof(property), "%s", argv[i]);
			}
			argv[i] = NULL;
		}
	}

	if (property[0] == '\0') {
		fprintf(stderr, "%s: need a property argument\n", argv[0]);
		command_help(2, &argv[-1]);
		exit(1);
	}

	if ((e = MEROgetStatus(&orig, NULL)) != NULL) {
		fprintf(stderr, "%s: %s\n", argv[0], e);
		free(e);
		exit(2);
	}
	stats = globMatchDBS(argc, argv, &orig, argv[0]);
	msab_freeStatus(&orig);
	orig = stats;

	if (orig == NULL) {
		/* error already printed by globMatchDBS */
		exit(1);
	}

	/* handle rename separately due to single argument constraint */
	if (strcmp(property, "name") == 0) {
		if (type == INHERIT) {
			fprintf(stderr, "inherit: cannot default to a database name\n");
			exit(1);
		}

		if (orig->next != NULL) {
			fprintf(stderr, "%s: cannot rename multiple databases to "
					"the same name\n", argv[0]);
			exit(1);
		}

		out = control_send(&res, mero_host, mero_port,
				orig->dbname, p, 0, mero_pass);
		if (out != NULL || strcmp(res, "OK") != 0) {
			res = out == NULL ? res : out;
			fprintf(stderr, "%s: %s\n", argv[0], res);
			state |= 1;
		}
		free(res);

		msab_freeStatus(&orig);
		exit(state);
	}

	for (stats = orig; stats != NULL; stats = stats->next) {
		if (type == INHERIT) {
			strncat(property, "=", sizeof(property) - strlen(property) - 1);
			p = property;
		}
		out = control_send(&res, mero_host, mero_port,
				stats->dbname, p, 0, mero_pass);
		if (out != NULL || strcmp(res, "OK") != 0) {
			res = out == NULL ? res : out;
			fprintf(stderr, "%s: %s\n", argv[0], res);
			state |= 1;
		}
		free(res);
	}

	msab_freeStatus(&orig);
	exit(state);
}
Beispiel #9
0
void
discoveryRunner(void *d)
{
	int sock = *(int *)d;
	int s = -1;
	struct sockaddr_storage peer_addr;
	socklen_t peer_addr_len;
	fd_set fds;
	struct timeval tv;
	int c;
	/* avoid first announce, the HELO will cause an announce when it's
	 * received by ourself */
	time_t deadline = 1;
	time_t now = 0;
	int forceannc = 0;
	sabdb *orig;
	sabdb *stats;
	confkeyval *ckv;
	confkeyval *kv;
	confkeyval *discttl;
	err e;
	remotedb rdb;
	remotedb prv;
	char *val;

	ssize_t nread;
	char buf[512]; /* our packages should be pretty small */
	char host[128];
	char service[8];

	/* start shouting around that we're here ;) request others to tell
	 * what databases they have */
	snprintf(buf, 512, "HELO %s", _mero_hostname);
	broadcast(buf);

	ckv = getDefaultProps();
	discttl = findConfKey(_mero_props, "discoveryttl");

	/* main loop */
	while (_mero_keep_listening == 1) {
		now = time(NULL);
		/* do a round of announcements, we're ahead of the ttl because
		 * when we announce, we add 60 seconds to avoid a "gap" */
		if (forceannc == 1 || deadline <= now) {
			forceannc = 0;
			/* set new deadline */
			deadline = now + discttl->ival;

			/* list all known databases */
			if ((e = msab_getStatus(&stats, NULL)) != NULL) {
				Mfprintf(_mero_discerr, "msab_getStatus error: %s, "
						"discovery services disabled\n", e);
				free(e);
				return;
			}

			for (orig = stats; stats != NULL; stats = stats->next) {
				readProps(ckv, stats->path);
				kv = findConfKey(ckv, "shared");
				val = kv->val == NULL ? "" : kv->val;
				/* skip databases under maintenance */
				if (strcmp(val, "no") != 0 && stats->locked != 1) {
					/* craft ANNC message for this db */
					if (strcmp(val, "yes") == 0)
						val = "";
					snprintf(buf, 512, "ANNC %s%s%s mapi:monetdb://%s:%u/ %d",
							stats->dbname, val[0] == '\0' ? "" : "/", val,
							_mero_hostname, (unsigned int)getConfNum(_mero_props, "port"),
							discttl->ival + 60);
					broadcast(buf);
				}
				freeConfFile(ckv);
			}

			if (orig != NULL)
				msab_freeStatus(&orig);

			if (getConfNum(_mero_props, "control") != 0) {
				/* announce control port */
				snprintf(buf, 512, "ANNC * %s:%u %d",
						_mero_hostname, (unsigned int)getConfNum(_mero_props, "port"),
						discttl->ival + 60);
				/* coverity[string_null] */
				broadcast(buf);
			}
		}

		/* do a round to see if we have to cleanup anything (expired
		 * ttl) */
		pthread_mutex_lock(&_mero_remotedb_lock);

		prv = NULL;
		rdb = _mero_remotedbs;
		while (rdb != NULL) {
			if (rdb->ttl > 0 && rdb->ttl <= now) {
				/* expired, let's remove */
				if (prv == NULL) {
					_mero_remotedbs = rdb->next;
				} else {
					prv->next = rdb->next;
				}
				Mfprintf(_mero_discout, "neighbour database %s%s "
						"has expired\n", rdb->conn, rdb->fullname);
				free(rdb->dbname);
				free(rdb->conn);
				free(rdb->fullname);
				free(rdb);
				break;
			}
			prv = rdb;
			rdb = rdb->next;
		}

		pthread_mutex_unlock(&_mero_remotedb_lock);

		peer_addr_len = sizeof(struct sockaddr_storage);
		FD_ZERO(&fds);
		FD_SET(sock, &fds);
		/* Wait up to 5 seconds. */
		tv.tv_sec = 5;
		tv.tv_usec = 0;
		nread = select(sock + 1, &fds, NULL, NULL, &tv);
		if (nread <= 0) {  /* assume only failure is EINTR */
			/* nothing interesting has happened */
			buf[0] = '\0';
			continue;
		}
		nread = recvfrom(sock, buf, 512, 0,
				(struct sockaddr *)&peer_addr, &peer_addr_len);
		if (nread == -1) {
			buf[0] = '\0';
			continue; /* ignore failed request */
		}

		s = getnameinfo((struct sockaddr *)&peer_addr,
				peer_addr_len, host, 128,
				service, 8, NI_NUMERICSERV);
		if (s != 0) {
			Mfprintf(_mero_discerr, "cannot retrieve name info: %s\n",
					gai_strerror(s));
			continue; /* skip this message */
		}

		/* ignore messages from broadcast interface */
		if (strcmp(host, "0.0.0.0") == 0)
			continue;
		/* forward messages not coming from ourself to all routes that
		 * are active */
		if (strcmp(host, _mero_hostname) != 0) {
			disc_message_tap h = _mero_disc_msg_taps;
			for (; h != NULL; h = h->next) {
				if (write(h->fd, buf, nread) == -1) {
					/* really nothing to be done here, since this is
					 * best effort stuff, keep the condition to keep
					 * fortification warnings off */
				}
			}
		}

		if (strncmp(buf, "HELO ", 5) == 0) {
			/* HELLO message, respond with current databases */
			Mfprintf(_mero_discout, "new neighbour %s (%s)\n", buf + 5, host);
			/* sleep a random amount of time to avoid an avalanche of
			 * ANNC messages flooding the network */
			/* coverity[dont_call] */
			c = 1 + (int)(2500.0 * (rand() / (RAND_MAX + 1.0)));
			sleep_ms(c);
			/* force an announcement round by dropping the deadline */
			forceannc = 1;
			continue;
		} else if (strncmp(buf, "LEAV ", 5) == 0) {
			/* LEAVE message, unregister database */
			char *sp = NULL;
			char *dbname;
			char *conn;

			strtok_r(buf, " ", &sp); /* discard the msg type */
			dbname = strtok_r(NULL, " ", &sp);
			conn = strtok_r(NULL, " ", &sp);

			if (dbname == NULL || conn == NULL)
				continue;

			if (removeRemoteDB(dbname, conn) == 0)
				Mfprintf(_mero_discout,
						"received leave request for unknown database "
						"%s%s from %s\n", conn, dbname, host);
		} else if (strncmp(buf, "ANNC ", 5) == 0) {
			/* ANNOUNCE message, register database */
			char *sp = NULL;
			char *dbname;
			char *conn;
			char *ttl;

			strtok_r(buf, " ", &sp); /* discard the msg type */
			dbname = strtok_r(NULL, " ", &sp);
			conn = strtok_r(NULL, " ", &sp);
			ttl = strtok_r(NULL, " ", &sp);

			if (dbname == NULL || conn == NULL || ttl == NULL)
				continue;

			if (addRemoteDB(dbname, conn, atoi(ttl)) == 1) {
				if (strcmp(dbname, "*") == 0) {
					Mfprintf(_mero_discout, "registered neighbour %s\n",
							conn);
				} else {
					Mfprintf(_mero_discout, "new database "
							"%s%s (ttl=%ss)\n",
							conn, dbname, ttl);
				}
			}
		} else {
			Mfprintf(_mero_discout, "ignoring unknown message from "
					"%s:%s: '%s'\n", host, service, buf);
		}
	}

	/* now notify of our soon to be absence ;) */

	/* list all known databases */
	if ((e = msab_getStatus(&stats, NULL)) != NULL) {
		Mfprintf(_mero_discerr, "msab_getStatus error: %s, "
				"discovery services disabled\n", e);
		free(e);
		free(ckv);
		return;
	}

	/* craft LEAV messages for each db */
	c = 0;
	orig = stats;
	while (stats != NULL) {
		readProps(ckv, stats->path);
		kv = findConfKey(ckv, "shared");
		if (kv->val != NULL && strcmp(kv->val, "no") != 0) {
			snprintf(buf, 512, "LEAV %s mapi:monetdb://%s:%u/",
					stats->dbname, _mero_hostname,
					(unsigned int)getConfNum(_mero_props, "port"));
			broadcast(buf);
			c = 1;
		}
		freeConfFile(ckv);
		stats = stats->next;
	}

	if (orig != NULL)
		msab_freeStatus(&orig);

	/* deregister this merovingian, so it doesn't remain a stale entry */
	if (getConfNum(_mero_props, "control") != 0) {
		snprintf(buf, 512, "LEAV * %s:%u",
				_mero_hostname, (unsigned int)getConfNum(_mero_props, "port"));
		broadcast(buf);
	}

	free(ckv);
}
Beispiel #10
0
/**
 * The terminateProcess function tries to let the given mserver process
 * shut down gracefully within a given time-out.  If that fails, it
 * sends the deadly SIGKILL signal to the mserver process and returns.
 */
void
terminateProcess(void *p)
{
	dpair d = (dpair)p;
	sabdb *stats;
	char *er;
	int i;
	confkeyval *kv;
	/* make local copies since d will disappear when killed */
	pid_t pid = d->pid;
	char *dbname = strdup(d->dbname);

	er = msab_getStatus(&stats, dbname);
	if (er != NULL) {
		Mfprintf(stderr, "cannot terminate process " LLFMT ": %s\n",
				(long long int)pid, er);
		free(er);
		free(dbname);
		return;
	}

	if (stats == NULL) {
		Mfprintf(stderr, "strange, process " LLFMT " serves database '%s' "
				"which does not exist\n", (long long int)pid, dbname);
		free(dbname);
		return;
	}

	switch (stats->state) {
		case SABdbRunning:
			/* ok, what we expect */
		break;
		case SABdbCrashed:
			Mfprintf(stderr, "cannot shut down database '%s', mserver "
					"(pid " LLFMT ") has crashed\n",
					dbname, (long long int)pid);
			msab_freeStatus(&stats);
			free(dbname);
			return;
		case SABdbInactive:
			Mfprintf(stdout, "database '%s' appears to have shut down already\n",
					dbname);
			fflush(stdout);
			msab_freeStatus(&stats);
			free(dbname);
			return;
		default:
			Mfprintf(stderr, "unknown state: %d", (int)stats->state);
			msab_freeStatus(&stats);
			free(dbname);
			return;
	}

	if (d->type == MEROFUN) {
		multiplexDestroy(dbname);
		free(dbname);
		return;
	} else if (d->type != MERODB) {
		/* barf */
		Mfprintf(stderr, "cannot stop merovingian process role: %s\n", dbname);
		free(dbname);
		return;
	}

	/* ok, once we get here, we'll be shutting down the server */
	Mfprintf(stdout, "sending process " LLFMT " (database '%s') the "
			"TERM signal\n", (long long int)pid, dbname);
	kill(pid, SIGTERM);
	kv = findConfKey(_mero_props, "exittimeout");
	for (i = 0; i < atoi(kv->val) * 2; i++) {
		if (stats != NULL)
			msab_freeStatus(&stats);
		sleep_ms(500);
		er = msab_getStatus(&stats, dbname);
		if (er != NULL) {
			Mfprintf(stderr, "unexpected problem: %s\n", er);
			free(er);
			/* don't die, just continue, so we KILL in the end */
		} else if (stats == NULL) {
			Mfprintf(stderr, "hmmmm, database '%s' suddenly doesn't exist "
					"any more\n", dbname);
		} else {
			switch (stats->state) {
				case SABdbRunning:
					/* ok, try again */
				break;
				case SABdbCrashed:
					Mfprintf (stderr, "database '%s' crashed after SIGTERM\n",
							dbname);
					msab_freeStatus(&stats);
					free(dbname);
					return;
				case SABdbInactive:
					Mfprintf(stdout, "database '%s' has shut down\n", dbname);
					fflush(stdout);
					msab_freeStatus(&stats);
					free(dbname);
					return;
				default:
					Mfprintf(stderr, "unknown state: %d", (int)stats->state);
				break;
			}
		}
	}
	Mfprintf(stderr, "timeout of %s seconds expired, sending process " LLFMT
			" (database '%s') the KILL signal\n",
			kv->val, (long long int)pid, dbname);
	kill(pid, SIGKILL);
	msab_freeStatus(&stats);
	free(dbname);
	return;
}
Beispiel #11
0
char* db_create(char* dbname) {
	sabdb *stats;
	size_t c;
	char* e;
	char* dbfarm;
	char buf[8096];
	char path[8096];
	FILE *f;

	if ((e = db_validname(dbname)) != NULL)
		return(e);

	/* the argument is the database to create, see what Sabaoth can
	 * tell us about it */
	if ((e = msab_getStatus(&stats, dbname)) != NULL) {
		snprintf(buf, sizeof(buf), "internal error: %s", e);
		free(e);
		return(strdup(buf));
	}

	/* if sabaoth doesn't know, then it's green light for us! */
	if (stats != NULL) {
		msab_freeStatus(&stats);
		snprintf(buf, sizeof(buf), "database '%s' already exists", dbname);
		return(strdup(buf));
	}

	if ((e = msab_getDBfarm(&dbfarm)) != NULL) {
		snprintf(buf, sizeof(buf), "internal error: %s", e);
		free(e);
		return(strdup(buf));
	}

	/* create the directory */
	c = snprintf(path, sizeof(path), "%s/%s", dbfarm, dbname);
	if (c >= sizeof(path)) {
		free(dbfarm);
		return(strdup("path/dbname combination too long, "
				"path would get truncated"));
	}
	if (mkdir(path, 0755) == -1) {
		snprintf(buf, sizeof(buf), "unable to create %s: %s",
				dbname, strerror(errno));
		free(dbfarm);
		return(strdup(buf));
	}

	/* perform another length check, with the .maintenance file,
	 * which happens to be the longest */
	c = snprintf(path, sizeof(path), "%s/%s/.maintenance",
			dbfarm, dbname);
	if (c >= sizeof(path)) {
		/* try to cleanup */
		snprintf(path, sizeof(path), "%s/%s", dbfarm, dbname);
		rmdir(path);
		free(dbfarm);
		return(strdup("path/dbname combination too long, "
				"filenames inside would get truncated"));
	}

	/* put this database under maintenance, make sure no race condition
	 * ever can happen, by putting it under maintenance before it even
	 * exists for Merovingian */
	if ((f = fopen(path, "w")) != NULL)
		fclose(f); /* if this fails, below probably fails too */

	/* avoid GDK making fugly complaints */
	snprintf(path, sizeof(path), "%s/%s/.gdk_lock", dbfarm, dbname);
	if ((f = fopen(path, "w")) == NULL) {
		snprintf(buf, sizeof(buf), "cannot write lock file: %s",
				strerror(errno));
		free(dbfarm);
		return(strdup(buf));
	}
	fclose(f);

	/* generate a vault key */
	snprintf(path, sizeof(path), "%s/%s/.vaultkey", dbfarm, dbname);
	if ((e = generatePassphraseFile(path)) != NULL) {
		free(dbfarm);
		return(e);
	}

	/* without an .uplog file, Merovingian won't work, this
	 * needs to be last to avoid race conditions */
	snprintf(path, sizeof(path), "%s/%s/.uplog", dbfarm, dbname);
	fclose(fopen(path, "w"));

	free(dbfarm);
	return(NULL);
}
Beispiel #12
0
/**
 * Frees up the sabdb structure returned by getStatus.
 */
str SABAOTHfreeStatus(sabdb** ret) {
	str err = msab_freeStatus(ret);
	if (err != NULL)
		excFromMem(MAL, "sabaoth.freestatus", err);
	return(MAL_SUCCEED);
}