mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-06 09:13:55 -06:00
build: move libqemuutil.a components to util/
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
This commit is contained in:
parent
f157ebba2d
commit
baacf04799
31 changed files with 15 additions and 13 deletions
10
util/Makefile.objs
Normal file
10
util/Makefile.objs
Normal file
|
@ -0,0 +1,10 @@
|
|||
util-obj-y = osdep.o cutils.o qemu-timer-common.o
|
||||
util-obj-$(CONFIG_WIN32) += oslib-win32.o qemu-thread-win32.o event_notifier-win32.o
|
||||
util-obj-$(CONFIG_POSIX) += oslib-posix.o qemu-thread-posix.o event_notifier-posix.o
|
||||
util-obj-y += envlist.o path.o host-utils.o cache-utils.o module.o
|
||||
util-obj-y += bitmap.o bitops.o
|
||||
util-obj-y += acl.o
|
||||
util-obj-y += error.o qemu-error.o
|
||||
util-obj-$(CONFIG_POSIX) += compatfd.o
|
||||
util-obj-y += iov.o aes.o qemu-config.o qemu-sockets.o uri.o notify.o
|
||||
util-obj-y += qemu-option.o qemu-progress.o
|
184
util/acl.c
Normal file
184
util/acl.c
Normal file
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* QEMU access control list management
|
||||
*
|
||||
* Copyright (C) 2009 Red Hat, Inc
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/acl.h"
|
||||
|
||||
#ifdef CONFIG_FNMATCH
|
||||
#include <fnmatch.h>
|
||||
#endif
|
||||
|
||||
|
||||
static unsigned int nacls = 0;
|
||||
static qemu_acl **acls = NULL;
|
||||
|
||||
|
||||
|
||||
qemu_acl *qemu_acl_find(const char *aclname)
|
||||
{
|
||||
int i;
|
||||
for (i = 0 ; i < nacls ; i++) {
|
||||
if (strcmp(acls[i]->aclname, aclname) == 0)
|
||||
return acls[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
qemu_acl *qemu_acl_init(const char *aclname)
|
||||
{
|
||||
qemu_acl *acl;
|
||||
|
||||
acl = qemu_acl_find(aclname);
|
||||
if (acl)
|
||||
return acl;
|
||||
|
||||
acl = g_malloc(sizeof(*acl));
|
||||
acl->aclname = g_strdup(aclname);
|
||||
/* Deny by default, so there is no window of "open
|
||||
* access" between QEMU starting, and the user setting
|
||||
* up ACLs in the monitor */
|
||||
acl->defaultDeny = 1;
|
||||
|
||||
acl->nentries = 0;
|
||||
QTAILQ_INIT(&acl->entries);
|
||||
|
||||
acls = g_realloc(acls, sizeof(*acls) * (nacls +1));
|
||||
acls[nacls] = acl;
|
||||
nacls++;
|
||||
|
||||
return acl;
|
||||
}
|
||||
|
||||
int qemu_acl_party_is_allowed(qemu_acl *acl,
|
||||
const char *party)
|
||||
{
|
||||
qemu_acl_entry *entry;
|
||||
|
||||
QTAILQ_FOREACH(entry, &acl->entries, next) {
|
||||
#ifdef CONFIG_FNMATCH
|
||||
if (fnmatch(entry->match, party, 0) == 0)
|
||||
return entry->deny ? 0 : 1;
|
||||
#else
|
||||
/* No fnmatch, so fallback to exact string matching
|
||||
* instead of allowing wildcards */
|
||||
if (strcmp(entry->match, party) == 0)
|
||||
return entry->deny ? 0 : 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
return acl->defaultDeny ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
void qemu_acl_reset(qemu_acl *acl)
|
||||
{
|
||||
qemu_acl_entry *entry, *next_entry;
|
||||
|
||||
/* Put back to deny by default, so there is no window
|
||||
* of "open access" while the user re-initializes the
|
||||
* access control list */
|
||||
acl->defaultDeny = 1;
|
||||
QTAILQ_FOREACH_SAFE(entry, &acl->entries, next, next_entry) {
|
||||
QTAILQ_REMOVE(&acl->entries, entry, next);
|
||||
free(entry->match);
|
||||
free(entry);
|
||||
}
|
||||
acl->nentries = 0;
|
||||
}
|
||||
|
||||
|
||||
int qemu_acl_append(qemu_acl *acl,
|
||||
int deny,
|
||||
const char *match)
|
||||
{
|
||||
qemu_acl_entry *entry;
|
||||
|
||||
entry = g_malloc(sizeof(*entry));
|
||||
entry->match = g_strdup(match);
|
||||
entry->deny = deny;
|
||||
|
||||
QTAILQ_INSERT_TAIL(&acl->entries, entry, next);
|
||||
acl->nentries++;
|
||||
|
||||
return acl->nentries;
|
||||
}
|
||||
|
||||
|
||||
int qemu_acl_insert(qemu_acl *acl,
|
||||
int deny,
|
||||
const char *match,
|
||||
int index)
|
||||
{
|
||||
qemu_acl_entry *entry;
|
||||
qemu_acl_entry *tmp;
|
||||
int i = 0;
|
||||
|
||||
if (index <= 0)
|
||||
return -1;
|
||||
if (index >= acl->nentries)
|
||||
return qemu_acl_append(acl, deny, match);
|
||||
|
||||
|
||||
entry = g_malloc(sizeof(*entry));
|
||||
entry->match = g_strdup(match);
|
||||
entry->deny = deny;
|
||||
|
||||
QTAILQ_FOREACH(tmp, &acl->entries, next) {
|
||||
i++;
|
||||
if (i == index) {
|
||||
QTAILQ_INSERT_BEFORE(tmp, entry, next);
|
||||
acl->nentries++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int qemu_acl_remove(qemu_acl *acl,
|
||||
const char *match)
|
||||
{
|
||||
qemu_acl_entry *entry;
|
||||
int i = 0;
|
||||
|
||||
QTAILQ_FOREACH(entry, &acl->entries, next) {
|
||||
i++;
|
||||
if (strcmp(entry->match, match) == 0) {
|
||||
QTAILQ_REMOVE(&acl->entries, entry, next);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-indent-level: 4
|
||||
* c-basic-offset: 4
|
||||
* tab-width: 8
|
||||
* End:
|
||||
*/
|
1314
util/aes.c
Normal file
1314
util/aes.c
Normal file
File diff suppressed because it is too large
Load diff
256
util/bitmap.c
Normal file
256
util/bitmap.c
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* Bitmap Module
|
||||
*
|
||||
* Stolen from linux/src/lib/bitmap.c
|
||||
*
|
||||
* Copyright (C) 2010 Corentin Chary
|
||||
*
|
||||
* This source code is licensed under the GNU General Public License,
|
||||
* Version 2.
|
||||
*/
|
||||
|
||||
#include "qemu/bitops.h"
|
||||
#include "qemu/bitmap.h"
|
||||
|
||||
/*
|
||||
* bitmaps provide an array of bits, implemented using an an
|
||||
* array of unsigned longs. The number of valid bits in a
|
||||
* given bitmap does _not_ need to be an exact multiple of
|
||||
* BITS_PER_LONG.
|
||||
*
|
||||
* The possible unused bits in the last, partially used word
|
||||
* of a bitmap are 'don't care'. The implementation makes
|
||||
* no particular effort to keep them zero. It ensures that
|
||||
* their value will not affect the results of any operation.
|
||||
* The bitmap operations that return Boolean (bitmap_empty,
|
||||
* for example) or scalar (bitmap_weight, for example) results
|
||||
* carefully filter out these unused bits from impacting their
|
||||
* results.
|
||||
*
|
||||
* These operations actually hold to a slightly stronger rule:
|
||||
* if you don't input any bitmaps to these ops that have some
|
||||
* unused bits set, then they won't output any set unused bits
|
||||
* in output bitmaps.
|
||||
*
|
||||
* The byte ordering of bitmaps is more natural on little
|
||||
* endian architectures.
|
||||
*/
|
||||
|
||||
int slow_bitmap_empty(const unsigned long *bitmap, int bits)
|
||||
{
|
||||
int k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
if (bitmap[k]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (bits % BITS_PER_LONG) {
|
||||
if (bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int slow_bitmap_full(const unsigned long *bitmap, int bits)
|
||||
{
|
||||
int k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
if (~bitmap[k]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bits % BITS_PER_LONG) {
|
||||
if (~bitmap[k] & BITMAP_LAST_WORD_MASK(bits)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int slow_bitmap_equal(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits)
|
||||
{
|
||||
int k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
if (bitmap1[k] != bitmap2[k]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bits % BITS_PER_LONG) {
|
||||
if ((bitmap1[k] ^ bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void slow_bitmap_complement(unsigned long *dst, const unsigned long *src,
|
||||
int bits)
|
||||
{
|
||||
int k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
dst[k] = ~src[k];
|
||||
}
|
||||
|
||||
if (bits % BITS_PER_LONG) {
|
||||
dst[k] = ~src[k] & BITMAP_LAST_WORD_MASK(bits);
|
||||
}
|
||||
}
|
||||
|
||||
int slow_bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits)
|
||||
{
|
||||
int k;
|
||||
int nr = BITS_TO_LONGS(bits);
|
||||
unsigned long result = 0;
|
||||
|
||||
for (k = 0; k < nr; k++) {
|
||||
result |= (dst[k] = bitmap1[k] & bitmap2[k]);
|
||||
}
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
void slow_bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits)
|
||||
{
|
||||
int k;
|
||||
int nr = BITS_TO_LONGS(bits);
|
||||
|
||||
for (k = 0; k < nr; k++) {
|
||||
dst[k] = bitmap1[k] | bitmap2[k];
|
||||
}
|
||||
}
|
||||
|
||||
void slow_bitmap_xor(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits)
|
||||
{
|
||||
int k;
|
||||
int nr = BITS_TO_LONGS(bits);
|
||||
|
||||
for (k = 0; k < nr; k++) {
|
||||
dst[k] = bitmap1[k] ^ bitmap2[k];
|
||||
}
|
||||
}
|
||||
|
||||
int slow_bitmap_andnot(unsigned long *dst, const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits)
|
||||
{
|
||||
int k;
|
||||
int nr = BITS_TO_LONGS(bits);
|
||||
unsigned long result = 0;
|
||||
|
||||
for (k = 0; k < nr; k++) {
|
||||
result |= (dst[k] = bitmap1[k] & ~bitmap2[k]);
|
||||
}
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
#define BITMAP_FIRST_WORD_MASK(start) (~0UL << ((start) % BITS_PER_LONG))
|
||||
|
||||
void bitmap_set(unsigned long *map, int start, int nr)
|
||||
{
|
||||
unsigned long *p = map + BIT_WORD(start);
|
||||
const int size = start + nr;
|
||||
int bits_to_set = BITS_PER_LONG - (start % BITS_PER_LONG);
|
||||
unsigned long mask_to_set = BITMAP_FIRST_WORD_MASK(start);
|
||||
|
||||
while (nr - bits_to_set >= 0) {
|
||||
*p |= mask_to_set;
|
||||
nr -= bits_to_set;
|
||||
bits_to_set = BITS_PER_LONG;
|
||||
mask_to_set = ~0UL;
|
||||
p++;
|
||||
}
|
||||
if (nr) {
|
||||
mask_to_set &= BITMAP_LAST_WORD_MASK(size);
|
||||
*p |= mask_to_set;
|
||||
}
|
||||
}
|
||||
|
||||
void bitmap_clear(unsigned long *map, int start, int nr)
|
||||
{
|
||||
unsigned long *p = map + BIT_WORD(start);
|
||||
const int size = start + nr;
|
||||
int bits_to_clear = BITS_PER_LONG - (start % BITS_PER_LONG);
|
||||
unsigned long mask_to_clear = BITMAP_FIRST_WORD_MASK(start);
|
||||
|
||||
while (nr - bits_to_clear >= 0) {
|
||||
*p &= ~mask_to_clear;
|
||||
nr -= bits_to_clear;
|
||||
bits_to_clear = BITS_PER_LONG;
|
||||
mask_to_clear = ~0UL;
|
||||
p++;
|
||||
}
|
||||
if (nr) {
|
||||
mask_to_clear &= BITMAP_LAST_WORD_MASK(size);
|
||||
*p &= ~mask_to_clear;
|
||||
}
|
||||
}
|
||||
|
||||
#define ALIGN_MASK(x,mask) (((x)+(mask))&~(mask))
|
||||
|
||||
/**
|
||||
* bitmap_find_next_zero_area - find a contiguous aligned zero area
|
||||
* @map: The address to base the search on
|
||||
* @size: The bitmap size in bits
|
||||
* @start: The bitnumber to start searching at
|
||||
* @nr: The number of zeroed bits we're looking for
|
||||
* @align_mask: Alignment mask for zero area
|
||||
*
|
||||
* The @align_mask should be one less than a power of 2; the effect is that
|
||||
* the bit offset of all zero areas this function finds is multiples of that
|
||||
* power of 2. A @align_mask of 0 means no alignment is required.
|
||||
*/
|
||||
unsigned long bitmap_find_next_zero_area(unsigned long *map,
|
||||
unsigned long size,
|
||||
unsigned long start,
|
||||
unsigned int nr,
|
||||
unsigned long align_mask)
|
||||
{
|
||||
unsigned long index, end, i;
|
||||
again:
|
||||
index = find_next_zero_bit(map, size, start);
|
||||
|
||||
/* Align allocation */
|
||||
index = ALIGN_MASK(index, align_mask);
|
||||
|
||||
end = index + nr;
|
||||
if (end > size) {
|
||||
return end;
|
||||
}
|
||||
i = find_next_bit(map, end, index);
|
||||
if (i < end) {
|
||||
start = i + 1;
|
||||
goto again;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int slow_bitmap_intersects(const unsigned long *bitmap1,
|
||||
const unsigned long *bitmap2, int bits)
|
||||
{
|
||||
int k, lim = bits/BITS_PER_LONG;
|
||||
|
||||
for (k = 0; k < lim; ++k) {
|
||||
if (bitmap1[k] & bitmap2[k]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bits % BITS_PER_LONG) {
|
||||
if ((bitmap1[k] & bitmap2[k]) & BITMAP_LAST_WORD_MASK(bits)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
142
util/bitops.c
Normal file
142
util/bitops.c
Normal file
|
@ -0,0 +1,142 @@
|
|||
/*
|
||||
* Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
* Copyright (C) 2008 IBM Corporation
|
||||
* Written by Rusty Russell <rusty@rustcorp.com.au>
|
||||
* (Inspired by David Howell's find_next_bit implementation)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/bitops.h"
|
||||
|
||||
#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
|
||||
|
||||
/*
|
||||
* Find the next set bit in a memory region.
|
||||
*/
|
||||
unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
|
||||
unsigned long offset)
|
||||
{
|
||||
const unsigned long *p = addr + BITOP_WORD(offset);
|
||||
unsigned long result = offset & ~(BITS_PER_LONG-1);
|
||||
unsigned long tmp;
|
||||
|
||||
if (offset >= size) {
|
||||
return size;
|
||||
}
|
||||
size -= result;
|
||||
offset %= BITS_PER_LONG;
|
||||
if (offset) {
|
||||
tmp = *(p++);
|
||||
tmp &= (~0UL << offset);
|
||||
if (size < BITS_PER_LONG) {
|
||||
goto found_first;
|
||||
}
|
||||
if (tmp) {
|
||||
goto found_middle;
|
||||
}
|
||||
size -= BITS_PER_LONG;
|
||||
result += BITS_PER_LONG;
|
||||
}
|
||||
while (size & ~(BITS_PER_LONG-1)) {
|
||||
if ((tmp = *(p++))) {
|
||||
goto found_middle;
|
||||
}
|
||||
result += BITS_PER_LONG;
|
||||
size -= BITS_PER_LONG;
|
||||
}
|
||||
if (!size) {
|
||||
return result;
|
||||
}
|
||||
tmp = *p;
|
||||
|
||||
found_first:
|
||||
tmp &= (~0UL >> (BITS_PER_LONG - size));
|
||||
if (tmp == 0UL) { /* Are any bits set? */
|
||||
return result + size; /* Nope. */
|
||||
}
|
||||
found_middle:
|
||||
return result + bitops_ffsl(tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This implementation of find_{first,next}_zero_bit was stolen from
|
||||
* Linus' asm-alpha/bitops.h.
|
||||
*/
|
||||
unsigned long find_next_zero_bit(const unsigned long *addr, unsigned long size,
|
||||
unsigned long offset)
|
||||
{
|
||||
const unsigned long *p = addr + BITOP_WORD(offset);
|
||||
unsigned long result = offset & ~(BITS_PER_LONG-1);
|
||||
unsigned long tmp;
|
||||
|
||||
if (offset >= size) {
|
||||
return size;
|
||||
}
|
||||
size -= result;
|
||||
offset %= BITS_PER_LONG;
|
||||
if (offset) {
|
||||
tmp = *(p++);
|
||||
tmp |= ~0UL >> (BITS_PER_LONG - offset);
|
||||
if (size < BITS_PER_LONG) {
|
||||
goto found_first;
|
||||
}
|
||||
if (~tmp) {
|
||||
goto found_middle;
|
||||
}
|
||||
size -= BITS_PER_LONG;
|
||||
result += BITS_PER_LONG;
|
||||
}
|
||||
while (size & ~(BITS_PER_LONG-1)) {
|
||||
if (~(tmp = *(p++))) {
|
||||
goto found_middle;
|
||||
}
|
||||
result += BITS_PER_LONG;
|
||||
size -= BITS_PER_LONG;
|
||||
}
|
||||
if (!size) {
|
||||
return result;
|
||||
}
|
||||
tmp = *p;
|
||||
|
||||
found_first:
|
||||
tmp |= ~0UL << size;
|
||||
if (tmp == ~0UL) { /* Are any bits zero? */
|
||||
return result + size; /* Nope. */
|
||||
}
|
||||
found_middle:
|
||||
return result + ffz(tmp);
|
||||
}
|
||||
|
||||
unsigned long find_last_bit(const unsigned long *addr, unsigned long size)
|
||||
{
|
||||
unsigned long words;
|
||||
unsigned long tmp;
|
||||
|
||||
/* Start at final word. */
|
||||
words = size / BITS_PER_LONG;
|
||||
|
||||
/* Partial final word? */
|
||||
if (size & (BITS_PER_LONG-1)) {
|
||||
tmp = (addr[words] & (~0UL >> (BITS_PER_LONG
|
||||
- (size & (BITS_PER_LONG-1)))));
|
||||
if (tmp) {
|
||||
goto found;
|
||||
}
|
||||
}
|
||||
|
||||
while (words) {
|
||||
tmp = addr[--words];
|
||||
if (tmp) {
|
||||
found:
|
||||
return words * BITS_PER_LONG + bitops_flsl(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return size;
|
||||
}
|
97
util/cache-utils.c
Normal file
97
util/cache-utils.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
#include "qemu/cache-utils.h"
|
||||
|
||||
#if defined(_ARCH_PPC)
|
||||
struct qemu_cache_conf qemu_cache_conf = {
|
||||
.dcache_bsize = 16,
|
||||
.icache_bsize = 16
|
||||
};
|
||||
|
||||
#if defined _AIX
|
||||
#include <sys/systemcfg.h>
|
||||
|
||||
static void ppc_init_cacheline_sizes(void)
|
||||
{
|
||||
qemu_cache_conf.icache_bsize = _system_configuration.icache_line;
|
||||
qemu_cache_conf.dcache_bsize = _system_configuration.dcache_line;
|
||||
}
|
||||
|
||||
#elif defined __linux__
|
||||
|
||||
#define QEMU_AT_NULL 0
|
||||
#define QEMU_AT_DCACHEBSIZE 19
|
||||
#define QEMU_AT_ICACHEBSIZE 20
|
||||
|
||||
static void ppc_init_cacheline_sizes(char **envp)
|
||||
{
|
||||
unsigned long *auxv;
|
||||
|
||||
while (*envp++);
|
||||
|
||||
for (auxv = (unsigned long *) envp; *auxv != QEMU_AT_NULL; auxv += 2) {
|
||||
switch (*auxv) {
|
||||
case QEMU_AT_DCACHEBSIZE: qemu_cache_conf.dcache_bsize = auxv[1]; break;
|
||||
case QEMU_AT_ICACHEBSIZE: qemu_cache_conf.icache_bsize = auxv[1]; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined __APPLE__
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
static void ppc_init_cacheline_sizes(void)
|
||||
{
|
||||
size_t len;
|
||||
unsigned cacheline;
|
||||
int name[2] = { CTL_HW, HW_CACHELINE };
|
||||
|
||||
len = sizeof(cacheline);
|
||||
if (sysctl(name, 2, &cacheline, &len, NULL, 0)) {
|
||||
perror("sysctl CTL_HW HW_CACHELINE failed");
|
||||
} else {
|
||||
qemu_cache_conf.dcache_bsize = cacheline;
|
||||
qemu_cache_conf.icache_bsize = cacheline;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
|
||||
static void ppc_init_cacheline_sizes(void)
|
||||
{
|
||||
size_t len = 4;
|
||||
unsigned cacheline;
|
||||
|
||||
if (sysctlbyname ("machdep.cacheline_size", &cacheline, &len, NULL, 0)) {
|
||||
fprintf(stderr, "sysctlbyname machdep.cacheline_size failed: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
qemu_cache_conf.dcache_bsize = cacheline;
|
||||
qemu_cache_conf.icache_bsize = cacheline;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef __linux__
|
||||
void qemu_cache_utils_init(char **envp)
|
||||
{
|
||||
ppc_init_cacheline_sizes(envp);
|
||||
}
|
||||
#else
|
||||
void qemu_cache_utils_init(char **envp)
|
||||
{
|
||||
(void) envp;
|
||||
ppc_init_cacheline_sizes();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _ARCH_PPC */
|
138
util/compatfd.c
Normal file
138
util/compatfd.c
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
* signalfd/eventfd compatibility
|
||||
*
|
||||
* Copyright IBM, Corp. 2008
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/compatfd.h"
|
||||
|
||||
#include <sys/syscall.h>
|
||||
#include <pthread.h>
|
||||
|
||||
struct sigfd_compat_info
|
||||
{
|
||||
sigset_t mask;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void *sigwait_compat(void *opaque)
|
||||
{
|
||||
struct sigfd_compat_info *info = opaque;
|
||||
sigset_t all;
|
||||
|
||||
sigfillset(&all);
|
||||
pthread_sigmask(SIG_BLOCK, &all, NULL);
|
||||
|
||||
while (1) {
|
||||
int sig;
|
||||
int err;
|
||||
|
||||
err = sigwait(&info->mask, &sig);
|
||||
if (err != 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
struct qemu_signalfd_siginfo buffer;
|
||||
size_t offset = 0;
|
||||
|
||||
memset(&buffer, 0, sizeof(buffer));
|
||||
buffer.ssi_signo = sig;
|
||||
|
||||
while (offset < sizeof(buffer)) {
|
||||
ssize_t len;
|
||||
|
||||
len = write(info->fd, (char *)&buffer + offset,
|
||||
sizeof(buffer) - offset);
|
||||
if (len == -1 && errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (len <= 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
offset += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int qemu_signalfd_compat(const sigset_t *mask)
|
||||
{
|
||||
pthread_attr_t attr;
|
||||
pthread_t tid;
|
||||
struct sigfd_compat_info *info;
|
||||
int fds[2];
|
||||
|
||||
info = malloc(sizeof(*info));
|
||||
if (info == NULL) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pipe(fds) == -1) {
|
||||
free(info);
|
||||
return -1;
|
||||
}
|
||||
|
||||
qemu_set_cloexec(fds[0]);
|
||||
qemu_set_cloexec(fds[1]);
|
||||
|
||||
memcpy(&info->mask, mask, sizeof(*mask));
|
||||
info->fd = fds[1];
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
pthread_create(&tid, &attr, sigwait_compat, info);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
|
||||
return fds[0];
|
||||
}
|
||||
|
||||
int qemu_signalfd(const sigset_t *mask)
|
||||
{
|
||||
#if defined(CONFIG_SIGNALFD)
|
||||
int ret;
|
||||
|
||||
ret = syscall(SYS_signalfd, -1, mask, _NSIG / 8);
|
||||
if (ret != -1) {
|
||||
qemu_set_cloexec(ret);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
return qemu_signalfd_compat(mask);
|
||||
}
|
||||
|
||||
bool qemu_signalfd_available(void)
|
||||
{
|
||||
#ifdef CONFIG_SIGNALFD
|
||||
sigset_t mask;
|
||||
int fd;
|
||||
bool ok;
|
||||
sigemptyset(&mask);
|
||||
errno = 0;
|
||||
fd = syscall(SYS_signalfd, -1, &mask, _NSIG / 8);
|
||||
ok = (errno != ENOSYS);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
return ok;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
325
util/cutils.c
Normal file
325
util/cutils.c
Normal file
|
@ -0,0 +1,325 @@
|
|||
/*
|
||||
* Simple C functions to supplement the C library
|
||||
*
|
||||
* Copyright (c) 2006 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/host-utils.h"
|
||||
#include <math.h>
|
||||
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu/iov.h"
|
||||
|
||||
void strpadcpy(char *buf, int buf_size, const char *str, char pad)
|
||||
{
|
||||
int len = qemu_strnlen(str, buf_size);
|
||||
memcpy(buf, str, len);
|
||||
memset(buf + len, pad, buf_size - len);
|
||||
}
|
||||
|
||||
void pstrcpy(char *buf, int buf_size, const char *str)
|
||||
{
|
||||
int c;
|
||||
char *q = buf;
|
||||
|
||||
if (buf_size <= 0)
|
||||
return;
|
||||
|
||||
for(;;) {
|
||||
c = *str++;
|
||||
if (c == 0 || q >= buf + buf_size - 1)
|
||||
break;
|
||||
*q++ = c;
|
||||
}
|
||||
*q = '\0';
|
||||
}
|
||||
|
||||
/* strcat and truncate. */
|
||||
char *pstrcat(char *buf, int buf_size, const char *s)
|
||||
{
|
||||
int len;
|
||||
len = strlen(buf);
|
||||
if (len < buf_size)
|
||||
pstrcpy(buf + len, buf_size - len, s);
|
||||
return buf;
|
||||
}
|
||||
|
||||
int strstart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (*p != *q)
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int stristart(const char *str, const char *val, const char **ptr)
|
||||
{
|
||||
const char *p, *q;
|
||||
p = str;
|
||||
q = val;
|
||||
while (*q != '\0') {
|
||||
if (qemu_toupper(*p) != qemu_toupper(*q))
|
||||
return 0;
|
||||
p++;
|
||||
q++;
|
||||
}
|
||||
if (ptr)
|
||||
*ptr = p;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* XXX: use host strnlen if available ? */
|
||||
int qemu_strnlen(const char *s, int max_len)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < max_len; i++) {
|
||||
if (s[i] == '\0') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
time_t mktimegm(struct tm *tm)
|
||||
{
|
||||
time_t t;
|
||||
int y = tm->tm_year + 1900, m = tm->tm_mon + 1, d = tm->tm_mday;
|
||||
if (m < 3) {
|
||||
m += 12;
|
||||
y--;
|
||||
}
|
||||
t = 86400ULL * (d + (153 * m - 457) / 5 + 365 * y + y / 4 - y / 100 +
|
||||
y / 400 - 719469);
|
||||
t += 3600 * tm->tm_hour + 60 * tm->tm_min + tm->tm_sec;
|
||||
return t;
|
||||
}
|
||||
|
||||
int qemu_fls(int i)
|
||||
{
|
||||
return 32 - clz32(i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure data goes on disk, but if possible do not bother to
|
||||
* write out the inode just for timestamp updates.
|
||||
*
|
||||
* Unfortunately even in 2009 many operating systems do not support
|
||||
* fdatasync and have to fall back to fsync.
|
||||
*/
|
||||
int qemu_fdatasync(int fd)
|
||||
{
|
||||
#ifdef CONFIG_FDATASYNC
|
||||
return fdatasync(fd);
|
||||
#else
|
||||
return fsync(fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if a buffer is all zeroes
|
||||
*
|
||||
* Attention! The len must be a multiple of 4 * sizeof(long) due to
|
||||
* restriction of optimizations in this function.
|
||||
*/
|
||||
bool buffer_is_zero(const void *buf, size_t len)
|
||||
{
|
||||
/*
|
||||
* Use long as the biggest available internal data type that fits into the
|
||||
* CPU register and unroll the loop to smooth out the effect of memory
|
||||
* latency.
|
||||
*/
|
||||
|
||||
size_t i;
|
||||
long d0, d1, d2, d3;
|
||||
const long * const data = buf;
|
||||
|
||||
assert(len % (4 * sizeof(long)) == 0);
|
||||
len /= sizeof(long);
|
||||
|
||||
for (i = 0; i < len; i += 4) {
|
||||
d0 = data[i + 0];
|
||||
d1 = data[i + 1];
|
||||
d2 = data[i + 2];
|
||||
d3 = data[i + 3];
|
||||
|
||||
if (d0 || d1 || d2 || d3) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/* Sets a specific flag */
|
||||
int fcntl_setfl(int fd, int flag)
|
||||
{
|
||||
int flags;
|
||||
|
||||
flags = fcntl(fd, F_GETFL);
|
||||
if (flags == -1)
|
||||
return -errno;
|
||||
|
||||
if (fcntl(fd, F_SETFL, flags | flag) == -1)
|
||||
return -errno;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int64_t suffix_mul(char suffix, int64_t unit)
|
||||
{
|
||||
switch (qemu_toupper(suffix)) {
|
||||
case STRTOSZ_DEFSUFFIX_B:
|
||||
return 1;
|
||||
case STRTOSZ_DEFSUFFIX_KB:
|
||||
return unit;
|
||||
case STRTOSZ_DEFSUFFIX_MB:
|
||||
return unit * unit;
|
||||
case STRTOSZ_DEFSUFFIX_GB:
|
||||
return unit * unit * unit;
|
||||
case STRTOSZ_DEFSUFFIX_TB:
|
||||
return unit * unit * unit * unit;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert string to bytes, allowing either B/b for bytes, K/k for KB,
|
||||
* M/m for MB, G/g for GB or T/t for TB. End pointer will be returned
|
||||
* in *end, if not NULL. Return -ERANGE on overflow, Return -EINVAL on
|
||||
* other error.
|
||||
*/
|
||||
int64_t strtosz_suffix_unit(const char *nptr, char **end,
|
||||
const char default_suffix, int64_t unit)
|
||||
{
|
||||
int64_t retval = -EINVAL;
|
||||
char *endptr;
|
||||
unsigned char c;
|
||||
int mul_required = 0;
|
||||
double val, mul, integral, fraction;
|
||||
|
||||
errno = 0;
|
||||
val = strtod(nptr, &endptr);
|
||||
if (isnan(val) || endptr == nptr || errno != 0) {
|
||||
goto fail;
|
||||
}
|
||||
fraction = modf(val, &integral);
|
||||
if (fraction != 0) {
|
||||
mul_required = 1;
|
||||
}
|
||||
c = *endptr;
|
||||
mul = suffix_mul(c, unit);
|
||||
if (mul >= 0) {
|
||||
endptr++;
|
||||
} else {
|
||||
mul = suffix_mul(default_suffix, unit);
|
||||
assert(mul >= 0);
|
||||
}
|
||||
if (mul == 1 && mul_required) {
|
||||
goto fail;
|
||||
}
|
||||
if ((val * mul >= INT64_MAX) || val < 0) {
|
||||
retval = -ERANGE;
|
||||
goto fail;
|
||||
}
|
||||
retval = val * mul;
|
||||
|
||||
fail:
|
||||
if (end) {
|
||||
*end = endptr;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int64_t strtosz_suffix(const char *nptr, char **end, const char default_suffix)
|
||||
{
|
||||
return strtosz_suffix_unit(nptr, end, default_suffix, 1024);
|
||||
}
|
||||
|
||||
int64_t strtosz(const char *nptr, char **end)
|
||||
{
|
||||
return strtosz_suffix(nptr, end, STRTOSZ_DEFSUFFIX_MB);
|
||||
}
|
||||
|
||||
int qemu_parse_fd(const char *param)
|
||||
{
|
||||
int fd;
|
||||
char *endptr = NULL;
|
||||
|
||||
fd = strtol(param, &endptr, 10);
|
||||
if (*endptr || (fd == 0 && param == endptr)) {
|
||||
return -1;
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* round down to the nearest power of 2*/
|
||||
int64_t pow2floor(int64_t value)
|
||||
{
|
||||
if (!is_power_of_2(value)) {
|
||||
value = 0x8000000000000000ULL >> clz64(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implementation of ULEB128 (http://en.wikipedia.org/wiki/LEB128)
|
||||
* Input is limited to 14-bit numbers
|
||||
*/
|
||||
int uleb128_encode_small(uint8_t *out, uint32_t n)
|
||||
{
|
||||
g_assert(n <= 0x3fff);
|
||||
if (n < 0x80) {
|
||||
*out++ = n;
|
||||
return 1;
|
||||
} else {
|
||||
*out++ = (n & 0x7f) | 0x80;
|
||||
*out++ = n >> 7;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
int uleb128_decode_small(const uint8_t *in, uint32_t *n)
|
||||
{
|
||||
if (!(*in & 0x80)) {
|
||||
*n = *in++;
|
||||
return 1;
|
||||
} else {
|
||||
*n = *in++ & 0x7f;
|
||||
/* we exceed 14 bit number */
|
||||
if (*in & 0x80) {
|
||||
return -1;
|
||||
}
|
||||
*n |= *in++ << 7;
|
||||
return 2;
|
||||
}
|
||||
}
|
246
util/envlist.c
Normal file
246
util/envlist.c
Normal file
|
@ -0,0 +1,246 @@
|
|||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/envlist.h"
|
||||
|
||||
struct envlist_entry {
|
||||
const char *ev_var; /* actual env value */
|
||||
QLIST_ENTRY(envlist_entry) ev_link;
|
||||
};
|
||||
|
||||
struct envlist {
|
||||
QLIST_HEAD(, envlist_entry) el_entries; /* actual entries */
|
||||
size_t el_count; /* number of entries */
|
||||
};
|
||||
|
||||
static int envlist_parse(envlist_t *envlist,
|
||||
const char *env, int (*)(envlist_t *, const char *));
|
||||
|
||||
/*
|
||||
* Allocates new envlist and returns pointer to that or
|
||||
* NULL in case of error.
|
||||
*/
|
||||
envlist_t *
|
||||
envlist_create(void)
|
||||
{
|
||||
envlist_t *envlist;
|
||||
|
||||
if ((envlist = malloc(sizeof (*envlist))) == NULL)
|
||||
return (NULL);
|
||||
|
||||
QLIST_INIT(&envlist->el_entries);
|
||||
envlist->el_count = 0;
|
||||
|
||||
return (envlist);
|
||||
}
|
||||
|
||||
/*
|
||||
* Releases given envlist and its entries.
|
||||
*/
|
||||
void
|
||||
envlist_free(envlist_t *envlist)
|
||||
{
|
||||
struct envlist_entry *entry;
|
||||
|
||||
assert(envlist != NULL);
|
||||
|
||||
while (envlist->el_entries.lh_first != NULL) {
|
||||
entry = envlist->el_entries.lh_first;
|
||||
QLIST_REMOVE(entry, ev_link);
|
||||
|
||||
free((char *)entry->ev_var);
|
||||
free(entry);
|
||||
}
|
||||
free(envlist);
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses comma separated list of set/modify environment
|
||||
* variable entries and updates given enlist accordingly.
|
||||
*
|
||||
* For example:
|
||||
* envlist_parse(el, "HOME=foo,SHELL=/bin/sh");
|
||||
*
|
||||
* inserts/sets environment variables HOME and SHELL.
|
||||
*
|
||||
* Returns 0 on success, errno otherwise.
|
||||
*/
|
||||
int
|
||||
envlist_parse_set(envlist_t *envlist, const char *env)
|
||||
{
|
||||
return (envlist_parse(envlist, env, &envlist_setenv));
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses comma separated list of unset environment variable
|
||||
* entries and removes given variables from given envlist.
|
||||
*
|
||||
* Returns 0 on success, errno otherwise.
|
||||
*/
|
||||
int
|
||||
envlist_parse_unset(envlist_t *envlist, const char *env)
|
||||
{
|
||||
return (envlist_parse(envlist, env, &envlist_unsetenv));
|
||||
}
|
||||
|
||||
/*
|
||||
* Parses comma separated list of set, modify or unset entries
|
||||
* and calls given callback for each entry.
|
||||
*
|
||||
* Returns 0 in case of success, errno otherwise.
|
||||
*/
|
||||
static int
|
||||
envlist_parse(envlist_t *envlist, const char *env,
|
||||
int (*callback)(envlist_t *, const char *))
|
||||
{
|
||||
char *tmpenv, *envvar;
|
||||
char *envsave = NULL;
|
||||
|
||||
assert(callback != NULL);
|
||||
|
||||
if ((envlist == NULL) || (env == NULL))
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* We need to make temporary copy of the env string
|
||||
* as strtok_r(3) modifies it while it tokenizes.
|
||||
*/
|
||||
if ((tmpenv = strdup(env)) == NULL)
|
||||
return (errno);
|
||||
|
||||
envvar = strtok_r(tmpenv, ",", &envsave);
|
||||
while (envvar != NULL) {
|
||||
if ((*callback)(envlist, envvar) != 0) {
|
||||
free(tmpenv);
|
||||
return (errno);
|
||||
}
|
||||
envvar = strtok_r(NULL, ",", &envsave);
|
||||
}
|
||||
|
||||
free(tmpenv);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Sets environment value to envlist in similar manner
|
||||
* than putenv(3).
|
||||
*
|
||||
* Returns 0 in success, errno otherwise.
|
||||
*/
|
||||
int
|
||||
envlist_setenv(envlist_t *envlist, const char *env)
|
||||
{
|
||||
struct envlist_entry *entry = NULL;
|
||||
const char *eq_sign;
|
||||
size_t envname_len;
|
||||
|
||||
if ((envlist == NULL) || (env == NULL))
|
||||
return (EINVAL);
|
||||
|
||||
/* find out first equals sign in given env */
|
||||
if ((eq_sign = strchr(env, '=')) == NULL)
|
||||
return (EINVAL);
|
||||
envname_len = eq_sign - env + 1;
|
||||
|
||||
/*
|
||||
* If there already exists variable with given name
|
||||
* we remove and release it before allocating a whole
|
||||
* new entry.
|
||||
*/
|
||||
for (entry = envlist->el_entries.lh_first; entry != NULL;
|
||||
entry = entry->ev_link.le_next) {
|
||||
if (strncmp(entry->ev_var, env, envname_len) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
if (entry != NULL) {
|
||||
QLIST_REMOVE(entry, ev_link);
|
||||
free((char *)entry->ev_var);
|
||||
free(entry);
|
||||
} else {
|
||||
envlist->el_count++;
|
||||
}
|
||||
|
||||
if ((entry = malloc(sizeof (*entry))) == NULL)
|
||||
return (errno);
|
||||
if ((entry->ev_var = strdup(env)) == NULL) {
|
||||
free(entry);
|
||||
return (errno);
|
||||
}
|
||||
QLIST_INSERT_HEAD(&envlist->el_entries, entry, ev_link);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes given env value from envlist in similar manner
|
||||
* than unsetenv(3). Returns 0 in success, errno otherwise.
|
||||
*/
|
||||
int
|
||||
envlist_unsetenv(envlist_t *envlist, const char *env)
|
||||
{
|
||||
struct envlist_entry *entry;
|
||||
size_t envname_len;
|
||||
|
||||
if ((envlist == NULL) || (env == NULL))
|
||||
return (EINVAL);
|
||||
|
||||
/* env is not allowed to contain '=' */
|
||||
if (strchr(env, '=') != NULL)
|
||||
return (EINVAL);
|
||||
|
||||
/*
|
||||
* Find out the requested entry and remove
|
||||
* it from the list.
|
||||
*/
|
||||
envname_len = strlen(env);
|
||||
for (entry = envlist->el_entries.lh_first; entry != NULL;
|
||||
entry = entry->ev_link.le_next) {
|
||||
if (strncmp(entry->ev_var, env, envname_len) == 0)
|
||||
break;
|
||||
}
|
||||
if (entry != NULL) {
|
||||
QLIST_REMOVE(entry, ev_link);
|
||||
free((char *)entry->ev_var);
|
||||
free(entry);
|
||||
|
||||
envlist->el_count--;
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns given envlist as array of strings (in same form that
|
||||
* global variable environ is). Caller must free returned memory
|
||||
* by calling free(3) for each element and for the array. Returned
|
||||
* array and given envlist are not related (no common references).
|
||||
*
|
||||
* If caller provides count pointer, number of items in array is
|
||||
* stored there. In case of error, NULL is returned and no memory
|
||||
* is allocated.
|
||||
*/
|
||||
char **
|
||||
envlist_to_environ(const envlist_t *envlist, size_t *count)
|
||||
{
|
||||
struct envlist_entry *entry;
|
||||
char **env, **penv;
|
||||
|
||||
penv = env = malloc((envlist->el_count + 1) * sizeof (char *));
|
||||
if (env == NULL)
|
||||
return (NULL);
|
||||
|
||||
for (entry = envlist->el_entries.lh_first; entry != NULL;
|
||||
entry = entry->ev_link.le_next) {
|
||||
*(penv++) = strdup(entry->ev_var);
|
||||
}
|
||||
*penv = NULL; /* NULL terminate the list */
|
||||
|
||||
if (count != NULL)
|
||||
*count = envlist->el_count;
|
||||
|
||||
return (env);
|
||||
}
|
115
util/error.c
Normal file
115
util/error.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* QEMU Error Objects
|
||||
*
|
||||
* Copyright IBM, Corp. 2011
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU LGPL, version 2. See
|
||||
* the COPYING.LIB file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qapi/qmp/qjson.h"
|
||||
#include "qapi/qmp/qdict.h"
|
||||
#include "qapi-types.h"
|
||||
#include "qapi/qmp/qerror.h"
|
||||
|
||||
struct Error
|
||||
{
|
||||
char *msg;
|
||||
ErrorClass err_class;
|
||||
};
|
||||
|
||||
void error_set(Error **errp, ErrorClass err_class, const char *fmt, ...)
|
||||
{
|
||||
Error *err;
|
||||
va_list ap;
|
||||
|
||||
if (errp == NULL) {
|
||||
return;
|
||||
}
|
||||
assert(*errp == NULL);
|
||||
|
||||
err = g_malloc0(sizeof(*err));
|
||||
|
||||
va_start(ap, fmt);
|
||||
err->msg = g_strdup_vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
err->err_class = err_class;
|
||||
|
||||
*errp = err;
|
||||
}
|
||||
|
||||
void error_set_errno(Error **errp, int os_errno, ErrorClass err_class,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
Error *err;
|
||||
char *msg1;
|
||||
va_list ap;
|
||||
|
||||
if (errp == NULL) {
|
||||
return;
|
||||
}
|
||||
assert(*errp == NULL);
|
||||
|
||||
err = g_malloc0(sizeof(*err));
|
||||
|
||||
va_start(ap, fmt);
|
||||
msg1 = g_strdup_vprintf(fmt, ap);
|
||||
if (os_errno != 0) {
|
||||
err->msg = g_strdup_printf("%s: %s", msg1, strerror(os_errno));
|
||||
g_free(msg1);
|
||||
} else {
|
||||
err->msg = msg1;
|
||||
}
|
||||
va_end(ap);
|
||||
err->err_class = err_class;
|
||||
|
||||
*errp = err;
|
||||
}
|
||||
|
||||
Error *error_copy(const Error *err)
|
||||
{
|
||||
Error *err_new;
|
||||
|
||||
err_new = g_malloc0(sizeof(*err));
|
||||
err_new->msg = g_strdup(err->msg);
|
||||
err_new->err_class = err->err_class;
|
||||
|
||||
return err_new;
|
||||
}
|
||||
|
||||
bool error_is_set(Error **errp)
|
||||
{
|
||||
return (errp && *errp);
|
||||
}
|
||||
|
||||
ErrorClass error_get_class(const Error *err)
|
||||
{
|
||||
return err->err_class;
|
||||
}
|
||||
|
||||
const char *error_get_pretty(Error *err)
|
||||
{
|
||||
return err->msg;
|
||||
}
|
||||
|
||||
void error_free(Error *err)
|
||||
{
|
||||
if (err) {
|
||||
g_free(err->msg);
|
||||
g_free(err);
|
||||
}
|
||||
}
|
||||
|
||||
void error_propagate(Error **dst_err, Error *local_err)
|
||||
{
|
||||
if (dst_err && !*dst_err) {
|
||||
*dst_err = local_err;
|
||||
} else if (local_err) {
|
||||
error_free(local_err);
|
||||
}
|
||||
}
|
121
util/event_notifier-posix.c
Normal file
121
util/event_notifier-posix.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* event notifier support
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Michael S. Tsirkin <mst@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/event_notifier.h"
|
||||
#include "char/char.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
#ifdef CONFIG_EVENTFD
|
||||
#include <sys/eventfd.h>
|
||||
#endif
|
||||
|
||||
void event_notifier_init_fd(EventNotifier *e, int fd)
|
||||
{
|
||||
e->rfd = fd;
|
||||
e->wfd = fd;
|
||||
}
|
||||
|
||||
int event_notifier_init(EventNotifier *e, int active)
|
||||
{
|
||||
int fds[2];
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_EVENTFD
|
||||
ret = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
|
||||
#else
|
||||
ret = -1;
|
||||
errno = ENOSYS;
|
||||
#endif
|
||||
if (ret >= 0) {
|
||||
e->rfd = e->wfd = ret;
|
||||
} else {
|
||||
if (errno != ENOSYS) {
|
||||
return -errno;
|
||||
}
|
||||
if (qemu_pipe(fds) < 0) {
|
||||
return -errno;
|
||||
}
|
||||
ret = fcntl_setfl(fds[0], O_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto fail;
|
||||
}
|
||||
ret = fcntl_setfl(fds[1], O_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
ret = -errno;
|
||||
goto fail;
|
||||
}
|
||||
e->rfd = fds[0];
|
||||
e->wfd = fds[1];
|
||||
}
|
||||
if (active) {
|
||||
event_notifier_set(e);
|
||||
}
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void event_notifier_cleanup(EventNotifier *e)
|
||||
{
|
||||
if (e->rfd != e->wfd) {
|
||||
close(e->rfd);
|
||||
}
|
||||
close(e->wfd);
|
||||
}
|
||||
|
||||
int event_notifier_get_fd(EventNotifier *e)
|
||||
{
|
||||
return e->rfd;
|
||||
}
|
||||
|
||||
int event_notifier_set_handler(EventNotifier *e,
|
||||
EventNotifierHandler *handler)
|
||||
{
|
||||
return qemu_set_fd_handler(e->rfd, (IOHandler *)handler, NULL, e);
|
||||
}
|
||||
|
||||
int event_notifier_set(EventNotifier *e)
|
||||
{
|
||||
static const uint64_t value = 1;
|
||||
ssize_t ret;
|
||||
|
||||
do {
|
||||
ret = write(e->wfd, &value, sizeof(value));
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
|
||||
/* EAGAIN is fine, a read must be pending. */
|
||||
if (ret < 0 && errno != EAGAIN) {
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_notifier_test_and_clear(EventNotifier *e)
|
||||
{
|
||||
int value;
|
||||
ssize_t len;
|
||||
char buffer[512];
|
||||
|
||||
/* Drain the notify pipe. For eventfd, only 8 bytes will be read. */
|
||||
value = 0;
|
||||
do {
|
||||
len = read(e->rfd, buffer, sizeof(buffer));
|
||||
value |= (len > 0);
|
||||
} while ((len == -1 && errno == EINTR) || len == sizeof(buffer));
|
||||
|
||||
return value;
|
||||
}
|
59
util/event_notifier-win32.c
Normal file
59
util/event_notifier-win32.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* event notifier support
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Michael S. Tsirkin <mst@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/event_notifier.h"
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
int event_notifier_init(EventNotifier *e, int active)
|
||||
{
|
||||
e->event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
assert(e->event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void event_notifier_cleanup(EventNotifier *e)
|
||||
{
|
||||
CloseHandle(e->event);
|
||||
}
|
||||
|
||||
HANDLE event_notifier_get_handle(EventNotifier *e)
|
||||
{
|
||||
return e->event;
|
||||
}
|
||||
|
||||
int event_notifier_set_handler(EventNotifier *e,
|
||||
EventNotifierHandler *handler)
|
||||
{
|
||||
if (handler) {
|
||||
return qemu_add_wait_object(e->event, (IOHandler *)handler, e);
|
||||
} else {
|
||||
qemu_del_wait_object(e->event, (IOHandler *)handler, e);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int event_notifier_set(EventNotifier *e)
|
||||
{
|
||||
SetEvent(e->event);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_notifier_test_and_clear(EventNotifier *e)
|
||||
{
|
||||
int ret = WaitForSingleObject(e->event, 0);
|
||||
if (ret == WAIT_OBJECT_0) {
|
||||
ResetEvent(e->event);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
105
util/host-utils.c
Normal file
105
util/host-utils.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
* Utility compute operations used by translated code.
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
* Copyright (c) 2007 Aurelien Jarno
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "qemu/host-utils.h"
|
||||
|
||||
//#define DEBUG_MULDIV
|
||||
|
||||
/* Long integer helpers */
|
||||
#if !defined(__x86_64__)
|
||||
static void add128 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
|
||||
{
|
||||
*plow += a;
|
||||
/* carry test */
|
||||
if (*plow < a)
|
||||
(*phigh)++;
|
||||
*phigh += b;
|
||||
}
|
||||
|
||||
static void neg128 (uint64_t *plow, uint64_t *phigh)
|
||||
{
|
||||
*plow = ~*plow;
|
||||
*phigh = ~*phigh;
|
||||
add128(plow, phigh, 1, 0);
|
||||
}
|
||||
|
||||
static void mul64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
|
||||
{
|
||||
uint32_t a0, a1, b0, b1;
|
||||
uint64_t v;
|
||||
|
||||
a0 = a;
|
||||
a1 = a >> 32;
|
||||
|
||||
b0 = b;
|
||||
b1 = b >> 32;
|
||||
|
||||
v = (uint64_t)a0 * (uint64_t)b0;
|
||||
*plow = v;
|
||||
*phigh = 0;
|
||||
|
||||
v = (uint64_t)a0 * (uint64_t)b1;
|
||||
add128(plow, phigh, v << 32, v >> 32);
|
||||
|
||||
v = (uint64_t)a1 * (uint64_t)b0;
|
||||
add128(plow, phigh, v << 32, v >> 32);
|
||||
|
||||
v = (uint64_t)a1 * (uint64_t)b1;
|
||||
*phigh += v;
|
||||
}
|
||||
|
||||
/* Unsigned 64x64 -> 128 multiplication */
|
||||
void mulu64 (uint64_t *plow, uint64_t *phigh, uint64_t a, uint64_t b)
|
||||
{
|
||||
mul64(plow, phigh, a, b);
|
||||
#if defined(DEBUG_MULDIV)
|
||||
printf("mulu64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
|
||||
a, b, *phigh, *plow);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Signed 64x64 -> 128 multiplication */
|
||||
void muls64 (uint64_t *plow, uint64_t *phigh, int64_t a, int64_t b)
|
||||
{
|
||||
int sa, sb;
|
||||
|
||||
sa = (a < 0);
|
||||
if (sa)
|
||||
a = -a;
|
||||
sb = (b < 0);
|
||||
if (sb)
|
||||
b = -b;
|
||||
mul64(plow, phigh, a, b);
|
||||
if (sa ^ sb) {
|
||||
neg128(plow, phigh);
|
||||
}
|
||||
#if defined(DEBUG_MULDIV)
|
||||
printf("muls64: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
|
||||
a, b, *phigh, *plow);
|
||||
#endif
|
||||
}
|
||||
#endif /* !defined(__x86_64__) */
|
422
util/iov.c
Normal file
422
util/iov.c
Normal file
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
* Helpers for getting linearized buffers from iov / filling buffers into iovs
|
||||
*
|
||||
* Copyright IBM, Corp. 2007, 2008
|
||||
* Copyright (C) 2010 Red Hat, Inc.
|
||||
*
|
||||
* Author(s):
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
* Amit Shah <amit.shah@redhat.com>
|
||||
* Michael Tokarev <mjt@tls.msk.ru>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu/iov.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
# include <windows.h>
|
||||
# include <winsock2.h>
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# include <sys/socket.h>
|
||||
#endif
|
||||
|
||||
size_t iov_from_buf(const struct iovec *iov, unsigned int iov_cnt,
|
||||
size_t offset, const void *buf, size_t bytes)
|
||||
{
|
||||
size_t done;
|
||||
unsigned int i;
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
|
||||
if (offset < iov[i].iov_len) {
|
||||
size_t len = MIN(iov[i].iov_len - offset, bytes - done);
|
||||
memcpy(iov[i].iov_base + offset, buf + done, len);
|
||||
done += len;
|
||||
offset = 0;
|
||||
} else {
|
||||
offset -= iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
assert(offset == 0);
|
||||
return done;
|
||||
}
|
||||
|
||||
size_t iov_to_buf(const struct iovec *iov, const unsigned int iov_cnt,
|
||||
size_t offset, void *buf, size_t bytes)
|
||||
{
|
||||
size_t done;
|
||||
unsigned int i;
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
|
||||
if (offset < iov[i].iov_len) {
|
||||
size_t len = MIN(iov[i].iov_len - offset, bytes - done);
|
||||
memcpy(buf + done, iov[i].iov_base + offset, len);
|
||||
done += len;
|
||||
offset = 0;
|
||||
} else {
|
||||
offset -= iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
assert(offset == 0);
|
||||
return done;
|
||||
}
|
||||
|
||||
size_t iov_memset(const struct iovec *iov, const unsigned int iov_cnt,
|
||||
size_t offset, int fillc, size_t bytes)
|
||||
{
|
||||
size_t done;
|
||||
unsigned int i;
|
||||
for (i = 0, done = 0; (offset || done < bytes) && i < iov_cnt; i++) {
|
||||
if (offset < iov[i].iov_len) {
|
||||
size_t len = MIN(iov[i].iov_len - offset, bytes - done);
|
||||
memset(iov[i].iov_base + offset, fillc, len);
|
||||
done += len;
|
||||
offset = 0;
|
||||
} else {
|
||||
offset -= iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
assert(offset == 0);
|
||||
return done;
|
||||
}
|
||||
|
||||
size_t iov_size(const struct iovec *iov, const unsigned int iov_cnt)
|
||||
{
|
||||
size_t len;
|
||||
unsigned int i;
|
||||
|
||||
len = 0;
|
||||
for (i = 0; i < iov_cnt; i++) {
|
||||
len += iov[i].iov_len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
/* helper function for iov_send_recv() */
|
||||
static ssize_t
|
||||
do_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt, bool do_send)
|
||||
{
|
||||
#if defined CONFIG_IOVEC && defined CONFIG_POSIX
|
||||
ssize_t ret;
|
||||
struct msghdr msg;
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = iov_cnt;
|
||||
do {
|
||||
ret = do_send
|
||||
? sendmsg(sockfd, &msg, 0)
|
||||
: recvmsg(sockfd, &msg, 0);
|
||||
} while (ret < 0 && errno == EINTR);
|
||||
return ret;
|
||||
#else
|
||||
/* else send piece-by-piece */
|
||||
/*XXX Note: windows has WSASend() and WSARecv() */
|
||||
unsigned i = 0;
|
||||
ssize_t ret = 0;
|
||||
while (i < iov_cnt) {
|
||||
ssize_t r = do_send
|
||||
? send(sockfd, iov[i].iov_base, iov[i].iov_len, 0)
|
||||
: recv(sockfd, iov[i].iov_base, iov[i].iov_len, 0);
|
||||
if (r > 0) {
|
||||
ret += r;
|
||||
} else if (!r) {
|
||||
break;
|
||||
} else if (errno == EINTR) {
|
||||
continue;
|
||||
} else {
|
||||
/* else it is some "other" error,
|
||||
* only return if there was no data processed. */
|
||||
if (ret == 0) {
|
||||
ret = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
ssize_t iov_send_recv(int sockfd, struct iovec *iov, unsigned iov_cnt,
|
||||
size_t offset, size_t bytes,
|
||||
bool do_send)
|
||||
{
|
||||
ssize_t ret;
|
||||
unsigned si, ei; /* start and end indexes */
|
||||
if (bytes == 0) {
|
||||
/* Catch the do-nothing case early, as otherwise we will pass an
|
||||
* empty iovec to sendmsg/recvmsg(), and not all implementations
|
||||
* accept this.
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find the start position, skipping `offset' bytes:
|
||||
* first, skip all full-sized vector elements, */
|
||||
for (si = 0; si < iov_cnt && offset >= iov[si].iov_len; ++si) {
|
||||
offset -= iov[si].iov_len;
|
||||
}
|
||||
if (offset) {
|
||||
assert(si < iov_cnt);
|
||||
/* second, skip `offset' bytes from the (now) first element,
|
||||
* undo it on exit */
|
||||
iov[si].iov_base += offset;
|
||||
iov[si].iov_len -= offset;
|
||||
}
|
||||
/* Find the end position skipping `bytes' bytes: */
|
||||
/* first, skip all full-sized elements */
|
||||
for (ei = si; ei < iov_cnt && iov[ei].iov_len <= bytes; ++ei) {
|
||||
bytes -= iov[ei].iov_len;
|
||||
}
|
||||
if (bytes) {
|
||||
/* second, fixup the last element, and remember
|
||||
* the length we've cut from the end of it in `bytes' */
|
||||
size_t tail;
|
||||
assert(ei < iov_cnt);
|
||||
assert(iov[ei].iov_len > bytes);
|
||||
tail = iov[ei].iov_len - bytes;
|
||||
iov[ei].iov_len = bytes;
|
||||
bytes = tail; /* bytes is now equal to the tail size */
|
||||
++ei;
|
||||
}
|
||||
|
||||
ret = do_send_recv(sockfd, iov + si, ei - si, do_send);
|
||||
|
||||
/* Undo the changes above */
|
||||
if (offset) {
|
||||
iov[si].iov_base -= offset;
|
||||
iov[si].iov_len += offset;
|
||||
}
|
||||
if (bytes) {
|
||||
iov[ei-1].iov_len += bytes;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void iov_hexdump(const struct iovec *iov, const unsigned int iov_cnt,
|
||||
FILE *fp, const char *prefix, size_t limit)
|
||||
{
|
||||
unsigned int i, v, b;
|
||||
uint8_t *c;
|
||||
|
||||
c = iov[0].iov_base;
|
||||
for (i = 0, v = 0, b = 0; b < limit; i++, b++) {
|
||||
if (i == iov[v].iov_len) {
|
||||
i = 0; v++;
|
||||
if (v == iov_cnt) {
|
||||
break;
|
||||
}
|
||||
c = iov[v].iov_base;
|
||||
}
|
||||
if ((b % 16) == 0) {
|
||||
fprintf(fp, "%s: %04x:", prefix, b);
|
||||
}
|
||||
if ((b % 4) == 0) {
|
||||
fprintf(fp, " ");
|
||||
}
|
||||
fprintf(fp, " %02x", c[i]);
|
||||
if ((b % 16) == 15) {
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
if ((b % 16) != 0) {
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
unsigned iov_copy(struct iovec *dst_iov, unsigned int dst_iov_cnt,
|
||||
const struct iovec *iov, unsigned int iov_cnt,
|
||||
size_t offset, size_t bytes)
|
||||
{
|
||||
size_t len;
|
||||
unsigned int i, j;
|
||||
for (i = 0, j = 0; i < iov_cnt && j < dst_iov_cnt && bytes; i++) {
|
||||
if (offset >= iov[i].iov_len) {
|
||||
offset -= iov[i].iov_len;
|
||||
continue;
|
||||
}
|
||||
len = MIN(bytes, iov[i].iov_len - offset);
|
||||
|
||||
dst_iov[j].iov_base = iov[i].iov_base + offset;
|
||||
dst_iov[j].iov_len = len;
|
||||
j++;
|
||||
bytes -= len;
|
||||
offset = 0;
|
||||
}
|
||||
assert(offset == 0);
|
||||
return j;
|
||||
}
|
||||
|
||||
/* io vectors */
|
||||
|
||||
void qemu_iovec_init(QEMUIOVector *qiov, int alloc_hint)
|
||||
{
|
||||
qiov->iov = g_malloc(alloc_hint * sizeof(struct iovec));
|
||||
qiov->niov = 0;
|
||||
qiov->nalloc = alloc_hint;
|
||||
qiov->size = 0;
|
||||
}
|
||||
|
||||
void qemu_iovec_init_external(QEMUIOVector *qiov, struct iovec *iov, int niov)
|
||||
{
|
||||
int i;
|
||||
|
||||
qiov->iov = iov;
|
||||
qiov->niov = niov;
|
||||
qiov->nalloc = -1;
|
||||
qiov->size = 0;
|
||||
for (i = 0; i < niov; i++)
|
||||
qiov->size += iov[i].iov_len;
|
||||
}
|
||||
|
||||
void qemu_iovec_add(QEMUIOVector *qiov, void *base, size_t len)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
||||
if (qiov->niov == qiov->nalloc) {
|
||||
qiov->nalloc = 2 * qiov->nalloc + 1;
|
||||
qiov->iov = g_realloc(qiov->iov, qiov->nalloc * sizeof(struct iovec));
|
||||
}
|
||||
qiov->iov[qiov->niov].iov_base = base;
|
||||
qiov->iov[qiov->niov].iov_len = len;
|
||||
qiov->size += len;
|
||||
++qiov->niov;
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenates (partial) iovecs from src_iov to the end of dst.
|
||||
* It starts copying after skipping `soffset' bytes at the
|
||||
* beginning of src and adds individual vectors from src to
|
||||
* dst copies up to `sbytes' bytes total, or up to the end
|
||||
* of src_iov if it comes first. This way, it is okay to specify
|
||||
* very large value for `sbytes' to indicate "up to the end
|
||||
* of src".
|
||||
* Only vector pointers are processed, not the actual data buffers.
|
||||
*/
|
||||
void qemu_iovec_concat_iov(QEMUIOVector *dst,
|
||||
struct iovec *src_iov, unsigned int src_cnt,
|
||||
size_t soffset, size_t sbytes)
|
||||
{
|
||||
int i;
|
||||
size_t done;
|
||||
assert(dst->nalloc != -1);
|
||||
for (i = 0, done = 0; done < sbytes && i < src_cnt; i++) {
|
||||
if (soffset < src_iov[i].iov_len) {
|
||||
size_t len = MIN(src_iov[i].iov_len - soffset, sbytes - done);
|
||||
qemu_iovec_add(dst, src_iov[i].iov_base + soffset, len);
|
||||
done += len;
|
||||
soffset = 0;
|
||||
} else {
|
||||
soffset -= src_iov[i].iov_len;
|
||||
}
|
||||
}
|
||||
assert(soffset == 0); /* offset beyond end of src */
|
||||
}
|
||||
|
||||
/*
|
||||
* Concatenates (partial) iovecs from src to the end of dst.
|
||||
* It starts copying after skipping `soffset' bytes at the
|
||||
* beginning of src and adds individual vectors from src to
|
||||
* dst copies up to `sbytes' bytes total, or up to the end
|
||||
* of src if it comes first. This way, it is okay to specify
|
||||
* very large value for `sbytes' to indicate "up to the end
|
||||
* of src".
|
||||
* Only vector pointers are processed, not the actual data buffers.
|
||||
*/
|
||||
void qemu_iovec_concat(QEMUIOVector *dst,
|
||||
QEMUIOVector *src, size_t soffset, size_t sbytes)
|
||||
{
|
||||
qemu_iovec_concat_iov(dst, src->iov, src->niov, soffset, sbytes);
|
||||
}
|
||||
|
||||
void qemu_iovec_destroy(QEMUIOVector *qiov)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
||||
qemu_iovec_reset(qiov);
|
||||
g_free(qiov->iov);
|
||||
qiov->nalloc = 0;
|
||||
qiov->iov = NULL;
|
||||
}
|
||||
|
||||
void qemu_iovec_reset(QEMUIOVector *qiov)
|
||||
{
|
||||
assert(qiov->nalloc != -1);
|
||||
|
||||
qiov->niov = 0;
|
||||
qiov->size = 0;
|
||||
}
|
||||
|
||||
size_t qemu_iovec_to_buf(QEMUIOVector *qiov, size_t offset,
|
||||
void *buf, size_t bytes)
|
||||
{
|
||||
return iov_to_buf(qiov->iov, qiov->niov, offset, buf, bytes);
|
||||
}
|
||||
|
||||
size_t qemu_iovec_from_buf(QEMUIOVector *qiov, size_t offset,
|
||||
const void *buf, size_t bytes)
|
||||
{
|
||||
return iov_from_buf(qiov->iov, qiov->niov, offset, buf, bytes);
|
||||
}
|
||||
|
||||
size_t qemu_iovec_memset(QEMUIOVector *qiov, size_t offset,
|
||||
int fillc, size_t bytes)
|
||||
{
|
||||
return iov_memset(qiov->iov, qiov->niov, offset, fillc, bytes);
|
||||
}
|
||||
|
||||
size_t iov_discard_front(struct iovec **iov, unsigned int *iov_cnt,
|
||||
size_t bytes)
|
||||
{
|
||||
size_t total = 0;
|
||||
struct iovec *cur;
|
||||
|
||||
for (cur = *iov; *iov_cnt > 0; cur++) {
|
||||
if (cur->iov_len > bytes) {
|
||||
cur->iov_base += bytes;
|
||||
cur->iov_len -= bytes;
|
||||
total += bytes;
|
||||
break;
|
||||
}
|
||||
|
||||
bytes -= cur->iov_len;
|
||||
total += cur->iov_len;
|
||||
*iov_cnt -= 1;
|
||||
}
|
||||
|
||||
*iov = cur;
|
||||
return total;
|
||||
}
|
||||
|
||||
size_t iov_discard_back(struct iovec *iov, unsigned int *iov_cnt,
|
||||
size_t bytes)
|
||||
{
|
||||
size_t total = 0;
|
||||
struct iovec *cur;
|
||||
|
||||
if (*iov_cnt == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
cur = iov + (*iov_cnt - 1);
|
||||
|
||||
while (*iov_cnt > 0) {
|
||||
if (cur->iov_len > bytes) {
|
||||
cur->iov_len -= bytes;
|
||||
total += bytes;
|
||||
break;
|
||||
}
|
||||
|
||||
bytes -= cur->iov_len;
|
||||
total += cur->iov_len;
|
||||
cur--;
|
||||
*iov_cnt -= 1;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
81
util/module.c
Normal file
81
util/module.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* QEMU Module Infrastructure
|
||||
*
|
||||
* Copyright IBM, Corp. 2009
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/queue.h"
|
||||
#include "qemu/module.h"
|
||||
|
||||
typedef struct ModuleEntry
|
||||
{
|
||||
void (*init)(void);
|
||||
QTAILQ_ENTRY(ModuleEntry) node;
|
||||
} ModuleEntry;
|
||||
|
||||
typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
|
||||
|
||||
static ModuleTypeList init_type_list[MODULE_INIT_MAX];
|
||||
|
||||
static void init_types(void)
|
||||
{
|
||||
static int inited;
|
||||
int i;
|
||||
|
||||
if (inited) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < MODULE_INIT_MAX; i++) {
|
||||
QTAILQ_INIT(&init_type_list[i]);
|
||||
}
|
||||
|
||||
inited = 1;
|
||||
}
|
||||
|
||||
|
||||
static ModuleTypeList *find_type(module_init_type type)
|
||||
{
|
||||
ModuleTypeList *l;
|
||||
|
||||
init_types();
|
||||
|
||||
l = &init_type_list[type];
|
||||
|
||||
return l;
|
||||
}
|
||||
|
||||
void register_module_init(void (*fn)(void), module_init_type type)
|
||||
{
|
||||
ModuleEntry *e;
|
||||
ModuleTypeList *l;
|
||||
|
||||
e = g_malloc0(sizeof(*e));
|
||||
e->init = fn;
|
||||
|
||||
l = find_type(type);
|
||||
|
||||
QTAILQ_INSERT_TAIL(l, e, node);
|
||||
}
|
||||
|
||||
void module_call_init(module_init_type type)
|
||||
{
|
||||
ModuleTypeList *l;
|
||||
ModuleEntry *e;
|
||||
|
||||
l = find_type(type);
|
||||
|
||||
QTAILQ_FOREACH(e, l, node) {
|
||||
e->init();
|
||||
}
|
||||
}
|
41
util/notify.c
Normal file
41
util/notify.c
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Notifier lists
|
||||
*
|
||||
* Copyright IBM, Corp. 2010
|
||||
*
|
||||
* Authors:
|
||||
* Anthony Liguori <aliguori@us.ibm.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2. See
|
||||
* the COPYING file in the top-level directory.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/notify.h"
|
||||
|
||||
void notifier_list_init(NotifierList *list)
|
||||
{
|
||||
QLIST_INIT(&list->notifiers);
|
||||
}
|
||||
|
||||
void notifier_list_add(NotifierList *list, Notifier *notifier)
|
||||
{
|
||||
QLIST_INSERT_HEAD(&list->notifiers, notifier, node);
|
||||
}
|
||||
|
||||
void notifier_remove(Notifier *notifier)
|
||||
{
|
||||
QLIST_REMOVE(notifier, node);
|
||||
}
|
||||
|
||||
void notifier_list_notify(NotifierList *list, void *data)
|
||||
{
|
||||
Notifier *notifier, *next;
|
||||
|
||||
QLIST_FOREACH_SAFE(notifier, &list->notifiers, node, next) {
|
||||
notifier->notify(notifier, data);
|
||||
}
|
||||
}
|
402
util/osdep.c
Normal file
402
util/osdep.c
Normal file
|
@ -0,0 +1,402 @@
|
|||
/*
|
||||
* QEMU low level functions
|
||||
*
|
||||
* Copyright (c) 2003 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
/* Needed early for CONFIG_BSD etc. */
|
||||
#include "config-host.h"
|
||||
|
||||
#if defined(CONFIG_MADVISE) || defined(CONFIG_POSIX_MADVISE)
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SOLARIS
|
||||
#include <sys/types.h>
|
||||
#include <sys/statvfs.h>
|
||||
/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for
|
||||
discussion about Solaris header problems */
|
||||
extern int madvise(caddr_t, size_t, int);
|
||||
#endif
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "monitor/monitor.h"
|
||||
|
||||
static bool fips_enabled = false;
|
||||
|
||||
static const char *qemu_version = QEMU_VERSION;
|
||||
|
||||
int socket_set_cork(int fd, int v)
|
||||
{
|
||||
#if defined(SOL_TCP) && defined(TCP_CORK)
|
||||
return setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v));
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int qemu_madvise(void *addr, size_t len, int advice)
|
||||
{
|
||||
if (advice == QEMU_MADV_INVALID) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#if defined(CONFIG_MADVISE)
|
||||
return madvise(addr, len, advice);
|
||||
#elif defined(CONFIG_POSIX_MADVISE)
|
||||
return posix_madvise(addr, len, advice);
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
/*
|
||||
* Dups an fd and sets the flags
|
||||
*/
|
||||
static int qemu_dup_flags(int fd, int flags)
|
||||
{
|
||||
int ret;
|
||||
int serrno;
|
||||
int dup_flags;
|
||||
|
||||
#ifdef F_DUPFD_CLOEXEC
|
||||
ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
|
||||
#else
|
||||
ret = dup(fd);
|
||||
if (ret != -1) {
|
||||
qemu_set_cloexec(ret);
|
||||
}
|
||||
#endif
|
||||
if (ret == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dup_flags = fcntl(ret, F_GETFL);
|
||||
if (dup_flags == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((flags & O_SYNC) != (dup_flags & O_SYNC)) {
|
||||
errno = EINVAL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Set/unset flags that we can with fcntl */
|
||||
if (fcntl(ret, F_SETFL, flags) == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Truncate the file in the cases that open() would truncate it */
|
||||
if (flags & O_TRUNC ||
|
||||
((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
|
||||
if (ftruncate(ret, 0) == -1) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
fail:
|
||||
serrno = errno;
|
||||
if (ret != -1) {
|
||||
close(ret);
|
||||
}
|
||||
errno = serrno;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int qemu_parse_fdset(const char *param)
|
||||
{
|
||||
return qemu_parse_fd(param);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Opens a file with FD_CLOEXEC set
|
||||
*/
|
||||
int qemu_open(const char *name, int flags, ...)
|
||||
{
|
||||
int ret;
|
||||
int mode = 0;
|
||||
|
||||
#ifndef _WIN32
|
||||
const char *fdset_id_str;
|
||||
|
||||
/* Attempt dup of fd from fd set */
|
||||
if (strstart(name, "/dev/fdset/", &fdset_id_str)) {
|
||||
int64_t fdset_id;
|
||||
int fd, dupfd;
|
||||
|
||||
fdset_id = qemu_parse_fdset(fdset_id_str);
|
||||
if (fdset_id == -1) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = monitor_fdset_get_fd(fdset_id, flags);
|
||||
if (fd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
dupfd = qemu_dup_flags(fd, flags);
|
||||
if (dupfd == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = monitor_fdset_dup_fd_add(fdset_id, dupfd);
|
||||
if (ret == -1) {
|
||||
close(dupfd);
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return dupfd;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (flags & O_CREAT) {
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, flags);
|
||||
mode = va_arg(ap, int);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
ret = open(name, flags | O_CLOEXEC, mode);
|
||||
#else
|
||||
ret = open(name, flags, mode);
|
||||
if (ret >= 0) {
|
||||
qemu_set_cloexec(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qemu_close(int fd)
|
||||
{
|
||||
int64_t fdset_id;
|
||||
|
||||
/* Close fd that was dup'd from an fdset */
|
||||
fdset_id = monitor_fdset_dup_fd_find(fd);
|
||||
if (fdset_id != -1) {
|
||||
int ret;
|
||||
|
||||
ret = close(fd);
|
||||
if (ret == 0) {
|
||||
monitor_fdset_dup_fd_remove(fd);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
/*
|
||||
* A variant of write(2) which handles partial write.
|
||||
*
|
||||
* Return the number of bytes transferred.
|
||||
* Set errno if fewer than `count' bytes are written.
|
||||
*
|
||||
* This function don't work with non-blocking fd's.
|
||||
* Any of the possibilities with non-bloking fd's is bad:
|
||||
* - return a short write (then name is wrong)
|
||||
* - busy wait adding (errno == EAGAIN) to the loop
|
||||
*/
|
||||
ssize_t qemu_write_full(int fd, const void *buf, size_t count)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
ssize_t total = 0;
|
||||
|
||||
while (count) {
|
||||
ret = write(fd, buf, count);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
|
||||
count -= ret;
|
||||
buf += ret;
|
||||
total += ret;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/*
|
||||
* Opens a socket with FD_CLOEXEC set
|
||||
*/
|
||||
int qemu_socket(int domain, int type, int protocol)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef SOCK_CLOEXEC
|
||||
ret = socket(domain, type | SOCK_CLOEXEC, protocol);
|
||||
if (ret != -1 || errno != EINVAL) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
ret = socket(domain, type, protocol);
|
||||
if (ret >= 0) {
|
||||
qemu_set_cloexec(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* Accept a connection and set FD_CLOEXEC
|
||||
*/
|
||||
int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_ACCEPT4
|
||||
ret = accept4(s, addr, addrlen, SOCK_CLOEXEC);
|
||||
if (ret != -1 || errno != ENOSYS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
ret = accept(s, addr, addrlen);
|
||||
if (ret >= 0) {
|
||||
qemu_set_cloexec(ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* A variant of send(2) which handles partial write.
|
||||
*
|
||||
* Return the number of bytes transferred, which is only
|
||||
* smaller than `count' if there is an error.
|
||||
*
|
||||
* This function won't work with non-blocking fd's.
|
||||
* Any of the possibilities with non-bloking fd's is bad:
|
||||
* - return a short write (then name is wrong)
|
||||
* - busy wait adding (errno == EAGAIN) to the loop
|
||||
*/
|
||||
ssize_t qemu_send_full(int fd, const void *buf, size_t count, int flags)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
ssize_t total = 0;
|
||||
|
||||
while (count) {
|
||||
ret = send(fd, buf, count, flags);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
count -= ret;
|
||||
buf += ret;
|
||||
total += ret;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/*
|
||||
* A variant of recv(2) which handles partial write.
|
||||
*
|
||||
* Return the number of bytes transferred, which is only
|
||||
* smaller than `count' if there is an error.
|
||||
*
|
||||
* This function won't work with non-blocking fd's.
|
||||
* Any of the possibilities with non-bloking fd's is bad:
|
||||
* - return a short write (then name is wrong)
|
||||
* - busy wait adding (errno == EAGAIN) to the loop
|
||||
*/
|
||||
ssize_t qemu_recv_full(int fd, void *buf, size_t count, int flags)
|
||||
{
|
||||
ssize_t ret = 0;
|
||||
ssize_t total = 0;
|
||||
|
||||
while (count) {
|
||||
ret = qemu_recv(fd, buf, count, flags);
|
||||
if (ret <= 0) {
|
||||
if (ret < 0 && errno == EINTR) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
count -= ret;
|
||||
buf += ret;
|
||||
total += ret;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
void qemu_set_version(const char *version)
|
||||
{
|
||||
qemu_version = version;
|
||||
}
|
||||
|
||||
const char *qemu_get_version(void)
|
||||
{
|
||||
return qemu_version;
|
||||
}
|
||||
|
||||
void fips_set_state(bool requested)
|
||||
{
|
||||
#ifdef __linux__
|
||||
if (requested) {
|
||||
FILE *fds = fopen("/proc/sys/crypto/fips_enabled", "r");
|
||||
if (fds != NULL) {
|
||||
fips_enabled = (fgetc(fds) == '1');
|
||||
fclose(fds);
|
||||
}
|
||||
}
|
||||
#else
|
||||
fips_enabled = false;
|
||||
#endif /* __linux__ */
|
||||
|
||||
#ifdef _FIPS_DEBUG
|
||||
fprintf(stderr, "FIPS mode %s (requested %s)\n",
|
||||
(fips_enabled ? "enabled" : "disabled"),
|
||||
(requested ? "enabled" : "disabled"));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool fips_get_state(void)
|
||||
{
|
||||
return fips_enabled;
|
||||
}
|
||||
|
228
util/oslib-posix.c
Normal file
228
util/oslib-posix.c
Normal file
|
@ -0,0 +1,228 @@
|
|||
/*
|
||||
* os-posix-lib.c
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2010 Red Hat, Inc.
|
||||
*
|
||||
* QEMU library functions on POSIX which are shared between QEMU and
|
||||
* the QEMU tools.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/* The following block of code temporarily renames the daemon() function so the
|
||||
compiler does not see the warning associated with it in stdlib.h on OSX */
|
||||
#ifdef __APPLE__
|
||||
#define daemon qemu_fake_daemon_function
|
||||
#include <stdlib.h>
|
||||
#undef daemon
|
||||
extern int daemon(int, int);
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(__x86_64__)
|
||||
/* Use 2 MiB alignment so transparent hugepages can be used by KVM.
|
||||
Valgrind does not support alignments larger than 1 MiB,
|
||||
therefore we need special code which handles running on Valgrind. */
|
||||
# define QEMU_VMALLOC_ALIGN (512 * 4096)
|
||||
# define CONFIG_VALGRIND
|
||||
#elif defined(__linux__) && defined(__s390x__)
|
||||
/* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
|
||||
# define QEMU_VMALLOC_ALIGN (256 * 4096)
|
||||
#else
|
||||
# define QEMU_VMALLOC_ALIGN getpagesize()
|
||||
#endif
|
||||
|
||||
#include "config-host.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/sockets.h"
|
||||
|
||||
#if defined(CONFIG_VALGRIND)
|
||||
static int running_on_valgrind = -1;
|
||||
#else
|
||||
# define running_on_valgrind 0
|
||||
#endif
|
||||
#ifdef CONFIG_LINUX
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
int qemu_get_thread_id(void)
|
||||
{
|
||||
#if defined(__linux__)
|
||||
return syscall(SYS_gettid);
|
||||
#else
|
||||
return getpid();
|
||||
#endif
|
||||
}
|
||||
|
||||
int qemu_daemon(int nochdir, int noclose)
|
||||
{
|
||||
return daemon(nochdir, noclose);
|
||||
}
|
||||
|
||||
void *qemu_oom_check(void *ptr)
|
||||
{
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
|
||||
abort();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *qemu_memalign(size_t alignment, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
|
||||
int ret;
|
||||
ret = posix_memalign(&ptr, alignment, size);
|
||||
if (ret != 0) {
|
||||
fprintf(stderr, "Failed to allocate %zu B: %s\n",
|
||||
size, strerror(ret));
|
||||
abort();
|
||||
}
|
||||
#elif defined(CONFIG_BSD)
|
||||
ptr = qemu_oom_check(valloc(size));
|
||||
#else
|
||||
ptr = qemu_oom_check(memalign(alignment, size));
|
||||
#endif
|
||||
trace_qemu_memalign(alignment, size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/* conflicts with qemu_vmalloc in bsd-user/mmap.c */
|
||||
#if !defined(CONFIG_BSD_USER)
|
||||
/* alloc shared memory pages */
|
||||
void *qemu_vmalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
size_t align = QEMU_VMALLOC_ALIGN;
|
||||
|
||||
#if defined(CONFIG_VALGRIND)
|
||||
if (running_on_valgrind < 0) {
|
||||
/* First call, test whether we are running on Valgrind.
|
||||
This is a substitute for RUNNING_ON_VALGRIND from valgrind.h. */
|
||||
const char *ld = getenv("LD_PRELOAD");
|
||||
running_on_valgrind = (ld != NULL && strstr(ld, "vgpreload"));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (size < align || running_on_valgrind) {
|
||||
align = getpagesize();
|
||||
}
|
||||
ptr = qemu_memalign(align, size);
|
||||
trace_qemu_vmalloc(size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
void qemu_vfree(void *ptr)
|
||||
{
|
||||
trace_qemu_vfree(ptr);
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
void socket_set_block(int fd)
|
||||
{
|
||||
int f;
|
||||
f = fcntl(fd, F_GETFL);
|
||||
fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
|
||||
}
|
||||
|
||||
void socket_set_nonblock(int fd)
|
||||
{
|
||||
int f;
|
||||
f = fcntl(fd, F_GETFL);
|
||||
fcntl(fd, F_SETFL, f | O_NONBLOCK);
|
||||
}
|
||||
|
||||
void qemu_set_cloexec(int fd)
|
||||
{
|
||||
int f;
|
||||
f = fcntl(fd, F_GETFD);
|
||||
fcntl(fd, F_SETFD, f | FD_CLOEXEC);
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a pipe with FD_CLOEXEC set on both file descriptors
|
||||
*/
|
||||
int qemu_pipe(int pipefd[2])
|
||||
{
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_PIPE2
|
||||
ret = pipe2(pipefd, O_CLOEXEC);
|
||||
if (ret != -1 || errno != ENOSYS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
ret = pipe(pipefd);
|
||||
if (ret == 0) {
|
||||
qemu_set_cloexec(pipefd[0]);
|
||||
qemu_set_cloexec(pipefd[1]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int qemu_utimens(const char *path, const struct timespec *times)
|
||||
{
|
||||
struct timeval tv[2], tv_now;
|
||||
struct stat st;
|
||||
int i;
|
||||
#ifdef CONFIG_UTIMENSAT
|
||||
int ret;
|
||||
|
||||
ret = utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
|
||||
if (ret != -1 || errno != ENOSYS) {
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
/* Fallback: use utimes() instead of utimensat() */
|
||||
|
||||
/* happy if special cases */
|
||||
if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) {
|
||||
return 0;
|
||||
}
|
||||
if (times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) {
|
||||
return utimes(path, NULL);
|
||||
}
|
||||
|
||||
/* prepare for hard cases */
|
||||
if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) {
|
||||
gettimeofday(&tv_now, NULL);
|
||||
}
|
||||
if (times[0].tv_nsec == UTIME_OMIT || times[1].tv_nsec == UTIME_OMIT) {
|
||||
stat(path, &st);
|
||||
}
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
if (times[i].tv_nsec == UTIME_NOW) {
|
||||
tv[i].tv_sec = tv_now.tv_sec;
|
||||
tv[i].tv_usec = tv_now.tv_usec;
|
||||
} else if (times[i].tv_nsec == UTIME_OMIT) {
|
||||
tv[i].tv_sec = (i == 0) ? st.st_atime : st.st_mtime;
|
||||
tv[i].tv_usec = 0;
|
||||
} else {
|
||||
tv[i].tv_sec = times[i].tv_sec;
|
||||
tv[i].tv_usec = times[i].tv_nsec / 1000;
|
||||
}
|
||||
}
|
||||
|
||||
return utimes(path, &tv[0]);
|
||||
}
|
152
util/oslib-win32.c
Normal file
152
util/oslib-win32.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* os-win32.c
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
* Copyright (c) 2010 Red Hat, Inc.
|
||||
*
|
||||
* QEMU library functions for win32 which are shared between QEMU and
|
||||
* the QEMU tools.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include <windows.h>
|
||||
#include "config-host.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include "qemu/main-loop.h"
|
||||
#include "trace.h"
|
||||
#include "qemu/sockets.h"
|
||||
|
||||
void *qemu_oom_check(void *ptr)
|
||||
{
|
||||
if (ptr == NULL) {
|
||||
fprintf(stderr, "Failed to allocate memory: %lu\n", GetLastError());
|
||||
abort();
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *qemu_memalign(size_t alignment, size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
if (!size) {
|
||||
abort();
|
||||
}
|
||||
ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
|
||||
trace_qemu_memalign(alignment, size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void *qemu_vmalloc(size_t size)
|
||||
{
|
||||
void *ptr;
|
||||
|
||||
/* FIXME: this is not exactly optimal solution since VirtualAlloc
|
||||
has 64Kb granularity, but at least it guarantees us that the
|
||||
memory is page aligned. */
|
||||
if (!size) {
|
||||
abort();
|
||||
}
|
||||
ptr = qemu_oom_check(VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE));
|
||||
trace_qemu_vmalloc(size, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void qemu_vfree(void *ptr)
|
||||
{
|
||||
trace_qemu_vfree(ptr);
|
||||
VirtualFree(ptr, 0, MEM_RELEASE);
|
||||
}
|
||||
|
||||
/* FIXME: add proper locking */
|
||||
struct tm *gmtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
struct tm *p = gmtime(timep);
|
||||
memset(result, 0, sizeof(*result));
|
||||
if (p) {
|
||||
*result = *p;
|
||||
p = result;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
/* FIXME: add proper locking */
|
||||
struct tm *localtime_r(const time_t *timep, struct tm *result)
|
||||
{
|
||||
struct tm *p = localtime(timep);
|
||||
memset(result, 0, sizeof(*result));
|
||||
if (p) {
|
||||
*result = *p;
|
||||
p = result;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void socket_set_block(int fd)
|
||||
{
|
||||
unsigned long opt = 0;
|
||||
WSAEventSelect(fd, NULL, 0);
|
||||
ioctlsocket(fd, FIONBIO, &opt);
|
||||
}
|
||||
|
||||
void socket_set_nonblock(int fd)
|
||||
{
|
||||
unsigned long opt = 1;
|
||||
ioctlsocket(fd, FIONBIO, &opt);
|
||||
qemu_fd_register(fd);
|
||||
}
|
||||
|
||||
int inet_aton(const char *cp, struct in_addr *ia)
|
||||
{
|
||||
uint32_t addr = inet_addr(cp);
|
||||
if (addr == 0xffffffff) {
|
||||
return 0;
|
||||
}
|
||||
ia->s_addr = addr;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void qemu_set_cloexec(int fd)
|
||||
{
|
||||
}
|
||||
|
||||
/* Offset between 1/1/1601 and 1/1/1970 in 100 nanosec units */
|
||||
#define _W32_FT_OFFSET (116444736000000000ULL)
|
||||
|
||||
int qemu_gettimeofday(qemu_timeval *tp)
|
||||
{
|
||||
union {
|
||||
unsigned long long ns100; /*time since 1 Jan 1601 in 100ns units */
|
||||
FILETIME ft;
|
||||
} _now;
|
||||
|
||||
if(tp) {
|
||||
GetSystemTimeAsFileTime (&_now.ft);
|
||||
tp->tv_usec=(long)((_now.ns100 / 10ULL) % 1000000ULL );
|
||||
tp->tv_sec= (long)((_now.ns100 - _W32_FT_OFFSET) / 10000000ULL);
|
||||
}
|
||||
/* Always return 0 as per Open Group Base Specifications Issue 6.
|
||||
Do not set errno on error. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qemu_get_thread_id(void)
|
||||
{
|
||||
return GetCurrentThreadId();
|
||||
}
|
182
util/path.c
Normal file
182
util/path.c
Normal file
|
@ -0,0 +1,182 @@
|
|||
/* Code to mangle pathnames into those matching a given prefix.
|
||||
eg. open("/lib/foo.so") => open("/usr/gnemul/i386-linux/lib/foo.so");
|
||||
|
||||
The assumption is that this area does not change.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "qemu-common.h"
|
||||
|
||||
struct pathelem
|
||||
{
|
||||
/* Name of this, eg. lib */
|
||||
char *name;
|
||||
/* Full path name, eg. /usr/gnemul/x86-linux/lib. */
|
||||
char *pathname;
|
||||
struct pathelem *parent;
|
||||
/* Children */
|
||||
unsigned int num_entries;
|
||||
struct pathelem *entries[0];
|
||||
};
|
||||
|
||||
static struct pathelem *base;
|
||||
|
||||
/* First N chars of S1 match S2, and S2 is N chars long. */
|
||||
static int strneq(const char *s1, unsigned int n, const char *s2)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
if (s1[i] != s2[i])
|
||||
return 0;
|
||||
return s2[i] == 0;
|
||||
}
|
||||
|
||||
static struct pathelem *add_entry(struct pathelem *root, const char *name,
|
||||
unsigned char type);
|
||||
|
||||
static struct pathelem *new_entry(const char *root,
|
||||
struct pathelem *parent,
|
||||
const char *name)
|
||||
{
|
||||
struct pathelem *new = malloc(sizeof(*new));
|
||||
new->name = strdup(name);
|
||||
if (asprintf(&new->pathname, "%s/%s", root, name) == -1) {
|
||||
printf("Cannot allocate memory\n");
|
||||
exit(1);
|
||||
}
|
||||
new->num_entries = 0;
|
||||
return new;
|
||||
}
|
||||
|
||||
#define streq(a,b) (strcmp((a), (b)) == 0)
|
||||
|
||||
/* Not all systems provide this feature */
|
||||
#if defined(DT_DIR) && defined(DT_UNKNOWN) && defined(DT_LNK)
|
||||
# define dirent_type(dirent) ((dirent)->d_type)
|
||||
# define is_dir_maybe(type) \
|
||||
((type) == DT_DIR || (type) == DT_UNKNOWN || (type) == DT_LNK)
|
||||
#else
|
||||
# define dirent_type(dirent) (1)
|
||||
# define is_dir_maybe(type) (type)
|
||||
#endif
|
||||
|
||||
static struct pathelem *add_dir_maybe(struct pathelem *path)
|
||||
{
|
||||
DIR *dir;
|
||||
|
||||
if ((dir = opendir(path->pathname)) != NULL) {
|
||||
struct dirent *dirent;
|
||||
|
||||
while ((dirent = readdir(dir)) != NULL) {
|
||||
if (!streq(dirent->d_name,".") && !streq(dirent->d_name,"..")){
|
||||
path = add_entry(path, dirent->d_name, dirent_type(dirent));
|
||||
}
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
static struct pathelem *add_entry(struct pathelem *root, const char *name,
|
||||
unsigned char type)
|
||||
{
|
||||
struct pathelem **e;
|
||||
|
||||
root->num_entries++;
|
||||
|
||||
root = realloc(root, sizeof(*root)
|
||||
+ sizeof(root->entries[0])*root->num_entries);
|
||||
e = &root->entries[root->num_entries-1];
|
||||
|
||||
*e = new_entry(root->pathname, root, name);
|
||||
if (is_dir_maybe(type)) {
|
||||
*e = add_dir_maybe(*e);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
/* This needs to be done after tree is stabilized (ie. no more reallocs!). */
|
||||
static void set_parents(struct pathelem *child, struct pathelem *parent)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
child->parent = parent;
|
||||
for (i = 0; i < child->num_entries; i++)
|
||||
set_parents(child->entries[i], child);
|
||||
}
|
||||
|
||||
/* FIXME: Doesn't handle DIR/.. where DIR is not in emulated dir. */
|
||||
static const char *
|
||||
follow_path(const struct pathelem *cursor, const char *name)
|
||||
{
|
||||
unsigned int i, namelen;
|
||||
|
||||
name += strspn(name, "/");
|
||||
namelen = strcspn(name, "/");
|
||||
|
||||
if (namelen == 0)
|
||||
return cursor->pathname;
|
||||
|
||||
if (strneq(name, namelen, ".."))
|
||||
return follow_path(cursor->parent, name + namelen);
|
||||
|
||||
if (strneq(name, namelen, "."))
|
||||
return follow_path(cursor, name + namelen);
|
||||
|
||||
for (i = 0; i < cursor->num_entries; i++)
|
||||
if (strneq(name, namelen, cursor->entries[i]->name))
|
||||
return follow_path(cursor->entries[i], name + namelen);
|
||||
|
||||
/* Not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void init_paths(const char *prefix)
|
||||
{
|
||||
char pref_buf[PATH_MAX];
|
||||
|
||||
if (prefix[0] == '\0' ||
|
||||
!strcmp(prefix, "/"))
|
||||
return;
|
||||
|
||||
if (prefix[0] != '/') {
|
||||
char *cwd = getcwd(NULL, 0);
|
||||
size_t pref_buf_len = sizeof(pref_buf);
|
||||
|
||||
if (!cwd)
|
||||
abort();
|
||||
pstrcpy(pref_buf, sizeof(pref_buf), cwd);
|
||||
pstrcat(pref_buf, pref_buf_len, "/");
|
||||
pstrcat(pref_buf, pref_buf_len, prefix);
|
||||
free(cwd);
|
||||
} else
|
||||
pstrcpy(pref_buf, sizeof(pref_buf), prefix + 1);
|
||||
|
||||
base = new_entry("", NULL, pref_buf);
|
||||
base = add_dir_maybe(base);
|
||||
if (base->num_entries == 0) {
|
||||
free (base);
|
||||
base = NULL;
|
||||
} else {
|
||||
set_parents(base, base);
|
||||
}
|
||||
}
|
||||
|
||||
/* Look for path in emulation dir, otherwise return name. */
|
||||
const char *path(const char *name)
|
||||
{
|
||||
/* Only do absolute paths: quick and dirty, but should mostly be OK.
|
||||
Could do relative by tracking cwd. */
|
||||
if (!base || !name || name[0] != '/')
|
||||
return name;
|
||||
|
||||
return follow_path(base, name) ?: name;
|
||||
}
|
215
util/qemu-config.c
Normal file
215
util/qemu-config.c
Normal file
|
@ -0,0 +1,215 @@
|
|||
#include "qemu-common.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qemu/option.h"
|
||||
#include "qemu/config-file.h"
|
||||
#include "hw/qdev.h"
|
||||
#include "qapi/error.h"
|
||||
|
||||
static QemuOptsList *vm_config_groups[32];
|
||||
|
||||
static QemuOptsList *find_list(QemuOptsList **lists, const char *group,
|
||||
Error **errp)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; lists[i] != NULL; i++) {
|
||||
if (strcmp(lists[i]->name, group) == 0)
|
||||
break;
|
||||
}
|
||||
if (lists[i] == NULL) {
|
||||
error_set(errp, QERR_INVALID_OPTION_GROUP, group);
|
||||
}
|
||||
return lists[i];
|
||||
}
|
||||
|
||||
QemuOptsList *qemu_find_opts(const char *group)
|
||||
{
|
||||
QemuOptsList *ret;
|
||||
Error *local_err = NULL;
|
||||
|
||||
ret = find_list(vm_config_groups, group, &local_err);
|
||||
if (error_is_set(&local_err)) {
|
||||
error_report("%s\n", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QemuOptsList *qemu_find_opts_err(const char *group, Error **errp)
|
||||
{
|
||||
return find_list(vm_config_groups, group, errp);
|
||||
}
|
||||
|
||||
void qemu_add_opts(QemuOptsList *list)
|
||||
{
|
||||
int entries, i;
|
||||
|
||||
entries = ARRAY_SIZE(vm_config_groups);
|
||||
entries--; /* keep list NULL terminated */
|
||||
for (i = 0; i < entries; i++) {
|
||||
if (vm_config_groups[i] == NULL) {
|
||||
vm_config_groups[i] = list;
|
||||
return;
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "ran out of space in vm_config_groups");
|
||||
abort();
|
||||
}
|
||||
|
||||
int qemu_set_option(const char *str)
|
||||
{
|
||||
char group[64], id[64], arg[64];
|
||||
QemuOptsList *list;
|
||||
QemuOpts *opts;
|
||||
int rc, offset;
|
||||
|
||||
rc = sscanf(str, "%63[^.].%63[^.].%63[^=]%n", group, id, arg, &offset);
|
||||
if (rc < 3 || str[offset] != '=') {
|
||||
error_report("can't parse: \"%s\"", str);
|
||||
return -1;
|
||||
}
|
||||
|
||||
list = qemu_find_opts(group);
|
||||
if (list == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
opts = qemu_opts_find(list, id);
|
||||
if (!opts) {
|
||||
error_report("there is no %s \"%s\" defined",
|
||||
list->name, id);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qemu_opt_set(opts, arg, str+offset+1) == -1) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ConfigWriteData {
|
||||
QemuOptsList *list;
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
static int config_write_opt(const char *name, const char *value, void *opaque)
|
||||
{
|
||||
struct ConfigWriteData *data = opaque;
|
||||
|
||||
fprintf(data->fp, " %s = \"%s\"\n", name, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int config_write_opts(QemuOpts *opts, void *opaque)
|
||||
{
|
||||
struct ConfigWriteData *data = opaque;
|
||||
const char *id = qemu_opts_id(opts);
|
||||
|
||||
if (id) {
|
||||
fprintf(data->fp, "[%s \"%s\"]\n", data->list->name, id);
|
||||
} else {
|
||||
fprintf(data->fp, "[%s]\n", data->list->name);
|
||||
}
|
||||
qemu_opt_foreach(opts, config_write_opt, data, 0);
|
||||
fprintf(data->fp, "\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void qemu_config_write(FILE *fp)
|
||||
{
|
||||
struct ConfigWriteData data = { .fp = fp };
|
||||
QemuOptsList **lists = vm_config_groups;
|
||||
int i;
|
||||
|
||||
fprintf(fp, "# qemu config file\n\n");
|
||||
for (i = 0; lists[i] != NULL; i++) {
|
||||
data.list = lists[i];
|
||||
qemu_opts_foreach(data.list, config_write_opts, &data, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int qemu_config_parse(FILE *fp, QemuOptsList **lists, const char *fname)
|
||||
{
|
||||
char line[1024], group[64], id[64], arg[64], value[1024];
|
||||
Location loc;
|
||||
QemuOptsList *list = NULL;
|
||||
Error *local_err = NULL;
|
||||
QemuOpts *opts = NULL;
|
||||
int res = -1, lno = 0;
|
||||
|
||||
loc_push_none(&loc);
|
||||
while (fgets(line, sizeof(line), fp) != NULL) {
|
||||
loc_set_file(fname, ++lno);
|
||||
if (line[0] == '\n') {
|
||||
/* skip empty lines */
|
||||
continue;
|
||||
}
|
||||
if (line[0] == '#') {
|
||||
/* comment */
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "[%63s \"%63[^\"]\"]", group, id) == 2) {
|
||||
/* group with id */
|
||||
list = find_list(lists, group, &local_err);
|
||||
if (error_is_set(&local_err)) {
|
||||
error_report("%s\n", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
}
|
||||
opts = qemu_opts_create(list, id, 1, NULL);
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, "[%63[^]]]", group) == 1) {
|
||||
/* group without id */
|
||||
list = find_list(lists, group, &local_err);
|
||||
if (error_is_set(&local_err)) {
|
||||
error_report("%s\n", error_get_pretty(local_err));
|
||||
error_free(local_err);
|
||||
goto out;
|
||||
}
|
||||
opts = qemu_opts_create_nofail(list);
|
||||
continue;
|
||||
}
|
||||
if (sscanf(line, " %63s = \"%1023[^\"]\"", arg, value) == 2) {
|
||||
/* arg = value */
|
||||
if (opts == NULL) {
|
||||
error_report("no group defined");
|
||||
goto out;
|
||||
}
|
||||
if (qemu_opt_set(opts, arg, value) != 0) {
|
||||
goto out;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
error_report("parse error");
|
||||
goto out;
|
||||
}
|
||||
if (ferror(fp)) {
|
||||
error_report("error reading file");
|
||||
goto out;
|
||||
}
|
||||
res = 0;
|
||||
out:
|
||||
loc_pop(&loc);
|
||||
return res;
|
||||
}
|
||||
|
||||
int qemu_read_config_file(const char *filename)
|
||||
{
|
||||
FILE *f = fopen(filename, "r");
|
||||
int ret;
|
||||
|
||||
if (f == NULL) {
|
||||
return -errno;
|
||||
}
|
||||
|
||||
ret = qemu_config_parse(f, vm_config_groups, filename);
|
||||
fclose(f);
|
||||
|
||||
if (ret == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
215
util/qemu-error.c
Normal file
215
util/qemu-error.c
Normal file
|
@ -0,0 +1,215 @@
|
|||
/*
|
||||
* Error reporting
|
||||
*
|
||||
* Copyright (C) 2010 Red Hat Inc.
|
||||
*
|
||||
* Authors:
|
||||
* Markus Armbruster <armbru@redhat.com>,
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "monitor/monitor.h"
|
||||
|
||||
/*
|
||||
* Print to current monitor if we have one, else to stderr.
|
||||
* TODO should return int, so callers can calculate width, but that
|
||||
* requires surgery to monitor_vprintf(). Left for another day.
|
||||
*/
|
||||
void error_vprintf(const char *fmt, va_list ap)
|
||||
{
|
||||
if (cur_mon) {
|
||||
monitor_vprintf(cur_mon, fmt, ap);
|
||||
} else {
|
||||
vfprintf(stderr, fmt, ap);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print to current monitor if we have one, else to stderr.
|
||||
* TODO just like error_vprintf()
|
||||
*/
|
||||
void error_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
error_vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void error_printf_unless_qmp(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
if (!monitor_cur_is_qmp()) {
|
||||
va_start(ap, fmt);
|
||||
error_vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
}
|
||||
|
||||
static Location std_loc = {
|
||||
.kind = LOC_NONE
|
||||
};
|
||||
static Location *cur_loc = &std_loc;
|
||||
|
||||
/*
|
||||
* Push location saved in LOC onto the location stack, return it.
|
||||
* The top of that stack is the current location.
|
||||
* Needs a matching loc_pop().
|
||||
*/
|
||||
Location *loc_push_restore(Location *loc)
|
||||
{
|
||||
assert(!loc->prev);
|
||||
loc->prev = cur_loc;
|
||||
cur_loc = loc;
|
||||
return loc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize *LOC to "nowhere", push it onto the location stack.
|
||||
* The top of that stack is the current location.
|
||||
* Needs a matching loc_pop().
|
||||
* Return LOC.
|
||||
*/
|
||||
Location *loc_push_none(Location *loc)
|
||||
{
|
||||
loc->kind = LOC_NONE;
|
||||
loc->prev = NULL;
|
||||
return loc_push_restore(loc);
|
||||
}
|
||||
|
||||
/*
|
||||
* Pop the location stack.
|
||||
* LOC must be the current location, i.e. the top of the stack.
|
||||
*/
|
||||
Location *loc_pop(Location *loc)
|
||||
{
|
||||
assert(cur_loc == loc && loc->prev);
|
||||
cur_loc = loc->prev;
|
||||
loc->prev = NULL;
|
||||
return loc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the current location in LOC, return LOC.
|
||||
*/
|
||||
Location *loc_save(Location *loc)
|
||||
{
|
||||
*loc = *cur_loc;
|
||||
loc->prev = NULL;
|
||||
return loc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the current location to the one saved in LOC.
|
||||
*/
|
||||
void loc_restore(Location *loc)
|
||||
{
|
||||
Location *prev = cur_loc->prev;
|
||||
assert(!loc->prev);
|
||||
*cur_loc = *loc;
|
||||
cur_loc->prev = prev;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the current location to "nowhere in particular".
|
||||
*/
|
||||
void loc_set_none(void)
|
||||
{
|
||||
cur_loc->kind = LOC_NONE;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the current location to argument ARGV[IDX..IDX+CNT-1].
|
||||
*/
|
||||
void loc_set_cmdline(char **argv, int idx, int cnt)
|
||||
{
|
||||
cur_loc->kind = LOC_CMDLINE;
|
||||
cur_loc->num = cnt;
|
||||
cur_loc->ptr = argv + idx;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the current location to file FNAME, line LNO.
|
||||
*/
|
||||
void loc_set_file(const char *fname, int lno)
|
||||
{
|
||||
assert (fname || cur_loc->kind == LOC_FILE);
|
||||
cur_loc->kind = LOC_FILE;
|
||||
cur_loc->num = lno;
|
||||
if (fname) {
|
||||
cur_loc->ptr = fname;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *progname;
|
||||
|
||||
/*
|
||||
* Set the program name for error_print_loc().
|
||||
*/
|
||||
void error_set_progname(const char *argv0)
|
||||
{
|
||||
const char *p = strrchr(argv0, '/');
|
||||
progname = p ? p + 1 : argv0;
|
||||
}
|
||||
|
||||
const char *error_get_progname(void)
|
||||
{
|
||||
return progname;
|
||||
}
|
||||
|
||||
/*
|
||||
* Print current location to current monitor if we have one, else to stderr.
|
||||
*/
|
||||
void error_print_loc(void)
|
||||
{
|
||||
const char *sep = "";
|
||||
int i;
|
||||
const char *const *argp;
|
||||
|
||||
if (!cur_mon && progname) {
|
||||
fprintf(stderr, "%s:", progname);
|
||||
sep = " ";
|
||||
}
|
||||
switch (cur_loc->kind) {
|
||||
case LOC_CMDLINE:
|
||||
argp = cur_loc->ptr;
|
||||
for (i = 0; i < cur_loc->num; i++) {
|
||||
error_printf("%s%s", sep, argp[i]);
|
||||
sep = " ";
|
||||
}
|
||||
error_printf(": ");
|
||||
break;
|
||||
case LOC_FILE:
|
||||
error_printf("%s:", (const char *)cur_loc->ptr);
|
||||
if (cur_loc->num) {
|
||||
error_printf("%d:", cur_loc->num);
|
||||
}
|
||||
error_printf(" ");
|
||||
break;
|
||||
default:
|
||||
error_printf("%s", sep);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Print an error message to current monitor if we have one, else to stderr.
|
||||
* Format arguments like sprintf(). The result should not contain
|
||||
* newlines.
|
||||
* Prepend the current location and append a newline.
|
||||
* It's wrong to call this in a QMP monitor. Use qerror_report() there.
|
||||
*/
|
||||
void error_report(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
error_print_loc();
|
||||
va_start(ap, fmt);
|
||||
error_vprintf(fmt, ap);
|
||||
va_end(ap);
|
||||
error_printf("\n");
|
||||
}
|
1134
util/qemu-option.c
Normal file
1134
util/qemu-option.c
Normal file
File diff suppressed because it is too large
Load diff
150
util/qemu-progress.c
Normal file
150
util/qemu-progress.c
Normal file
|
@ -0,0 +1,150 @@
|
|||
/*
|
||||
* QEMU progress printing utility functions
|
||||
*
|
||||
* Copyright (C) 2011 Jes Sorensen <Jes.Sorensen@redhat.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/osdep.h"
|
||||
#include "sysemu/sysemu.h"
|
||||
#include <stdio.h>
|
||||
|
||||
struct progress_state {
|
||||
float current;
|
||||
float last_print;
|
||||
float min_skip;
|
||||
void (*print)(void);
|
||||
void (*end)(void);
|
||||
};
|
||||
|
||||
static struct progress_state state;
|
||||
static volatile sig_atomic_t print_pending;
|
||||
|
||||
/*
|
||||
* Simple progress print function.
|
||||
* @percent relative percent of current operation
|
||||
* @max percent of total operation
|
||||
*/
|
||||
static void progress_simple_print(void)
|
||||
{
|
||||
printf(" (%3.2f/100%%)\r", state.current);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
static void progress_simple_end(void)
|
||||
{
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static void progress_simple_init(void)
|
||||
{
|
||||
state.print = progress_simple_print;
|
||||
state.end = progress_simple_end;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_POSIX
|
||||
static void sigusr_print(int signal)
|
||||
{
|
||||
print_pending = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void progress_dummy_print(void)
|
||||
{
|
||||
if (print_pending) {
|
||||
fprintf(stderr, " (%3.2f/100%%)\n", state.current);
|
||||
print_pending = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void progress_dummy_end(void)
|
||||
{
|
||||
}
|
||||
|
||||
static void progress_dummy_init(void)
|
||||
{
|
||||
#ifdef CONFIG_POSIX
|
||||
struct sigaction action;
|
||||
|
||||
memset(&action, 0, sizeof(action));
|
||||
sigfillset(&action.sa_mask);
|
||||
action.sa_handler = sigusr_print;
|
||||
action.sa_flags = 0;
|
||||
sigaction(SIGUSR1, &action, NULL);
|
||||
#endif
|
||||
|
||||
state.print = progress_dummy_print;
|
||||
state.end = progress_dummy_end;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize progress reporting.
|
||||
* If @enabled is false, actual reporting is suppressed. The user can
|
||||
* still trigger a report by sending a SIGUSR1.
|
||||
* Reports are also suppressed unless we've had at least @min_skip
|
||||
* percent progress since the last report.
|
||||
*/
|
||||
void qemu_progress_init(int enabled, float min_skip)
|
||||
{
|
||||
state.min_skip = min_skip;
|
||||
if (enabled) {
|
||||
progress_simple_init();
|
||||
} else {
|
||||
progress_dummy_init();
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_progress_end(void)
|
||||
{
|
||||
state.end();
|
||||
}
|
||||
|
||||
/*
|
||||
* Report progress.
|
||||
* @delta is how much progress we made.
|
||||
* If @max is zero, @delta is an absolut value of the total job done.
|
||||
* Else, @delta is a progress delta since the last call, as a fraction
|
||||
* of @max. I.e. the delta is @delta * @max / 100. This allows
|
||||
* relative accounting of functions which may be a different fraction of
|
||||
* the full job, depending on the context they are called in. I.e.
|
||||
* a function might be considered 40% of the full job if used from
|
||||
* bdrv_img_create() but only 20% if called from img_convert().
|
||||
*/
|
||||
void qemu_progress_print(float delta, int max)
|
||||
{
|
||||
float current;
|
||||
|
||||
if (max == 0) {
|
||||
current = delta;
|
||||
} else {
|
||||
current = state.current + delta / 100 * max;
|
||||
}
|
||||
if (current > 100) {
|
||||
current = 100;
|
||||
}
|
||||
state.current = current;
|
||||
|
||||
if (current > (state.last_print + state.min_skip) ||
|
||||
(current == 100) || (current == 0)) {
|
||||
state.last_print = state.current;
|
||||
state.print();
|
||||
}
|
||||
}
|
970
util/qemu-sockets.c
Normal file
970
util/qemu-sockets.c
Normal file
|
@ -0,0 +1,970 @@
|
|||
/*
|
||||
* inet and unix socket functions for qemu
|
||||
*
|
||||
* (c) 2008 Gerd Hoffmann <kraxel@redhat.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; under version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Contributions after 2012-01-13 are licensed under the terms of the
|
||||
* GNU GPL, version 2 or (at your option) any later version.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "monitor/monitor.h"
|
||||
#include "qemu/sockets.h"
|
||||
#include "qemu-common.h" /* for qemu_isdigit */
|
||||
#include "qemu/main-loop.h"
|
||||
|
||||
#ifndef AI_ADDRCONFIG
|
||||
# define AI_ADDRCONFIG 0
|
||||
#endif
|
||||
|
||||
static const int on=1, off=0;
|
||||
|
||||
/* used temporarely until all users are converted to QemuOpts */
|
||||
static QemuOptsList dummy_opts = {
|
||||
.name = "dummy",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(dummy_opts.head),
|
||||
.desc = {
|
||||
{
|
||||
.name = "path",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},{
|
||||
.name = "host",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},{
|
||||
.name = "port",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},{
|
||||
.name = "to",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},{
|
||||
.name = "ipv4",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},{
|
||||
.name = "ipv6",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{ /* end if list */ }
|
||||
},
|
||||
};
|
||||
|
||||
static int inet_getport(struct addrinfo *e)
|
||||
{
|
||||
struct sockaddr_in *i4;
|
||||
struct sockaddr_in6 *i6;
|
||||
|
||||
switch (e->ai_family) {
|
||||
case PF_INET6:
|
||||
i6 = (void*)e->ai_addr;
|
||||
return ntohs(i6->sin6_port);
|
||||
case PF_INET:
|
||||
i4 = (void*)e->ai_addr;
|
||||
return ntohs(i4->sin_port);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void inet_setport(struct addrinfo *e, int port)
|
||||
{
|
||||
struct sockaddr_in *i4;
|
||||
struct sockaddr_in6 *i6;
|
||||
|
||||
switch (e->ai_family) {
|
||||
case PF_INET6:
|
||||
i6 = (void*)e->ai_addr;
|
||||
i6->sin6_port = htons(port);
|
||||
break;
|
||||
case PF_INET:
|
||||
i4 = (void*)e->ai_addr;
|
||||
i4->sin_port = htons(port);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *inet_strfamily(int family)
|
||||
{
|
||||
switch (family) {
|
||||
case PF_INET6: return "ipv6";
|
||||
case PF_INET: return "ipv4";
|
||||
case PF_UNIX: return "unix";
|
||||
}
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
int inet_listen_opts(QemuOpts *opts, int port_offset, Error **errp)
|
||||
{
|
||||
struct addrinfo ai,*res,*e;
|
||||
const char *addr;
|
||||
char port[33];
|
||||
char uaddr[INET6_ADDRSTRLEN+1];
|
||||
char uport[33];
|
||||
int slisten, rc, to, port_min, port_max, p;
|
||||
|
||||
memset(&ai,0, sizeof(ai));
|
||||
ai.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
|
||||
ai.ai_family = PF_UNSPEC;
|
||||
ai.ai_socktype = SOCK_STREAM;
|
||||
|
||||
if ((qemu_opt_get(opts, "host") == NULL) ||
|
||||
(qemu_opt_get(opts, "port") == NULL)) {
|
||||
error_setg(errp, "host and/or port not specified");
|
||||
return -1;
|
||||
}
|
||||
pstrcpy(port, sizeof(port), qemu_opt_get(opts, "port"));
|
||||
addr = qemu_opt_get(opts, "host");
|
||||
|
||||
to = qemu_opt_get_number(opts, "to", 0);
|
||||
if (qemu_opt_get_bool(opts, "ipv4", 0))
|
||||
ai.ai_family = PF_INET;
|
||||
if (qemu_opt_get_bool(opts, "ipv6", 0))
|
||||
ai.ai_family = PF_INET6;
|
||||
|
||||
/* lookup */
|
||||
if (port_offset)
|
||||
snprintf(port, sizeof(port), "%d", atoi(port) + port_offset);
|
||||
rc = getaddrinfo(strlen(addr) ? addr : NULL, port, &ai, &res);
|
||||
if (rc != 0) {
|
||||
error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
|
||||
gai_strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* create socket + bind */
|
||||
for (e = res; e != NULL; e = e->ai_next) {
|
||||
getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen,
|
||||
uaddr,INET6_ADDRSTRLEN,uport,32,
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol);
|
||||
if (slisten < 0) {
|
||||
if (!e->ai_next) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
setsockopt(slisten,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
|
||||
#ifdef IPV6_V6ONLY
|
||||
if (e->ai_family == PF_INET6) {
|
||||
/* listen on both ipv4 and ipv6 */
|
||||
setsockopt(slisten,IPPROTO_IPV6,IPV6_V6ONLY,(void*)&off,
|
||||
sizeof(off));
|
||||
}
|
||||
#endif
|
||||
|
||||
port_min = inet_getport(e);
|
||||
port_max = to ? to + port_offset : port_min;
|
||||
for (p = port_min; p <= port_max; p++) {
|
||||
inet_setport(e, p);
|
||||
if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) {
|
||||
goto listen;
|
||||
}
|
||||
if (p == port_max) {
|
||||
if (!e->ai_next) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED);
|
||||
}
|
||||
}
|
||||
}
|
||||
closesocket(slisten);
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
return -1;
|
||||
|
||||
listen:
|
||||
if (listen(slisten,1) != 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED);
|
||||
closesocket(slisten);
|
||||
freeaddrinfo(res);
|
||||
return -1;
|
||||
}
|
||||
snprintf(uport, sizeof(uport), "%d", inet_getport(e) - port_offset);
|
||||
qemu_opt_set(opts, "host", uaddr);
|
||||
qemu_opt_set(opts, "port", uport);
|
||||
qemu_opt_set(opts, "ipv6", (e->ai_family == PF_INET6) ? "on" : "off");
|
||||
qemu_opt_set(opts, "ipv4", (e->ai_family != PF_INET6) ? "on" : "off");
|
||||
freeaddrinfo(res);
|
||||
return slisten;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#define QEMU_SOCKET_RC_INPROGRESS(rc) \
|
||||
((rc) == -EINPROGRESS || (rc) == -EWOULDBLOCK || (rc) == -WSAEALREADY)
|
||||
#else
|
||||
#define QEMU_SOCKET_RC_INPROGRESS(rc) \
|
||||
((rc) == -EINPROGRESS)
|
||||
#endif
|
||||
|
||||
/* Struct to store connect state for non blocking connect */
|
||||
typedef struct ConnectState {
|
||||
int fd;
|
||||
struct addrinfo *addr_list;
|
||||
struct addrinfo *current_addr;
|
||||
NonBlockingConnectHandler *callback;
|
||||
void *opaque;
|
||||
} ConnectState;
|
||||
|
||||
static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
|
||||
ConnectState *connect_state, Error **errp);
|
||||
|
||||
static void wait_for_connect(void *opaque)
|
||||
{
|
||||
ConnectState *s = opaque;
|
||||
int val = 0, rc = 0;
|
||||
socklen_t valsize = sizeof(val);
|
||||
bool in_progress;
|
||||
|
||||
qemu_set_fd_handler2(s->fd, NULL, NULL, NULL, NULL);
|
||||
|
||||
do {
|
||||
rc = getsockopt(s->fd, SOL_SOCKET, SO_ERROR, (void *) &val, &valsize);
|
||||
} while (rc == -1 && socket_error() == EINTR);
|
||||
|
||||
/* update rc to contain error */
|
||||
if (!rc && val) {
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
/* connect error */
|
||||
if (rc < 0) {
|
||||
closesocket(s->fd);
|
||||
s->fd = rc;
|
||||
}
|
||||
|
||||
/* try to connect to the next address on the list */
|
||||
if (s->current_addr) {
|
||||
while (s->current_addr->ai_next != NULL && s->fd < 0) {
|
||||
s->current_addr = s->current_addr->ai_next;
|
||||
s->fd = inet_connect_addr(s->current_addr, &in_progress, s, NULL);
|
||||
/* connect in progress */
|
||||
if (in_progress) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
freeaddrinfo(s->addr_list);
|
||||
}
|
||||
|
||||
if (s->callback) {
|
||||
s->callback(s->fd, s->opaque);
|
||||
}
|
||||
g_free(s);
|
||||
}
|
||||
|
||||
static int inet_connect_addr(struct addrinfo *addr, bool *in_progress,
|
||||
ConnectState *connect_state, Error **errp)
|
||||
{
|
||||
int sock, rc;
|
||||
|
||||
*in_progress = false;
|
||||
|
||||
sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (sock < 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
|
||||
return -1;
|
||||
}
|
||||
qemu_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
||||
if (connect_state != NULL) {
|
||||
socket_set_nonblock(sock);
|
||||
}
|
||||
/* connect to peer */
|
||||
do {
|
||||
rc = 0;
|
||||
if (connect(sock, addr->ai_addr, addr->ai_addrlen) < 0) {
|
||||
rc = -socket_error();
|
||||
}
|
||||
} while (rc == -EINTR);
|
||||
|
||||
if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) {
|
||||
connect_state->fd = sock;
|
||||
qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect,
|
||||
connect_state);
|
||||
*in_progress = true;
|
||||
} else if (rc < 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED);
|
||||
closesocket(sock);
|
||||
return -1;
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
static struct addrinfo *inet_parse_connect_opts(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
struct addrinfo ai, *res;
|
||||
int rc;
|
||||
const char *addr;
|
||||
const char *port;
|
||||
|
||||
memset(&ai, 0, sizeof(ai));
|
||||
|
||||
ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
|
||||
ai.ai_family = PF_UNSPEC;
|
||||
ai.ai_socktype = SOCK_STREAM;
|
||||
|
||||
addr = qemu_opt_get(opts, "host");
|
||||
port = qemu_opt_get(opts, "port");
|
||||
if (addr == NULL || port == NULL) {
|
||||
error_setg(errp, "host and/or port not specified");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (qemu_opt_get_bool(opts, "ipv4", 0)) {
|
||||
ai.ai_family = PF_INET;
|
||||
}
|
||||
if (qemu_opt_get_bool(opts, "ipv6", 0)) {
|
||||
ai.ai_family = PF_INET6;
|
||||
}
|
||||
|
||||
/* lookup */
|
||||
rc = getaddrinfo(addr, port, &ai, &res);
|
||||
if (rc != 0) {
|
||||
error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
|
||||
gai_strerror(rc));
|
||||
return NULL;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a socket and connect it to an address.
|
||||
*
|
||||
* @opts: QEMU options, recognized parameters strings "host" and "port",
|
||||
* bools "ipv4" and "ipv6".
|
||||
* @errp: set on error
|
||||
* @callback: callback function for non-blocking connect
|
||||
* @opaque: opaque for callback function
|
||||
*
|
||||
* Returns: -1 on error, file descriptor on success.
|
||||
*
|
||||
* If @callback is non-null, the connect is non-blocking. If this
|
||||
* function succeeds, callback will be called when the connection
|
||||
* completes, with the file descriptor on success, or -1 on error.
|
||||
*/
|
||||
int inet_connect_opts(QemuOpts *opts, Error **errp,
|
||||
NonBlockingConnectHandler *callback, void *opaque)
|
||||
{
|
||||
struct addrinfo *res, *e;
|
||||
int sock = -1;
|
||||
bool in_progress;
|
||||
ConnectState *connect_state = NULL;
|
||||
|
||||
res = inet_parse_connect_opts(opts, errp);
|
||||
if (!res) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (callback != NULL) {
|
||||
connect_state = g_malloc0(sizeof(*connect_state));
|
||||
connect_state->addr_list = res;
|
||||
connect_state->callback = callback;
|
||||
connect_state->opaque = opaque;
|
||||
}
|
||||
|
||||
for (e = res; e != NULL; e = e->ai_next) {
|
||||
if (connect_state != NULL) {
|
||||
connect_state->current_addr = e;
|
||||
}
|
||||
sock = inet_connect_addr(e, &in_progress, connect_state, errp);
|
||||
if (in_progress) {
|
||||
return sock;
|
||||
} else if (sock >= 0) {
|
||||
/* non blocking socket immediate success, call callback */
|
||||
if (callback != NULL) {
|
||||
callback(sock, opaque);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
g_free(connect_state);
|
||||
freeaddrinfo(res);
|
||||
return sock;
|
||||
}
|
||||
|
||||
int inet_dgram_opts(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
struct addrinfo ai, *peer = NULL, *local = NULL;
|
||||
const char *addr;
|
||||
const char *port;
|
||||
int sock = -1, rc;
|
||||
|
||||
/* lookup peer addr */
|
||||
memset(&ai,0, sizeof(ai));
|
||||
ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
|
||||
ai.ai_family = PF_UNSPEC;
|
||||
ai.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
addr = qemu_opt_get(opts, "host");
|
||||
port = qemu_opt_get(opts, "port");
|
||||
if (addr == NULL || strlen(addr) == 0) {
|
||||
addr = "localhost";
|
||||
}
|
||||
if (port == NULL || strlen(port) == 0) {
|
||||
error_setg(errp, "remote port not specified");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (qemu_opt_get_bool(opts, "ipv4", 0))
|
||||
ai.ai_family = PF_INET;
|
||||
if (qemu_opt_get_bool(opts, "ipv6", 0))
|
||||
ai.ai_family = PF_INET6;
|
||||
|
||||
if (0 != (rc = getaddrinfo(addr, port, &ai, &peer))) {
|
||||
error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
|
||||
gai_strerror(rc));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* lookup local addr */
|
||||
memset(&ai,0, sizeof(ai));
|
||||
ai.ai_flags = AI_PASSIVE;
|
||||
ai.ai_family = peer->ai_family;
|
||||
ai.ai_socktype = SOCK_DGRAM;
|
||||
|
||||
addr = qemu_opt_get(opts, "localaddr");
|
||||
port = qemu_opt_get(opts, "localport");
|
||||
if (addr == NULL || strlen(addr) == 0) {
|
||||
addr = NULL;
|
||||
}
|
||||
if (!port || strlen(port) == 0)
|
||||
port = "0";
|
||||
|
||||
if (0 != (rc = getaddrinfo(addr, port, &ai, &local))) {
|
||||
error_setg(errp, "address resolution failed for %s:%s: %s", addr, port,
|
||||
gai_strerror(rc));
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* create socket */
|
||||
sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol);
|
||||
if (sock < 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
|
||||
goto err;
|
||||
}
|
||||
setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(void*)&on,sizeof(on));
|
||||
|
||||
/* bind socket */
|
||||
if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* connect to peer */
|
||||
if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_CONNECT_FAILED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
freeaddrinfo(local);
|
||||
freeaddrinfo(peer);
|
||||
return sock;
|
||||
|
||||
err:
|
||||
if (-1 != sock)
|
||||
closesocket(sock);
|
||||
if (local)
|
||||
freeaddrinfo(local);
|
||||
if (peer)
|
||||
freeaddrinfo(peer);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* compatibility wrapper */
|
||||
static InetSocketAddress *inet_parse(const char *str, Error **errp)
|
||||
{
|
||||
InetSocketAddress *addr;
|
||||
const char *optstr, *h;
|
||||
char host[64];
|
||||
char port[33];
|
||||
int to;
|
||||
int pos;
|
||||
|
||||
addr = g_new0(InetSocketAddress, 1);
|
||||
|
||||
/* parse address */
|
||||
if (str[0] == ':') {
|
||||
/* no host given */
|
||||
host[0] = '\0';
|
||||
if (1 != sscanf(str, ":%32[^,]%n", port, &pos)) {
|
||||
error_setg(errp, "error parsing port in address '%s'", str);
|
||||
goto fail;
|
||||
}
|
||||
} else if (str[0] == '[') {
|
||||
/* IPv6 addr */
|
||||
if (2 != sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos)) {
|
||||
error_setg(errp, "error parsing IPv6 address '%s'", str);
|
||||
goto fail;
|
||||
}
|
||||
addr->ipv6 = addr->has_ipv6 = true;
|
||||
} else if (qemu_isdigit(str[0])) {
|
||||
/* IPv4 addr */
|
||||
if (2 != sscanf(str, "%64[0-9.]:%32[^,]%n", host, port, &pos)) {
|
||||
error_setg(errp, "error parsing IPv4 address '%s'", str);
|
||||
goto fail;
|
||||
}
|
||||
addr->ipv4 = addr->has_ipv4 = true;
|
||||
} else {
|
||||
/* hostname */
|
||||
if (2 != sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos)) {
|
||||
error_setg(errp, "error parsing address '%s'", str);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
addr->host = g_strdup(host);
|
||||
addr->port = g_strdup(port);
|
||||
|
||||
/* parse options */
|
||||
optstr = str + pos;
|
||||
h = strstr(optstr, ",to=");
|
||||
if (h) {
|
||||
h += 4;
|
||||
if (sscanf(h, "%d%n", &to, &pos) != 1 ||
|
||||
(h[pos] != '\0' && h[pos] != ',')) {
|
||||
error_setg(errp, "error parsing to= argument");
|
||||
goto fail;
|
||||
}
|
||||
addr->has_to = true;
|
||||
addr->to = to;
|
||||
}
|
||||
if (strstr(optstr, ",ipv4")) {
|
||||
addr->ipv4 = addr->has_ipv4 = true;
|
||||
}
|
||||
if (strstr(optstr, ",ipv6")) {
|
||||
addr->ipv6 = addr->has_ipv6 = true;
|
||||
}
|
||||
return addr;
|
||||
|
||||
fail:
|
||||
qapi_free_InetSocketAddress(addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void inet_addr_to_opts(QemuOpts *opts, InetSocketAddress *addr)
|
||||
{
|
||||
bool ipv4 = addr->ipv4 || !addr->has_ipv4;
|
||||
bool ipv6 = addr->ipv6 || !addr->has_ipv6;
|
||||
|
||||
if (!ipv4 || !ipv6) {
|
||||
qemu_opt_set_bool(opts, "ipv4", ipv4);
|
||||
qemu_opt_set_bool(opts, "ipv6", ipv6);
|
||||
}
|
||||
if (addr->has_to) {
|
||||
char to[20];
|
||||
snprintf(to, sizeof(to), "%d", addr->to);
|
||||
qemu_opt_set(opts, "to", to);
|
||||
}
|
||||
qemu_opt_set(opts, "host", addr->host);
|
||||
qemu_opt_set(opts, "port", addr->port);
|
||||
}
|
||||
|
||||
int inet_listen(const char *str, char *ostr, int olen,
|
||||
int socktype, int port_offset, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
char *optstr;
|
||||
int sock = -1;
|
||||
InetSocketAddress *addr;
|
||||
|
||||
addr = inet_parse(str, errp);
|
||||
if (addr != NULL) {
|
||||
opts = qemu_opts_create_nofail(&dummy_opts);
|
||||
inet_addr_to_opts(opts, addr);
|
||||
qapi_free_InetSocketAddress(addr);
|
||||
sock = inet_listen_opts(opts, port_offset, errp);
|
||||
if (sock != -1 && ostr) {
|
||||
optstr = strchr(str, ',');
|
||||
if (qemu_opt_get_bool(opts, "ipv6", 0)) {
|
||||
snprintf(ostr, olen, "[%s]:%s%s",
|
||||
qemu_opt_get(opts, "host"),
|
||||
qemu_opt_get(opts, "port"),
|
||||
optstr ? optstr : "");
|
||||
} else {
|
||||
snprintf(ostr, olen, "%s:%s%s",
|
||||
qemu_opt_get(opts, "host"),
|
||||
qemu_opt_get(opts, "port"),
|
||||
optstr ? optstr : "");
|
||||
}
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a blocking socket and connect it to an address.
|
||||
*
|
||||
* @str: address string
|
||||
* @errp: set in case of an error
|
||||
*
|
||||
* Returns -1 in case of error, file descriptor on success
|
||||
**/
|
||||
int inet_connect(const char *str, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
int sock = -1;
|
||||
InetSocketAddress *addr;
|
||||
|
||||
addr = inet_parse(str, errp);
|
||||
if (addr != NULL) {
|
||||
opts = qemu_opts_create_nofail(&dummy_opts);
|
||||
inet_addr_to_opts(opts, addr);
|
||||
qapi_free_InetSocketAddress(addr);
|
||||
sock = inet_connect_opts(opts, errp, NULL, NULL);
|
||||
qemu_opts_del(opts);
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a non-blocking socket and connect it to an address.
|
||||
* Calls the callback function with fd in case of success or -1 in case of
|
||||
* error.
|
||||
*
|
||||
* @str: address string
|
||||
* @callback: callback function that is called when connect completes,
|
||||
* cannot be NULL.
|
||||
* @opaque: opaque for callback function
|
||||
* @errp: set in case of an error
|
||||
*
|
||||
* Returns: -1 on immediate error, file descriptor on success.
|
||||
**/
|
||||
int inet_nonblocking_connect(const char *str,
|
||||
NonBlockingConnectHandler *callback,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
int sock = -1;
|
||||
InetSocketAddress *addr;
|
||||
|
||||
g_assert(callback != NULL);
|
||||
|
||||
addr = inet_parse(str, errp);
|
||||
if (addr != NULL) {
|
||||
opts = qemu_opts_create_nofail(&dummy_opts);
|
||||
inet_addr_to_opts(opts, addr);
|
||||
qapi_free_InetSocketAddress(addr);
|
||||
sock = inet_connect_opts(opts, errp, callback, opaque);
|
||||
qemu_opts_del(opts);
|
||||
}
|
||||
return sock;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
int unix_listen_opts(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
struct sockaddr_un un;
|
||||
const char *path = qemu_opt_get(opts, "path");
|
||||
int sock, fd;
|
||||
|
||||
sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&un, 0, sizeof(un));
|
||||
un.sun_family = AF_UNIX;
|
||||
if (path && strlen(path)) {
|
||||
snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
|
||||
} else {
|
||||
char *tmpdir = getenv("TMPDIR");
|
||||
snprintf(un.sun_path, sizeof(un.sun_path), "%s/qemu-socket-XXXXXX",
|
||||
tmpdir ? tmpdir : "/tmp");
|
||||
/*
|
||||
* This dummy fd usage silences the mktemp() unsecure warning.
|
||||
* Using mkstemp() doesn't make things more secure here
|
||||
* though. bind() complains about existing files, so we have
|
||||
* to unlink first and thus re-open the race window. The
|
||||
* worst case possible is bind() failing, i.e. a DoS attack.
|
||||
*/
|
||||
fd = mkstemp(un.sun_path); close(fd);
|
||||
qemu_opt_set(opts, "path", un.sun_path);
|
||||
}
|
||||
|
||||
unlink(un.sun_path);
|
||||
if (bind(sock, (struct sockaddr*) &un, sizeof(un)) < 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_BIND_FAILED);
|
||||
goto err;
|
||||
}
|
||||
if (listen(sock, 1) < 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_LISTEN_FAILED);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
||||
err:
|
||||
closesocket(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unix_connect_opts(QemuOpts *opts, Error **errp,
|
||||
NonBlockingConnectHandler *callback, void *opaque)
|
||||
{
|
||||
struct sockaddr_un un;
|
||||
const char *path = qemu_opt_get(opts, "path");
|
||||
ConnectState *connect_state = NULL;
|
||||
int sock, rc;
|
||||
|
||||
if (NULL == path) {
|
||||
error_setg(errp, "unix connect: no path specified\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
sock = qemu_socket(PF_UNIX, SOCK_STREAM, 0);
|
||||
if (sock < 0) {
|
||||
error_set_errno(errp, errno, QERR_SOCKET_CREATE_FAILED);
|
||||
return -1;
|
||||
}
|
||||
if (callback != NULL) {
|
||||
connect_state = g_malloc0(sizeof(*connect_state));
|
||||
connect_state->callback = callback;
|
||||
connect_state->opaque = opaque;
|
||||
socket_set_nonblock(sock);
|
||||
}
|
||||
|
||||
memset(&un, 0, sizeof(un));
|
||||
un.sun_family = AF_UNIX;
|
||||
snprintf(un.sun_path, sizeof(un.sun_path), "%s", path);
|
||||
|
||||
/* connect to peer */
|
||||
do {
|
||||
rc = 0;
|
||||
if (connect(sock, (struct sockaddr *) &un, sizeof(un)) < 0) {
|
||||
rc = -socket_error();
|
||||
}
|
||||
} while (rc == -EINTR);
|
||||
|
||||
if (connect_state != NULL && QEMU_SOCKET_RC_INPROGRESS(rc)) {
|
||||
connect_state->fd = sock;
|
||||
qemu_set_fd_handler2(sock, NULL, NULL, wait_for_connect,
|
||||
connect_state);
|
||||
return sock;
|
||||
} else if (rc >= 0) {
|
||||
/* non blocking socket immediate success, call callback */
|
||||
if (callback != NULL) {
|
||||
callback(sock, opaque);
|
||||
}
|
||||
}
|
||||
|
||||
if (rc < 0) {
|
||||
error_set_errno(errp, -rc, QERR_SOCKET_CONNECT_FAILED);
|
||||
close(sock);
|
||||
sock = -1;
|
||||
}
|
||||
|
||||
g_free(connect_state);
|
||||
return sock;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int unix_listen_opts(QemuOpts *opts, Error **errp)
|
||||
{
|
||||
error_setg(errp, "unix sockets are not available on windows");
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int unix_connect_opts(QemuOpts *opts, Error **errp,
|
||||
NonBlockingConnectHandler *callback, void *opaque)
|
||||
{
|
||||
error_setg(errp, "unix sockets are not available on windows");
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* compatibility wrapper */
|
||||
int unix_listen(const char *str, char *ostr, int olen, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
char *path, *optstr;
|
||||
int sock, len;
|
||||
|
||||
opts = qemu_opts_create_nofail(&dummy_opts);
|
||||
|
||||
optstr = strchr(str, ',');
|
||||
if (optstr) {
|
||||
len = optstr - str;
|
||||
if (len) {
|
||||
path = g_malloc(len+1);
|
||||
snprintf(path, len+1, "%.*s", len, str);
|
||||
qemu_opt_set(opts, "path", path);
|
||||
g_free(path);
|
||||
}
|
||||
} else {
|
||||
qemu_opt_set(opts, "path", str);
|
||||
}
|
||||
|
||||
sock = unix_listen_opts(opts, errp);
|
||||
|
||||
if (sock != -1 && ostr)
|
||||
snprintf(ostr, olen, "%s%s", qemu_opt_get(opts, "path"), optstr ? optstr : "");
|
||||
qemu_opts_del(opts);
|
||||
return sock;
|
||||
}
|
||||
|
||||
int unix_connect(const char *path, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
int sock;
|
||||
|
||||
opts = qemu_opts_create_nofail(&dummy_opts);
|
||||
qemu_opt_set(opts, "path", path);
|
||||
sock = unix_connect_opts(opts, errp, NULL, NULL);
|
||||
qemu_opts_del(opts);
|
||||
return sock;
|
||||
}
|
||||
|
||||
|
||||
int unix_nonblocking_connect(const char *path,
|
||||
NonBlockingConnectHandler *callback,
|
||||
void *opaque, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
int sock = -1;
|
||||
|
||||
g_assert(callback != NULL);
|
||||
|
||||
opts = qemu_opts_create_nofail(&dummy_opts);
|
||||
qemu_opt_set(opts, "path", path);
|
||||
sock = unix_connect_opts(opts, errp, callback, opaque);
|
||||
qemu_opts_del(opts);
|
||||
return sock;
|
||||
}
|
||||
|
||||
SocketAddress *socket_parse(const char *str, Error **errp)
|
||||
{
|
||||
SocketAddress *addr = NULL;
|
||||
|
||||
addr = g_new(SocketAddress, 1);
|
||||
if (strstart(str, "unix:", NULL)) {
|
||||
if (str[5] == '\0') {
|
||||
error_setg(errp, "invalid Unix socket address\n");
|
||||
goto fail;
|
||||
} else {
|
||||
addr->kind = SOCKET_ADDRESS_KIND_UNIX;
|
||||
addr->q_unix = g_new(UnixSocketAddress, 1);
|
||||
addr->q_unix->path = g_strdup(str + 5);
|
||||
}
|
||||
} else if (strstart(str, "fd:", NULL)) {
|
||||
if (str[3] == '\0') {
|
||||
error_setg(errp, "invalid file descriptor address\n");
|
||||
goto fail;
|
||||
} else {
|
||||
addr->kind = SOCKET_ADDRESS_KIND_FD;
|
||||
addr->fd = g_new(String, 1);
|
||||
addr->fd->str = g_strdup(str + 3);
|
||||
}
|
||||
} else {
|
||||
addr->kind = SOCKET_ADDRESS_KIND_INET;
|
||||
addr->inet = g_new(InetSocketAddress, 1);
|
||||
addr->inet = inet_parse(str, errp);
|
||||
if (addr->inet == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return addr;
|
||||
|
||||
fail:
|
||||
qapi_free_SocketAddress(addr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int socket_connect(SocketAddress *addr, Error **errp,
|
||||
NonBlockingConnectHandler *callback, void *opaque)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
int fd;
|
||||
|
||||
opts = qemu_opts_create_nofail(&dummy_opts);
|
||||
switch (addr->kind) {
|
||||
case SOCKET_ADDRESS_KIND_INET:
|
||||
inet_addr_to_opts(opts, addr->inet);
|
||||
fd = inet_connect_opts(opts, errp, callback, opaque);
|
||||
break;
|
||||
|
||||
case SOCKET_ADDRESS_KIND_UNIX:
|
||||
qemu_opt_set(opts, "path", addr->q_unix->path);
|
||||
fd = unix_connect_opts(opts, errp, callback, opaque);
|
||||
break;
|
||||
|
||||
case SOCKET_ADDRESS_KIND_FD:
|
||||
fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
|
||||
if (callback) {
|
||||
callback(fd, opaque);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return fd;
|
||||
}
|
||||
|
||||
int socket_listen(SocketAddress *addr, Error **errp)
|
||||
{
|
||||
QemuOpts *opts;
|
||||
int fd;
|
||||
|
||||
opts = qemu_opts_create_nofail(&dummy_opts);
|
||||
switch (addr->kind) {
|
||||
case SOCKET_ADDRESS_KIND_INET:
|
||||
inet_addr_to_opts(opts, addr->inet);
|
||||
fd = inet_listen_opts(opts, 0, errp);
|
||||
break;
|
||||
|
||||
case SOCKET_ADDRESS_KIND_UNIX:
|
||||
qemu_opt_set(opts, "path", addr->q_unix->path);
|
||||
fd = unix_listen_opts(opts, errp);
|
||||
break;
|
||||
|
||||
case SOCKET_ADDRESS_KIND_FD:
|
||||
fd = monitor_get_fd(cur_mon, addr->fd->str, errp);
|
||||
break;
|
||||
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
qemu_opts_del(opts);
|
||||
return fd;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
static void socket_cleanup(void)
|
||||
{
|
||||
WSACleanup();
|
||||
}
|
||||
#endif
|
||||
|
||||
int socket_init(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WSADATA Data;
|
||||
int ret, err;
|
||||
|
||||
ret = WSAStartup(MAKEWORD(2,2), &Data);
|
||||
if (ret != 0) {
|
||||
err = WSAGetLastError();
|
||||
fprintf(stderr, "WSAStartup: %d\n", err);
|
||||
return -1;
|
||||
}
|
||||
atexit(socket_cleanup);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
327
util/qemu-thread-posix.c
Normal file
327
util/qemu-thread-posix.c
Normal file
|
@ -0,0 +1,327 @@
|
|||
/*
|
||||
* Wrappers around mutex/cond/thread functions
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2009
|
||||
*
|
||||
* Author:
|
||||
* Marcelo Tosatti <mtosatti@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include "qemu/thread.h"
|
||||
|
||||
static void error_exit(int err, const char *msg)
|
||||
{
|
||||
fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
|
||||
abort();
|
||||
}
|
||||
|
||||
void qemu_mutex_init(QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
pthread_mutexattr_t mutexattr;
|
||||
|
||||
pthread_mutexattr_init(&mutexattr);
|
||||
pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK);
|
||||
err = pthread_mutex_init(&mutex->lock, &mutexattr);
|
||||
pthread_mutexattr_destroy(&mutexattr);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_mutex_destroy(QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_destroy(&mutex->lock);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_mutex_lock(QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_lock(&mutex->lock);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
int qemu_mutex_trylock(QemuMutex *mutex)
|
||||
{
|
||||
return pthread_mutex_trylock(&mutex->lock);
|
||||
}
|
||||
|
||||
void qemu_mutex_unlock(QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_mutex_unlock(&mutex->lock);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_init(QemuCond *cond)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_init(&cond->cond, NULL);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_destroy(QemuCond *cond)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_destroy(&cond->cond);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_signal(QemuCond *cond)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_signal(&cond->cond);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_broadcast(QemuCond *cond)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_broadcast(&cond->cond);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = pthread_cond_wait(&cond->cond, &mutex->lock);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
|
||||
void qemu_sem_init(QemuSemaphore *sem, int init)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
rc = pthread_mutex_init(&sem->lock, NULL);
|
||||
if (rc != 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
rc = pthread_cond_init(&sem->cond, NULL);
|
||||
if (rc != 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
if (init < 0) {
|
||||
error_exit(EINVAL, __func__);
|
||||
}
|
||||
sem->count = init;
|
||||
#else
|
||||
rc = sem_init(&sem->sem, 0, init);
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_sem_destroy(QemuSemaphore *sem)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
rc = pthread_cond_destroy(&sem->cond);
|
||||
if (rc < 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
rc = pthread_mutex_destroy(&sem->lock);
|
||||
if (rc < 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
#else
|
||||
rc = sem_destroy(&sem->sem);
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_sem_post(QemuSemaphore *sem)
|
||||
{
|
||||
int rc;
|
||||
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
if (sem->count == INT_MAX) {
|
||||
rc = EINVAL;
|
||||
} else if (sem->count++ < 0) {
|
||||
rc = pthread_cond_signal(&sem->cond);
|
||||
} else {
|
||||
rc = 0;
|
||||
}
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
if (rc != 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
#else
|
||||
rc = sem_post(&sem->sem);
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static void compute_abs_deadline(struct timespec *ts, int ms)
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
ts->tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000;
|
||||
ts->tv_sec = tv.tv_sec + ms / 1000;
|
||||
if (ts->tv_nsec >= 1000000000) {
|
||||
ts->tv_sec++;
|
||||
ts->tv_nsec -= 1000000000;
|
||||
}
|
||||
}
|
||||
|
||||
int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
|
||||
{
|
||||
int rc;
|
||||
struct timespec ts;
|
||||
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
compute_abs_deadline(&ts, ms);
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
--sem->count;
|
||||
while (sem->count < 0) {
|
||||
rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts);
|
||||
if (rc == ETIMEDOUT) {
|
||||
++sem->count;
|
||||
break;
|
||||
}
|
||||
if (rc != 0) {
|
||||
error_exit(rc, __func__);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
return (rc == ETIMEDOUT ? -1 : 0);
|
||||
#else
|
||||
if (ms <= 0) {
|
||||
/* This is cheaper than sem_timedwait. */
|
||||
do {
|
||||
rc = sem_trywait(&sem->sem);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
if (rc == -1 && errno == EAGAIN) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
compute_abs_deadline(&ts, ms);
|
||||
do {
|
||||
rc = sem_timedwait(&sem->sem, &ts);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
if (rc == -1 && errno == ETIMEDOUT) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_sem_wait(QemuSemaphore *sem)
|
||||
{
|
||||
#if defined(__APPLE__) || defined(__NetBSD__)
|
||||
pthread_mutex_lock(&sem->lock);
|
||||
--sem->count;
|
||||
while (sem->count < 0) {
|
||||
pthread_cond_wait(&sem->cond, &sem->lock);
|
||||
}
|
||||
pthread_mutex_unlock(&sem->lock);
|
||||
#else
|
||||
int rc;
|
||||
|
||||
do {
|
||||
rc = sem_wait(&sem->sem);
|
||||
} while (rc == -1 && errno == EINTR);
|
||||
if (rc < 0) {
|
||||
error_exit(errno, __func__);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void qemu_thread_create(QemuThread *thread,
|
||||
void *(*start_routine)(void*),
|
||||
void *arg, int mode)
|
||||
{
|
||||
sigset_t set, oldset;
|
||||
int err;
|
||||
pthread_attr_t attr;
|
||||
|
||||
err = pthread_attr_init(&attr);
|
||||
if (err) {
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
if (mode == QEMU_THREAD_DETACHED) {
|
||||
err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
if (err) {
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
}
|
||||
|
||||
/* Leave signal handling to the iothread. */
|
||||
sigfillset(&set);
|
||||
pthread_sigmask(SIG_SETMASK, &set, &oldset);
|
||||
err = pthread_create(&thread->thread, &attr, start_routine, arg);
|
||||
if (err)
|
||||
error_exit(err, __func__);
|
||||
|
||||
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
|
||||
|
||||
pthread_attr_destroy(&attr);
|
||||
}
|
||||
|
||||
void qemu_thread_get_self(QemuThread *thread)
|
||||
{
|
||||
thread->thread = pthread_self();
|
||||
}
|
||||
|
||||
bool qemu_thread_is_self(QemuThread *thread)
|
||||
{
|
||||
return pthread_equal(pthread_self(), thread->thread);
|
||||
}
|
||||
|
||||
void qemu_thread_exit(void *retval)
|
||||
{
|
||||
pthread_exit(retval);
|
||||
}
|
||||
|
||||
void *qemu_thread_join(QemuThread *thread)
|
||||
{
|
||||
int err;
|
||||
void *ret;
|
||||
|
||||
err = pthread_join(thread->thread, &ret);
|
||||
if (err) {
|
||||
error_exit(err, __func__);
|
||||
}
|
||||
return ret;
|
||||
}
|
359
util/qemu-thread-win32.c
Normal file
359
util/qemu-thread-win32.c
Normal file
|
@ -0,0 +1,359 @@
|
|||
/*
|
||||
* Win32 implementation for mutex/cond/thread functions
|
||||
*
|
||||
* Copyright Red Hat, Inc. 2010
|
||||
*
|
||||
* Author:
|
||||
* Paolo Bonzini <pbonzini@redhat.com>
|
||||
*
|
||||
* This work is licensed under the terms of the GNU GPL, version 2 or later.
|
||||
* See the COPYING file in the top-level directory.
|
||||
*
|
||||
*/
|
||||
#include "qemu-common.h"
|
||||
#include "qemu/thread.h"
|
||||
#include <process.h>
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
static void error_exit(int err, const char *msg)
|
||||
{
|
||||
char *pstr;
|
||||
|
||||
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
|
||||
NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
|
||||
fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
|
||||
LocalFree(pstr);
|
||||
abort();
|
||||
}
|
||||
|
||||
void qemu_mutex_init(QemuMutex *mutex)
|
||||
{
|
||||
mutex->owner = 0;
|
||||
InitializeCriticalSection(&mutex->lock);
|
||||
}
|
||||
|
||||
void qemu_mutex_destroy(QemuMutex *mutex)
|
||||
{
|
||||
assert(mutex->owner == 0);
|
||||
DeleteCriticalSection(&mutex->lock);
|
||||
}
|
||||
|
||||
void qemu_mutex_lock(QemuMutex *mutex)
|
||||
{
|
||||
EnterCriticalSection(&mutex->lock);
|
||||
|
||||
/* Win32 CRITICAL_SECTIONs are recursive. Assert that we're not
|
||||
* using them as such.
|
||||
*/
|
||||
assert(mutex->owner == 0);
|
||||
mutex->owner = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
int qemu_mutex_trylock(QemuMutex *mutex)
|
||||
{
|
||||
int owned;
|
||||
|
||||
owned = TryEnterCriticalSection(&mutex->lock);
|
||||
if (owned) {
|
||||
assert(mutex->owner == 0);
|
||||
mutex->owner = GetCurrentThreadId();
|
||||
}
|
||||
return !owned;
|
||||
}
|
||||
|
||||
void qemu_mutex_unlock(QemuMutex *mutex)
|
||||
{
|
||||
assert(mutex->owner == GetCurrentThreadId());
|
||||
mutex->owner = 0;
|
||||
LeaveCriticalSection(&mutex->lock);
|
||||
}
|
||||
|
||||
void qemu_cond_init(QemuCond *cond)
|
||||
{
|
||||
memset(cond, 0, sizeof(*cond));
|
||||
|
||||
cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
|
||||
if (!cond->sema) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
cond->continue_event = CreateEvent(NULL, /* security */
|
||||
FALSE, /* auto-reset */
|
||||
FALSE, /* not signaled */
|
||||
NULL); /* name */
|
||||
if (!cond->continue_event) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_cond_destroy(QemuCond *cond)
|
||||
{
|
||||
BOOL result;
|
||||
result = CloseHandle(cond->continue_event);
|
||||
if (!result) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
cond->continue_event = 0;
|
||||
result = CloseHandle(cond->sema);
|
||||
if (!result) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
cond->sema = 0;
|
||||
}
|
||||
|
||||
void qemu_cond_signal(QemuCond *cond)
|
||||
{
|
||||
DWORD result;
|
||||
|
||||
/*
|
||||
* Signal only when there are waiters. cond->waiters is
|
||||
* incremented by pthread_cond_wait under the external lock,
|
||||
* so we are safe about that.
|
||||
*/
|
||||
if (cond->waiters == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Waiting threads decrement it outside the external lock, but
|
||||
* only if another thread is executing pthread_cond_broadcast and
|
||||
* has the mutex. So, it also cannot be decremented concurrently
|
||||
* with this particular access.
|
||||
*/
|
||||
cond->target = cond->waiters - 1;
|
||||
result = SignalObjectAndWait(cond->sema, cond->continue_event,
|
||||
INFINITE, FALSE);
|
||||
if (result == WAIT_ABANDONED || result == WAIT_FAILED) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
}
|
||||
|
||||
void qemu_cond_broadcast(QemuCond *cond)
|
||||
{
|
||||
BOOLEAN result;
|
||||
/*
|
||||
* As in pthread_cond_signal, access to cond->waiters and
|
||||
* cond->target is locked via the external mutex.
|
||||
*/
|
||||
if (cond->waiters == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cond->target = 0;
|
||||
result = ReleaseSemaphore(cond->sema, cond->waiters, NULL);
|
||||
if (!result) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point all waiters continue. Each one takes its
|
||||
* slice of the semaphore. Now it's our turn to wait: Since
|
||||
* the external mutex is held, no thread can leave cond_wait,
|
||||
* yet. For this reason, we can be sure that no thread gets
|
||||
* a chance to eat *more* than one slice. OTOH, it means
|
||||
* that the last waiter must send us a wake-up.
|
||||
*/
|
||||
WaitForSingleObject(cond->continue_event, INFINITE);
|
||||
}
|
||||
|
||||
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
|
||||
{
|
||||
/*
|
||||
* This access is protected under the mutex.
|
||||
*/
|
||||
cond->waiters++;
|
||||
|
||||
/*
|
||||
* Unlock external mutex and wait for signal.
|
||||
* NOTE: we've held mutex locked long enough to increment
|
||||
* waiters count above, so there's no problem with
|
||||
* leaving mutex unlocked before we wait on semaphore.
|
||||
*/
|
||||
qemu_mutex_unlock(mutex);
|
||||
WaitForSingleObject(cond->sema, INFINITE);
|
||||
|
||||
/* Now waiters must rendez-vous with the signaling thread and
|
||||
* let it continue. For cond_broadcast this has heavy contention
|
||||
* and triggers thundering herd. So goes life.
|
||||
*
|
||||
* Decrease waiters count. The mutex is not taken, so we have
|
||||
* to do this atomically.
|
||||
*
|
||||
* All waiters contend for the mutex at the end of this function
|
||||
* until the signaling thread relinquishes it. To ensure
|
||||
* each waiter consumes exactly one slice of the semaphore,
|
||||
* the signaling thread stops until it is told by the last
|
||||
* waiter that it can go on.
|
||||
*/
|
||||
if (InterlockedDecrement(&cond->waiters) == cond->target) {
|
||||
SetEvent(cond->continue_event);
|
||||
}
|
||||
|
||||
qemu_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
void qemu_sem_init(QemuSemaphore *sem, int init)
|
||||
{
|
||||
/* Manual reset. */
|
||||
sem->sema = CreateSemaphore(NULL, init, LONG_MAX, NULL);
|
||||
}
|
||||
|
||||
void qemu_sem_destroy(QemuSemaphore *sem)
|
||||
{
|
||||
CloseHandle(sem->sema);
|
||||
}
|
||||
|
||||
void qemu_sem_post(QemuSemaphore *sem)
|
||||
{
|
||||
ReleaseSemaphore(sem->sema, 1, NULL);
|
||||
}
|
||||
|
||||
int qemu_sem_timedwait(QemuSemaphore *sem, int ms)
|
||||
{
|
||||
int rc = WaitForSingleObject(sem->sema, ms);
|
||||
if (rc == WAIT_OBJECT_0) {
|
||||
return 0;
|
||||
}
|
||||
if (rc != WAIT_TIMEOUT) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void qemu_sem_wait(QemuSemaphore *sem)
|
||||
{
|
||||
if (WaitForSingleObject(sem->sema, INFINITE) != WAIT_OBJECT_0) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
}
|
||||
|
||||
struct QemuThreadData {
|
||||
/* Passed to win32_start_routine. */
|
||||
void *(*start_routine)(void *);
|
||||
void *arg;
|
||||
short mode;
|
||||
|
||||
/* Only used for joinable threads. */
|
||||
bool exited;
|
||||
void *ret;
|
||||
CRITICAL_SECTION cs;
|
||||
};
|
||||
|
||||
static __thread QemuThreadData *qemu_thread_data;
|
||||
|
||||
static unsigned __stdcall win32_start_routine(void *arg)
|
||||
{
|
||||
QemuThreadData *data = (QemuThreadData *) arg;
|
||||
void *(*start_routine)(void *) = data->start_routine;
|
||||
void *thread_arg = data->arg;
|
||||
|
||||
if (data->mode == QEMU_THREAD_DETACHED) {
|
||||
g_free(data);
|
||||
data = NULL;
|
||||
}
|
||||
qemu_thread_data = data;
|
||||
qemu_thread_exit(start_routine(thread_arg));
|
||||
abort();
|
||||
}
|
||||
|
||||
void qemu_thread_exit(void *arg)
|
||||
{
|
||||
QemuThreadData *data = qemu_thread_data;
|
||||
|
||||
if (data) {
|
||||
assert(data->mode != QEMU_THREAD_DETACHED);
|
||||
data->ret = arg;
|
||||
EnterCriticalSection(&data->cs);
|
||||
data->exited = true;
|
||||
LeaveCriticalSection(&data->cs);
|
||||
}
|
||||
_endthreadex(0);
|
||||
}
|
||||
|
||||
void *qemu_thread_join(QemuThread *thread)
|
||||
{
|
||||
QemuThreadData *data;
|
||||
void *ret;
|
||||
HANDLE handle;
|
||||
|
||||
data = thread->data;
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
/*
|
||||
* Because multiple copies of the QemuThread can exist via
|
||||
* qemu_thread_get_self, we need to store a value that cannot
|
||||
* leak there. The simplest, non racy way is to store the TID,
|
||||
* discard the handle that _beginthreadex gives back, and
|
||||
* get another copy of the handle here.
|
||||
*/
|
||||
handle = qemu_thread_get_handle(thread);
|
||||
if (handle) {
|
||||
WaitForSingleObject(handle, INFINITE);
|
||||
CloseHandle(handle);
|
||||
}
|
||||
ret = data->ret;
|
||||
assert(data->mode != QEMU_THREAD_DETACHED);
|
||||
DeleteCriticalSection(&data->cs);
|
||||
g_free(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void qemu_thread_create(QemuThread *thread,
|
||||
void *(*start_routine)(void *),
|
||||
void *arg, int mode)
|
||||
{
|
||||
HANDLE hThread;
|
||||
struct QemuThreadData *data;
|
||||
|
||||
data = g_malloc(sizeof *data);
|
||||
data->start_routine = start_routine;
|
||||
data->arg = arg;
|
||||
data->mode = mode;
|
||||
data->exited = false;
|
||||
|
||||
if (data->mode != QEMU_THREAD_DETACHED) {
|
||||
InitializeCriticalSection(&data->cs);
|
||||
}
|
||||
|
||||
hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
|
||||
data, 0, &thread->tid);
|
||||
if (!hThread) {
|
||||
error_exit(GetLastError(), __func__);
|
||||
}
|
||||
CloseHandle(hThread);
|
||||
thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data;
|
||||
}
|
||||
|
||||
void qemu_thread_get_self(QemuThread *thread)
|
||||
{
|
||||
thread->data = qemu_thread_data;
|
||||
thread->tid = GetCurrentThreadId();
|
||||
}
|
||||
|
||||
HANDLE qemu_thread_get_handle(QemuThread *thread)
|
||||
{
|
||||
QemuThreadData *data;
|
||||
HANDLE handle;
|
||||
|
||||
data = thread->data;
|
||||
if (!data) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
assert(data->mode != QEMU_THREAD_DETACHED);
|
||||
EnterCriticalSection(&data->cs);
|
||||
if (!data->exited) {
|
||||
handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE,
|
||||
thread->tid);
|
||||
} else {
|
||||
handle = NULL;
|
||||
}
|
||||
LeaveCriticalSection(&data->cs);
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool qemu_thread_is_self(QemuThread *thread)
|
||||
{
|
||||
return GetCurrentThreadId() == thread->tid;
|
||||
}
|
63
util/qemu-timer-common.c
Normal file
63
util/qemu-timer-common.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* QEMU System Emulator
|
||||
*
|
||||
* Copyright (c) 2003-2008 Fabrice Bellard
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
#include "qemu/timer.h"
|
||||
|
||||
/***********************************************************/
|
||||
/* real time host monotonic timer */
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
int64_t clock_freq;
|
||||
|
||||
static void __attribute__((constructor)) init_get_clock(void)
|
||||
{
|
||||
LARGE_INTEGER freq;
|
||||
int ret;
|
||||
ret = QueryPerformanceFrequency(&freq);
|
||||
if (ret == 0) {
|
||||
fprintf(stderr, "Could not calibrate ticks\n");
|
||||
exit(1);
|
||||
}
|
||||
clock_freq = freq.QuadPart;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
int use_rt_clock;
|
||||
|
||||
static void __attribute__((constructor)) init_get_clock(void)
|
||||
{
|
||||
use_rt_clock = 0;
|
||||
#if defined(__linux__) || (defined(__FreeBSD__) && __FreeBSD_version >= 500000) \
|
||||
|| defined(__DragonFly__) || defined(__FreeBSD_kernel__) \
|
||||
|| defined(__OpenBSD__)
|
||||
{
|
||||
struct timespec ts;
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
|
||||
use_rt_clock = 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
2249
util/uri.c
Normal file
2249
util/uri.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue