Beispiel #1
0
void
rumprun_config(char *cmdline)
{
	char *cfg;
	struct rumprun_exec *rre;
	jsmn_parser p;
	jsmntok_t *tokens = NULL;
	jsmntok_t *t;
	size_t cmdline_len;
	unsigned int i;
	int ntok;

	/* is the config file on rootfs?  if so, mount & dig it out */
	cfg = rumprun_config_path(cmdline);
	if (cfg != NULL) {
		cmdline = getcmdlinefromroot(cfg);
		if (cmdline == NULL)
			errx(1, "could not get cfg from rootfs");
	}

	while (*cmdline != '{') {
		if (*cmdline == '\0') {
			warnx("could not find start of json.  no config?");
			makeargv(strdup("rumprun"));
			return;
		}
		cmdline++;
	}

	cmdline_len = strlen(cmdline);
	jsmn_init(&p);
	ntok = jsmn_parse(&p, cmdline, cmdline_len, NULL, 0);

	if (ntok <= 0) {
		errx(1, "json parse failed 1");
	}

	tokens = malloc(ntok * sizeof(*t));
	if (!tokens) {
		errx(1, "failed to allocate jsmn tokens");
	}

	jsmn_init(&p);
	if ((ntok = jsmn_parse(&p, cmdline, cmdline_len, tokens, ntok)) < 1) {
		errx(1, "json parse failed 2");
	}

	T_CHECKTYPE(tokens, cmdline, JSMN_OBJECT, __func__);

	for (t = &tokens[0]; t < &tokens[ntok]; ) {
		/* allow multiple levels of object nesting */
		if (t->type == JSMN_OBJECT) {
			t++;
			continue;
		}

		T_CHECKTYPE(t, cmdline, JSMN_STRING, __func__);
		for (i = 0; i < __arraycount(parsers); i++) {
			if (T_STREQ(t, cmdline, parsers[i].name)) {
				int left;

				t++;
				left = &tokens[ntok] - t;
				t += parsers[i].handler(t, left, cmdline);
				break;
			}
		}
		if (i == __arraycount(parsers))
			errx(1, "no match for key \"%.*s\"",
			    T_PRINTFSTAR(t, cmdline));
	}

	/*
	 * Before we start running things, perform some sanity checks
	 */
	rre = TAILQ_LAST(&rumprun_execs, rumprun_execs);
	if (rre == NULL) {
		errx(1, "rumprun_config: no bins");
	}
	if (rre->rre_flags & RUMPRUN_EXEC_PIPE) {
		errx(1, "rumprun_config: last bin may not output to pipe");
	}

	free(tokens);
}
Beispiel #2
0
static int
handle_blk(jsmntok_t *t, int left, char *data)
{
	const char *source, *origpath, *fstype;
	char *mp, *path;
	jsmntok_t *key, *value;
	int i, objsize;

	T_CHECKTYPE(t, data, JSMN_OBJECT, __func__);

	/* we expect straight key-value pairs */
	objsize = t->size;
	if (left < 2*objsize + 1) {
		return -1;
	}
	t++;

	fstype = source = origpath = mp = path = NULL;

	for (i = 0; i < objsize; i++, t+=2) {
		char *valuestr;
		key = t;
		value = t+1;

		T_CHECKTYPE(key, data, JSMN_STRING, __func__);
		T_CHECKSIZE(key, data, 1, __func__);

		T_CHECKTYPE(value, data, JSMN_STRING, __func__);
		T_CHECKSIZE(value, data, 0, __func__);

		valuestr = token2cstr(value, data);
		if (T_STREQ(key, data, "source")) {
			source = valuestr;
		} else if (T_STREQ(key, data, "path")) {
			origpath = path = valuestr;
		} else if (T_STREQ(key, data, "fstype")) {
			fstype = valuestr;
		} else if (T_STREQ(key, data, "mountpoint")) {
			mp = valuestr;
		} else {
			errx(1, "unexpected key \"%.*s\" in \"%s\"",
			    T_PRINTFSTAR(key, data), __func__);
		}
	}

	if (!source || !path) {
		errx(1, "blk cfg missing vital data");
	}

	if (strcmp(source, "dev") == 0) {
		/* nothing to do here */
	} else if (strcmp(source, "vnd") == 0) {
		path = configvnd(path);
	} else if (strcmp(source, "etfs") == 0) {
		path = configetfs(path, 1);
	} else {
		errx(1, "unsupported blk source \"%s\"", source);
	}

	/* we only need to do something only if a mountpoint is specified */
	if (mp) {
		char *chunk;
		unsigned mi;

		if (!fstype) {
			errx(1, "no fstype for mountpoint \"%s\"\n", mp);
		}

		for (chunk = mp;;) {
			bool end;

			/* find & terminate the next chunk */
			chunk += strspn(chunk, "/");
			chunk += strcspn(chunk, "/");
			end = (*chunk == '\0');
			*chunk = '\0';

			if (mkdir(mp, 0755) == -1) {
				if (errno != EEXIST)
					err(1, "failed to create mp dir \"%s\"",
					    chunk);
			}

			/* restore path */
			if (!end)
				*chunk = '/';
			else
				break;
		}

		for (mi = 0; mi < __arraycount(mounters); mi++) {
			if (strcmp(fstype, mounters[mi].mt_fstype) == 0) {
				if (!mounters[mi].mt_mount(path, mp))
					errx(1, "failed to mount fs type "
					    "\"%s\" from \"%s\" to \"%s\"",
					    fstype, path, mp);
				break;
			}
		}
		if (mi == __arraycount(mounters))
			errx(1, "unknown fstype \"%s\"", fstype);
	}

	if (path != origpath)
		free(path);

	return 2*objsize + 1;
}
Beispiel #3
0
/*
 * "rc": [
 *	{ "bin" : "binname",
 *	  "argv" : [ "arg1", "arg2", ... ], (optional)
 *	  "runmode" : "& OR |" (optional)
 *	},
 *      ....
 * ]
 */
