/** * 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; }
/* * Manage input and output to the child process. */ static int virCommandProcessIO(virCommandPtr cmd) { int infd = -1, outfd = -1, errfd = -1; size_t inlen = 0, outlen = 0, errlen = 0; size_t inoff = 0; int ret = 0; /* With an input buffer, feed data to child * via pipe */ if (cmd->inbuf) { inlen = strlen(cmd->inbuf); infd = cmd->inpipe; } /* With out/err buffer, the outfd/errfd have been filled with an * FD for us. Guarantee an allocated string with partial results * even if we encounter a later failure, as well as freeing any * results accumulated over a prior run of the same command. */ if (cmd->outbuf) { outfd = cmd->outfd; if (VIR_REALLOC_N(*cmd->outbuf, 1) < 0) { virReportOOMError(); ret = -1; } } if (cmd->errbuf) { errfd = cmd->errfd; if (VIR_REALLOC_N(*cmd->errbuf, 1) < 0) { virReportOOMError(); ret = -1; } } if (ret == -1) goto cleanup; ret = -1; for (;;) { int i; struct pollfd fds[3]; int nfds = 0; if (infd != -1) { fds[nfds].fd = infd; fds[nfds].events = POLLOUT; nfds++; } if (outfd != -1) { fds[nfds].fd = outfd; fds[nfds].events = POLLIN; nfds++; } if (errfd != -1) { fds[nfds].fd = errfd; fds[nfds].events = POLLIN; nfds++; } if (nfds == 0) break; if (poll(fds, nfds, -1) < 0) { if ((errno == EAGAIN) || (errno == EINTR)) continue; virReportSystemError(errno, "%s", _("unable to poll on child")); goto cleanup; } for (i = 0; i < nfds ; i++) { if (fds[i].fd == errfd || fds[i].fd == outfd) { char data[1024]; char **buf; size_t *len; int done; if (fds[i].fd == outfd) { buf = cmd->outbuf; len = &outlen; } else { buf = cmd->errbuf; len = &errlen; } /* Silence a false positive from clang. */ sa_assert(buf); done = read(fds[i].fd, data, sizeof(data)); if (done < 0) { if (errno != EINTR && errno != EAGAIN) { virReportSystemError(errno, "%s", _("unable to write to child input")); goto cleanup; } } else if (done == 0) { if (fds[i].fd == outfd) outfd = -1; else errfd = -1; } else { if (VIR_REALLOC_N(*buf, *len + done + 1) < 0) { virReportOOMError(); goto cleanup; } memcpy(*buf + *len, data, done); *len += done; } } else { int done; done = write(infd, cmd->inbuf + inoff, inlen - inoff); if (done < 0) { if (errno != EINTR && errno != EAGAIN) { virReportSystemError(errno, "%s", _("unable to write to child input")); goto cleanup; } } else { inoff += done; if (inoff == inlen) { int tmpfd = infd; if (VIR_CLOSE(infd) < 0) VIR_DEBUG("ignoring failed close on fd %d", tmpfd); } } } } } ret = 0; cleanup: if (cmd->outbuf && *cmd->outbuf) (*cmd->outbuf)[outlen] = '\0'; if (cmd->errbuf && *cmd->errbuf) (*cmd->errbuf)[errlen] = '\0'; return ret; }
static int virCgroupMakeGroup(virCgroupPtr parent, virCgroupPtr group, int create, unsigned int flags) { int i; int rc = 0; VIR_DEBUG("Make group %s", group->path); for (i = 0 ; i < VIR_CGROUP_CONTROLLER_LAST ; i++) { char *path = NULL; /* Skip over controllers that aren't mounted */ if (!group->controllers[i].mountPoint) continue; /* We need to control cpu bandwidth for each vcpu now */ if ((flags & VIR_CGROUP_VCPU) && (i != VIR_CGROUP_CONTROLLER_CPU && i != VIR_CGROUP_CONTROLLER_CPUACCT)) { /* treat it as unmounted and we can use virCgroupAddTask */ VIR_FREE(group->controllers[i].mountPoint); continue; } rc = virCgroupPathOfController(group, i, "", &path); if (rc < 0) return rc; /* As of Feb 2011, clang can't see that the above function * call did not modify group. */ sa_assert(group->controllers[i].mountPoint); VIR_DEBUG("Make controller %s", path); if (access(path, F_OK) != 0) { if (!create || mkdir(path, 0755) < 0) { /* With a kernel that doesn't support multi-level directory * for blkio controller, libvirt will fail and disable all * other controllers even though they are available. So * treat blkio as unmounted if mkdir fails. */ if (i == VIR_CGROUP_CONTROLLER_BLKIO) { rc = 0; VIR_FREE(group->controllers[i].mountPoint); VIR_FREE(path); continue; } else { rc = -errno; VIR_FREE(path); break; } } if (group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint != NULL && (i == VIR_CGROUP_CONTROLLER_CPUSET || STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_CPUSET].mountPoint))) { rc = virCgroupCpuSetInherit(parent, group); if (rc != 0) { VIR_FREE(path); break; } } /* * Note that virCgroupSetMemoryUseHierarchy should always be * called prior to creating subcgroups and attaching tasks. */ if ((flags & VIR_CGROUP_MEM_HIERACHY) && (group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint != NULL) && (i == VIR_CGROUP_CONTROLLER_MEMORY || STREQ(group->controllers[i].mountPoint, group->controllers[VIR_CGROUP_CONTROLLER_MEMORY].mountPoint))) { rc = virCgroupSetMemoryUseHierarchy(group); if (rc != 0) { VIR_FREE(path); break; } } } VIR_FREE(path); } return rc; }
/** * virBitmapParse: * @str: points to a string representing a human-readable bitmap * @terminator: character separating the bitmap to parse * @bitmap: a bitmap created from @str * @bitmapSize: the upper limit of num of bits in created bitmap * * This function is the counterpart of virBitmapFormat. This function creates * a bitmap, in which bits are set according to the content of @str. * * @str is a comma separated string of fields N, which means a number of bit * to set, and ^N, which means to unset the bit, and N-M for ranges of bits * to set. * * To allow parsing of bitmaps within larger strings it is possible to set * a termination character in the argument @terminator. When the character * in @terminator is encountered in @str, the parsing of the bitmap stops. * Pass 0 as @terminator if it is not needed. Whitespace characters may not * be used as terminators. * * Returns the number of bits set in @bitmap, or -1 in case of error. */ int virBitmapParse(const char *str, char terminator, virBitmapPtr *bitmap, size_t bitmapSize) { int ret = 0; bool neg = false; const char *cur; char *tmp; size_t i; int start, last; if (!str) return -1; cur = str; virSkipSpaces(&cur); if (*cur == 0) return -1; *bitmap = virBitmapNew(bitmapSize); if (!*bitmap) return -1; while (*cur != 0 && *cur != terminator) { /* * 3 constructs are allowed: * - N : a single CPU number * - N-M : a range of CPU numbers with N < M * - ^N : remove a single CPU number from the current set */ if (*cur == '^') { cur++; neg = true; } if (!c_isdigit(*cur)) goto parse_error; if (virStrToLong_i(cur, &tmp, 10, &start) < 0) goto parse_error; if (start < 0) goto parse_error; cur = tmp; virSkipSpaces(&cur); if (*cur == ',' || *cur == 0 || *cur == terminator) { if (neg) { if (virBitmapIsSet(*bitmap, start)) { ignore_value(virBitmapClearBit(*bitmap, start)); ret--; } } else { if (!virBitmapIsSet(*bitmap, start)) { ignore_value(virBitmapSetBit(*bitmap, start)); ret++; } } } else if (*cur == '-') { if (neg) goto parse_error; cur++; virSkipSpaces(&cur); if (virStrToLong_i(cur, &tmp, 10, &last) < 0) goto parse_error; if (last < start) goto parse_error; cur = tmp; for (i = start; i <= last; i++) { if (!virBitmapIsSet(*bitmap, i)) { ignore_value(virBitmapSetBit(*bitmap, i)); ret++; } } virSkipSpaces(&cur); } if (*cur == ',') { cur++; virSkipSpaces(&cur); neg = false; } else if (*cur == 0 || *cur == terminator) { break; } else { goto parse_error; } } sa_assert(ret >= 0); return ret; parse_error: virBitmapFree(*bitmap); *bitmap = NULL; return -1; }