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); }
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; }
/* * "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; }
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; }
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); }