static int
addbin(jsmntok_t *t, char *data)
{
	jsmntok_t *t_bin, *t_argv, *t_runmode;
	struct rumprun_exec *rre;
	jsmntok_t *key, *value;
	char *binname;
	int binsize = 1;
	int objleft = t->size;
	int rreflags, i;

	T_CHECKTYPE(t, data, JSMN_OBJECT, __func__);
	t++;

	/* process and validate data */
	t_bin = t_argv = t_runmode = NULL;
	while (objleft--) {
		int mysize;

		key = t;
		value = t+1;

		T_CHECKTYPE(key, data, JSMN_STRING, __func__);

		if (T_STREQ(key, data, "bin")) {
			t_bin = value;

			T_CHECKSIZE(key, data, 1, __func__);
			T_CHECKTYPE(value, data, JSMN_STRING, __func__);
			T_CHECKSIZE(value, data, 0, __func__);

			mysize = 1 + 1;
		} else if (T_STREQ(key, data, "argv")) {
			T_CHECKTYPE(value, data, JSMN_ARRAY, __func__);

			t_argv = value;

			/* key + array + array contents */
			mysize = 1 + 1 + value->size;
		} else if (T_STREQ(key, data, "runmode")) {
			t_runmode = value;

			T_CHECKSIZE(key, data, 1, __func__);
			T_CHECKTYPE(value, data, JSMN_STRING, __func__);
			T_CHECKSIZE(value, data, 0, __func__);

			mysize = 1 + 1;
		} else {
			errx(1, "unexpected key \"%.*s\" in \"%s\"",
			    T_PRINTFSTAR(key, data), __func__);
		}

		t += mysize;
		binsize += mysize;
	}

	if (!t_bin)
		errx(1, "missing \"bin\" for rc entry");
	binname = token2cstr(t_bin, data);

	if (t_runmode) {
		bool sizeok = T_SIZE(t_runmode) == 1;

		if (sizeok && *T_STR(t_runmode,data) == '&') {
			rreflags = RUMPRUN_EXEC_BACKGROUND;
		} else if (sizeok && *T_STR(t_runmode,data) == '|') {
			rreflags = RUMPRUN_EXEC_PIPE;
		} else {
			errx(1, "invalid runmode \"%.*s\" for bin \"%.*s\"",
			    T_PRINTFSTAR(t_runmode, data),
			    T_PRINTFSTAR(t_bin, data));
		}
	} else {
		rreflags = 0;
	}

	/* ok, we got everything.  save into rumprun_exec structure */
	rre = malloc(sizeof(*rre) + (2+t_argv->size) * sizeof(char *));
	if (rre == NULL)
		err(1, "allocate rumprun_exec");
	rre->rre_flags = rreflags;
	rre->rre_argc = 1+t_argv->size;
	rre->rre_argv[0] = binname;
	for (i = 1, t = t_argv+1; i <= t_argv->size; i++, t++) {
		T_CHECKTYPE(t, data, JSMN_STRING, __func__);
		rre->rre_argv[i] = token2cstr(t, data);
	}
	rre->rre_argv[rre->rre_argc] = NULL;

	TAILQ_INSERT_TAIL(&rumprun_execs, rre, rre_entries);

	return binsize;
}
Beispiel #4
0
static int
handle_net(jsmntok_t *t, int left, char *data)
{
	const char *ifname, *cloner, *type, *method;
	const char *addr, *mask, *gw;
	jsmntok_t *key, *value;
	int i, objsize;
	int rv;
	static int configured;

	T_CHECKTYPE(t, data, JSMN_OBJECT, __func__);

	/* we expect straight key-value pairs (at least for now) */
	objsize = t->size;
	if (left < 2*objsize + 1) {
		return -1;
	}
	t++;

	if (configured) {
		errx(1, "currently only 1 \"net\" configuration is supported");
	}

	ifname = cloner = type = method = NULL;
	addr = mask = gw = NULL;

	for (i = 0; i < objsize; i++, t+=2) {
		const char *valuestr;
		key = t;
		value = t+1;

		T_CHECKTYPE(key, data, JSMN_STRING, __func__);
		T_CHECKSIZE(key, data, 1, __func__);

		T_CHECKTYPE(value, data, JSMN_STRING, __func__);
		T_CHECKSIZE(value, data, 0, __func__);

		/*
		 * XXX: this mimics the structure from Xen.  We probably
		 * want a richer structure, but let's be happy to not
		 * diverge for now.
		 */
		valuestr = token2cstr(value, data);
		if (T_STREQ(key, data, "if")) {
			ifname = valuestr;
		} else if (T_STREQ(key, data, "cloner")) {
			cloner = valuestr;
		} else if (T_STREQ(key, data, "type")) {
			type = valuestr;
		} else if (T_STREQ(key, data, "method")) {
			method = valuestr;
		} else if (T_STREQ(key, data, "addr")) {
			addr = valuestr;
		} else if (T_STREQ(key, data, "mask")) {
			/* XXX: we could also pass mask as a number ... */
			mask = valuestr;
		} else if (T_STREQ(key, data, "gw")) {
			gw = valuestr;
		} else {
			errx(1, "unexpected key \"%.*s\" in \"%s\"",
			    T_PRINTFSTAR(key, data), __func__);
		}
	}

	if (!ifname || !type || !method) {
		errx(1, "net cfg missing vital data, not configuring");
	}

	if (cloner) {
		if ((rv = rump_pub_netconfig_ifcreate(ifname)) != 0) {
			errx(1, "rumprun_config: ifcreate %s failed: %d",
			    ifname, rv);
		}
	}

	if (strcmp(type, "inet") == 0) {
		config_ipv4(ifname, method, addr, mask, gw);
	} else if (strcmp(type, "inet6") == 0) {
		config_ipv6(ifname, method, addr, mask, gw);
	} else {
		errx(1, "network type \"%s\" not supported", type);
	}

	return 2*objsize + 1;
}
Beispiel #5
0
void
rumprun_config(char *cmdline)
{
	jsmn_parser p;
	jsmntok_t *tokens = NULL;
	jsmntok_t *t;
	size_t cmdline_len;
	unsigned int i;
	int ntok;

	/* is the config file on rootfs?  if so, mount & dig it out */
	if (rumprun_config_isonrootfs_p(cmdline)) {
		cmdline = getcmdlinefromroot(cmdline + rootcfglen);
		if (cmdline == NULL)
			errx(1, "could not get cfg from rootfs");
	}

	while (*cmdline != '{') {
		if (*cmdline == '\0') {
			warnx("could not find start of json.  no config?");
			makeargv("rumprun");
			return;
		}
		cmdline++;
	}

	cmdline_len = strlen(cmdline);
	jsmn_init(&p);
	ntok = jsmn_parse(&p, cmdline, cmdline_len, NULL, 0);

	if (ntok <= 0) {
		errx(1, "json parse failed 1");
	}

	tokens = malloc(ntok * sizeof(*t));
	if (!tokens) {
		errx(1, "failed to allocate jsmn tokens");
	}

	jsmn_init(&p);
	if ((ntok = jsmn_parse(&p, cmdline, cmdline_len, tokens, ntok)) < 1) {
		errx(1, "json parse failed 2");
	}

	T_CHECKTYPE(tokens, cmdline, JSMN_OBJECT, __func__);

	for (t = &tokens[1]; t < &tokens[ntok]; ) {
		for (i = 0; i < __arraycount(parsers); i++) {
			if (T_STREQ(t, cmdline, parsers[i].name)) {
				int left;

				t++;
				left = &tokens[ntok] - t;
				t += parsers[i].handler(t, left, cmdline);
				break;
			}
		}
		if (i == __arraycount(parsers))
			errx(1, "no match for key \"%.*s\"",
			    T_PRINTFSTAR(t, cmdline));
	}

	free(tokens);
}