/** * virConfParseString: * @ctxt: the parsing context * * Parse one string * * Returns a pointer to the string or NULL in case of error */ static char * virConfParseString(virConfParserCtxtPtr ctxt) { const char *base; char *ret = NULL; if (CUR == '\'') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR))) NEXT; if (CUR != '\'') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; } else if ((ctxt->cur + 6 < ctxt->end) && (STRPREFIX(ctxt->cur, "\"\"\""))) { /* String starts with python-style triple quotes """ */ ctxt->cur += 3; base = ctxt->cur; /* Find the ending triple quotes */ while ((ctxt->cur + 2 < ctxt->end) && !(STRPREFIX(ctxt->cur, "\"\"\""))) { if (CUR == '\n') ctxt->line++; NEXT; } if (!STRPREFIX(ctxt->cur, "\"\"\"")) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; ctxt->cur += 3; } else if (CUR == '"') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR))) NEXT; if (CUR != '"') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; } return ret; }
/** * virConfParseName: * @ctxt: the parsing context * * Parse one name * * Returns a copy of the new string, NULL in case of error */ static char * virConfParseName(virConfParserCtxtPtr ctxt) { const char *base; char *ret; SKIP_BLANKS; base = ctxt->cur; /* TODO: probably need encoding support and UTF-8 parsing ! */ if (!c_isalpha(CUR) && !((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && (CUR == '.'))) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a name")); return NULL; } while ((ctxt->cur < ctxt->end) && (c_isalnum(CUR) || (CUR == '_') || ((ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) && ((CUR == ':') || (CUR == '.') || (CUR == '-'))) || ((ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) && (CUR == '.')))) NEXT; if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; return ret; }
/** * virConfParseLong: * @ctxt: the parsing context * @val: the result * * Parse one long int value * * Returns 0 in case of success and -1 in case of error */ static int virConfParseLong(virConfParserCtxtPtr ctxt, long *val) { long l = 0; int neg = 0; if (CUR == '-') { neg = 1; NEXT; } else if (CUR == '+') { NEXT; } if ((ctxt->cur >= ctxt->end) || (!c_isdigit(CUR))) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated number")); return -1; } while ((ctxt->cur < ctxt->end) && (c_isdigit(CUR))) { l = l * 10 + (CUR - '0'); NEXT; } if (neg) l = -l; *val = l; return 0; }
/** * virConfReadFile: * @filename: the path to the configuration file. * @flags: combination of virConfFlag(s) * * Reads a configuration file. * * Returns a handle to lookup settings or NULL if it failed to * read or parse the file, use virConfFree() to free the data. */ virConfPtr virConfReadFile(const char *filename, unsigned int flags) { char *content; int len; virConfPtr conf = NULL; VIR_DEBUG("filename=%s", NULLSTR(filename)); if (filename == NULL) { virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return NULL; } if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0) return NULL; if (len && len < MAX_CONFIG_FILE_SIZE && content[len - 1] != '\n') { VIR_DEBUG("appending newline to busted config file %s", filename); if (VIR_REALLOC_N(content, len + 1) < 0) goto cleanup; content[len++] = '\n'; content[len] = '\0'; } conf = virConfParse(filename, content, len, flags); cleanup: VIR_FREE(content); return conf; }
static int remoteConfigGetAuth(virConfPtr conf, const char *key, int *auth, const char *filename) { virConfValuePtr p; p = virConfGetValue (conf, key); if (!p) return 0; if (checkType (p, filename, key, VIR_CONF_STRING) < 0) return -1; if (!p->str) return 0; if (STREQ(p->str, "none")) { *auth = VIR_NET_SERVER_SERVICE_AUTH_NONE; #if HAVE_SASL } else if (STREQ(p->str, "sasl")) { *auth = VIR_NET_SERVER_SERVICE_AUTH_SASL; #endif } else if (STREQ(p->str, "polkit")) { *auth = VIR_NET_SERVER_SERVICE_AUTH_POLKIT; } else { virConfError(VIR_ERR_CONFIG_UNSUPPORTED, _("remoteReadConfigFile: %s: %s: unsupported auth %s"), filename, key, p->str); return -1; } return 0; }
/** * virConfWriteFile: * @filename: the path to the configuration file. * @conf: the conf * * Writes a configuration file back to a file. * * Returns the number of bytes written or -1 in case of error. */ int virConfWriteFile(const char *filename, virConfPtr conf) { virBuffer buf = VIR_BUFFER_INITIALIZER; virConfEntryPtr cur; int ret; int fd; char *content; unsigned int use; if (conf == NULL) return -1; cur = conf->entries; while (cur != NULL) { virConfSaveEntry(&buf, cur); cur = cur->next; } if (virBufferError(&buf)) { virBufferFreeAndReset(&buf); virReportOOMError(); return -1; } fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); if (fd < 0) { virBufferFreeAndReset(&buf); virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to open file")); return -1; } use = virBufferUse(&buf); content = virBufferContentAndReset(&buf); ret = safewrite(fd, content, use); VIR_FREE(content); VIR_FORCE_CLOSE(fd); if (ret != (int)use) { virConfError(NULL, VIR_ERR_WRITE_FAILED, _("failed to save content")); return -1; } return ret; }
/** * virConfReadMem: * @memory: pointer to the content of the configuration file * @len: length in byte * @flags: combination of virConfFlag(s) * * Reads a configuration file loaded in memory. The string can be * zero terminated in which case @len can be 0 * * Returns a handle to lookup settings or NULL if it failed to * parse the content, use virConfFree() to free the data. */ virConfPtr virConfReadMem(const char *memory, int len, unsigned int flags) { if ((memory == NULL) || (len < 0)) { virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return NULL; } if (len == 0) len = strlen(memory); return virConfParse("memory conf", memory, len, flags); }
/* A helper function used by each of the following macros. */ static int checkType (virConfValuePtr p, const char *filename, const char *key, virConfType required_type) { if (p->type != required_type) { virConfError(VIR_ERR_CONFIG_UNSUPPORTED, _("remoteReadConfigFile: %s: %s: invalid type:" " got %s; expected %s"), filename, key, virConfTypeName (p->type), virConfTypeName (required_type)); return -1; } return 0; }
/** * virConfParseStatement: * @ctxt: the parsing context * * Parse one statement in the conf file * * Returns 0 in case of success and -1 in case of error */ static int virConfParseStatement(virConfParserCtxtPtr ctxt) { const char *base; char *name; virConfValuePtr value; char *comm = NULL; SKIP_BLANKS_AND_EOL; if (CUR == '#') { return virConfParseComment(ctxt); } name = virConfParseName(ctxt); if (name == NULL) return -1; SKIP_BLANKS; if (CUR != '=') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting an assignment")); VIR_FREE(name); return -1; } NEXT; SKIP_BLANKS; value = virConfParseValue(ctxt); if (value == NULL) { VIR_FREE(name); return -1; } SKIP_BLANKS; if (CUR == '#') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; comm = strndup(base, ctxt->cur - base); if (comm == NULL) { virReportOOMError(); VIR_FREE(name); virConfFreeValue(value); return -1; } } if (virConfAddEntry(ctxt->conf, name, value, comm) == NULL) { VIR_FREE(name); virConfFreeValue(value); VIR_FREE(comm); return -1; } return 0; }
/** * virConfParseSeparator: * @ctxt: the parsing context * * Parse one separator between statement if not at the end. * * Returns 0 in case of success and -1 in case of error */ static int virConfParseSeparator(virConfParserCtxtPtr ctxt) { SKIP_BLANKS; if (ctxt->cur >= ctxt->end) return 0; if (IS_EOL(CUR)) { SKIP_BLANKS_AND_EOL; } else if (CUR == ';') { NEXT; SKIP_BLANKS_AND_EOL; } else { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator")); return -1; } return 0; }
/** * virConfReadFile: * @filename: the path to the configuration file. * @flags: combination of virConfFlag(s) * * Reads a configuration file. * * Returns a handle to lookup settings or NULL if it failed to * read or parse the file, use virConfFree() to free the data. */ virConfPtr virConfReadFile(const char *filename, unsigned int flags) { char *content; int len; virConfPtr conf; if (filename == NULL) { virConfError(NULL, VIR_ERR_INVALID_ARG, __FUNCTION__); return NULL; } if ((len = virFileReadAll(filename, MAX_CONFIG_FILE_SIZE, &content)) < 0) { return NULL; } conf = virConfParse(filename, content, len, flags); VIR_FREE(content); return conf; }
/** * virConfParseValue: * @ctxt: the parsing context * * Parse one value * * Returns a pointer to the value or NULL in case of error */ static virConfValuePtr virConfParseValue(virConfParserCtxtPtr ctxt) { virConfValuePtr ret, lst = NULL, tmp, prev; virConfType type = VIR_CONF_NONE; char *str = NULL; long l = 0; SKIP_BLANKS; if (ctxt->cur >= ctxt->end) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value")); return NULL; } if ((CUR == '"') || (CUR == '\'') || (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT)) { type = VIR_CONF_STRING; str = virConfParseString(ctxt); if (str == NULL) return NULL; } else if (CUR == '[') { if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("lists not allowed in VMX format")); return NULL; } type = VIR_CONF_LIST; NEXT; SKIP_BLANKS_AND_EOL; if ((ctxt->cur < ctxt->end) && (CUR != ']')) { if ((lst = virConfParseValue(ctxt)) == NULL) return NULL; SKIP_BLANKS_AND_EOL; } while ((ctxt->cur < ctxt->end) && (CUR != ']')) { /* Tell Clang that when execution reaches this point "lst" is guaranteed to be non-NULL. This stops it from issuing an invalid NULL-dereference warning about "prev = lst; while (prev->next..." below. */ sa_assert(lst); if (CUR != ',') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a separator in list")); virConfFreeList(lst); return NULL; } NEXT; SKIP_BLANKS_AND_EOL; if (CUR == ']') { break; } tmp = virConfParseValue(ctxt); if (tmp == NULL) { virConfFreeList(lst); return NULL; } prev = lst; while (prev->next != NULL) prev = prev->next; prev->next = tmp; SKIP_BLANKS_AND_EOL; } if (CUR == ']') { NEXT; } else { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("list is not closed with ]")); virConfFreeList(lst); return NULL; } } else if (c_isdigit(CUR) || (CUR == '-') || (CUR == '+')) { if (ctxt->conf->flags & VIR_CONF_FLAG_VMX_FORMAT) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("numbers not allowed in VMX format")); return NULL; } if (virConfParseLong(ctxt, &l) < 0) { return NULL; } type = VIR_CONF_LONG; } else { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("expecting a value")); return NULL; } if (VIR_ALLOC(ret) < 0) { virConfFreeList(lst); VIR_FREE(str); return NULL; } ret->type = type; ret->l = l; ret->str = str; ret->list = lst; return ret; }
/** * virConfParseString: * @ctxt: the parsing context * * Parse one string * * Returns a pointer to the string or NULL in case of error */ static char * virConfParseString(virConfParserCtxtPtr ctxt) { const char *base; char *ret = NULL; if (CUR == '\'') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (CUR != '\'') && (!IS_EOL(CUR))) NEXT; if (CUR != '\'') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; } else if ((ctxt->cur + 6 < ctxt->end) && (STRPREFIX(ctxt->cur, "\"\"\""))) { /* String starts with python-style triple quotes """ */ ctxt->cur += 3; base = ctxt->cur; /* Find the ending triple quotes */ while ((ctxt->cur + 2 < ctxt->end) && !(STRPREFIX(ctxt->cur, "\"\"\""))) { if (CUR == '\n') ctxt->line++; NEXT; } if (!STRPREFIX(ctxt->cur, "\"\"\"")) { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; ctxt->cur += 3; } else if (CUR == '"') { NEXT; base = ctxt->cur; while ((ctxt->cur < ctxt->end) && (CUR != '"') && (!IS_EOL(CUR))) NEXT; if (CUR != '"') { virConfError(ctxt, VIR_ERR_CONF_SYNTAX, _("unterminated string")); return NULL; } if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; NEXT; } else if (ctxt->conf->flags & VIR_CONF_FLAG_LXC_FORMAT) { base = ctxt->cur; /* LXC config format doesn't support comments after the value */ while ((ctxt->cur < ctxt->end) && (!IS_EOL(CUR))) NEXT; /* Reverse to exclude the trailing blanks from the value */ while ((ctxt->cur > base) && (c_isblank(CUR))) ctxt->cur--; if (VIR_STRNDUP(ret, base, ctxt->cur - base) < 0) return NULL; } return ret; }
/* Allocate an array of malloc'd strings from the config file, filename * (used only in diagnostics), using handle "conf". Upon error, return -1 * and free any allocated memory. Otherwise, save the array in *list_arg * and return 0. */ static int remoteConfigGetStringList(virConfPtr conf, const char *key, char ***list_arg, const char *filename) { char **list; virConfValuePtr p = virConfGetValue (conf, key); if (!p) return 0; switch (p->type) { case VIR_CONF_STRING: if (VIR_ALLOC_N(list, 2) < 0) { virConfError(VIR_ERR_CONFIG_UNSUPPORTED, _("failed to allocate memory for %s config list"), key); return -1; } list[0] = strdup (p->str); list[1] = NULL; if (list[0] == NULL) { virConfError(VIR_ERR_CONFIG_UNSUPPORTED, _("failed to allocate memory for %s config list value"), key); VIR_FREE(list); return -1; } break; case VIR_CONF_LIST: { int i, len = 0; virConfValuePtr pp; for (pp = p->list; pp; pp = pp->next) len++; if (VIR_ALLOC_N(list, 1+len) < 0) { virConfError(VIR_ERR_CONFIG_UNSUPPORTED, _("failed to allocate memory for %s config list"), key); return -1; } for (i = 0, pp = p->list; pp; ++i, pp = pp->next) { if (pp->type != VIR_CONF_STRING) { virConfError(VIR_ERR_CONFIG_UNSUPPORTED, _("remoteReadConfigFile: %s: %s:" " must be a string or list of strings"), filename, key); VIR_FREE(list); return -1; } list[i] = strdup (pp->str); if (list[i] == NULL) { int j; for (j = 0 ; j < i ; j++) VIR_FREE(list[j]); VIR_FREE(list); virConfError(VIR_ERR_CONFIG_UNSUPPORTED, _("failed to allocate memory for %s config list value"), key); return -1; } } list[i] = NULL; break; } default: virConfError(VIR_ERR_CONFIG_UNSUPPORTED, _("remoteReadConfigFile: %s: %s:" " must be a string or list of strings"), filename, key); return -1; } *list_arg = list; return 0; }