qemu/util/osdep.c
<<
>>
Prefs
   1/*
   2 * QEMU low level functions
   3 *
   4 * Copyright (c) 2003 Fabrice Bellard
   5 *
   6 * Permission is hereby granted, free of charge, to any person obtaining a copy
   7 * of this software and associated documentation files (the "Software"), to deal
   8 * in the Software without restriction, including without limitation the rights
   9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 * copies of the Software, and to permit persons to whom the Software is
  11 * furnished to do so, subject to the following conditions:
  12 *
  13 * The above copyright notice and this permission notice shall be included in
  14 * all copies or substantial portions of the Software.
  15 *
  16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 * THE SOFTWARE.
  23 */
  24#include <stdlib.h>
  25#include <stdio.h>
  26#include <stdarg.h>
  27#include <stdbool.h>
  28#include <string.h>
  29#include <errno.h>
  30#include <unistd.h>
  31#include <fcntl.h>
  32
  33/* Needed early for CONFIG_BSD etc. */
  34#include "config-host.h"
  35
  36#if defined(CONFIG_MADVISE) || defined(CONFIG_POSIX_MADVISE)
  37#include <sys/mman.h>
  38#endif
  39
  40#ifdef CONFIG_SOLARIS
  41#include <sys/types.h>
  42#include <sys/statvfs.h>
  43/* See MySQL bug #7156 (http://bugs.mysql.com/bug.php?id=7156) for
  44   discussion about Solaris header problems */
  45extern int madvise(caddr_t, size_t, int);
  46#endif
  47
  48#include "qemu-common.h"
  49#include "qemu/sockets.h"
  50#include "qemu/error-report.h"
  51#include "monitor/monitor.h"
  52
  53static bool fips_enabled = false;
  54
  55/* Starting on QEMU 2.5, qemu_hw_version() returns "2.5+" by default
  56 * instead of QEMU_VERSION, so setting hw_version on MachineClass
  57 * is no longer mandatory.
  58 *
  59 * Do NOT change this string, or it will break compatibility on all
  60 * machine classes that don't set hw_version.
  61 */
  62static const char *hw_version = "2.5+";
  63
  64int socket_set_cork(int fd, int v)
  65{
  66#if defined(SOL_TCP) && defined(TCP_CORK)
  67    return qemu_setsockopt(fd, SOL_TCP, TCP_CORK, &v, sizeof(v));
  68#else
  69    return 0;
  70#endif
  71}
  72
  73int socket_set_nodelay(int fd)
  74{
  75    int v = 1;
  76    return qemu_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &v, sizeof(v));
  77}
  78
  79int qemu_madvise(void *addr, size_t len, int advice)
  80{
  81    if (advice == QEMU_MADV_INVALID) {
  82        errno = EINVAL;
  83        return -1;
  84    }
  85#if defined(CONFIG_MADVISE)
  86    return madvise(addr, len, advice);
  87#elif defined(CONFIG_POSIX_MADVISE)
  88    return posix_madvise(addr, len, advice);
  89#else
  90    errno = EINVAL;
  91    return -1;
  92#endif
  93}
  94
  95#ifndef _WIN32
  96/*
  97 * Dups an fd and sets the flags
  98 */
  99static int qemu_dup_flags(int fd, int flags)
 100{
 101    int ret;
 102    int serrno;
 103    int dup_flags;
 104
 105#ifdef F_DUPFD_CLOEXEC
 106    ret = fcntl(fd, F_DUPFD_CLOEXEC, 0);
 107#else
 108    ret = dup(fd);
 109    if (ret != -1) {
 110        qemu_set_cloexec(ret);
 111    }
 112#endif
 113    if (ret == -1) {
 114        goto fail;
 115    }
 116
 117    dup_flags = fcntl(ret, F_GETFL);
 118    if (dup_flags == -1) {
 119        goto fail;
 120    }
 121
 122    if ((flags & O_SYNC) != (dup_flags & O_SYNC)) {
 123        errno = EINVAL;
 124        goto fail;
 125    }
 126
 127    /* Set/unset flags that we can with fcntl */
 128    if (fcntl(ret, F_SETFL, flags) == -1) {
 129        goto fail;
 130    }
 131
 132    /* Truncate the file in the cases that open() would truncate it */
 133    if (flags & O_TRUNC ||
 134            ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))) {
 135        if (ftruncate(ret, 0) == -1) {
 136            goto fail;
 137        }
 138    }
 139
 140    return ret;
 141
 142fail:
 143    serrno = errno;
 144    if (ret != -1) {
 145        close(ret);
 146    }
 147    errno = serrno;
 148    return -1;
 149}
 150
 151static int qemu_parse_fdset(const char *param)
 152{
 153    return qemu_parse_fd(param);
 154}
 155#endif
 156
 157/*
 158 * Opens a file with FD_CLOEXEC set
 159 */
 160int qemu_open(const char *name, int flags, ...)
 161{
 162    int ret;
 163    int mode = 0;
 164
 165#ifndef _WIN32
 166    const char *fdset_id_str;
 167
 168    /* Attempt dup of fd from fd set */
 169    if (strstart(name, "/dev/fdset/", &fdset_id_str)) {
 170        int64_t fdset_id;
 171        int fd, dupfd;
 172
 173        fdset_id = qemu_parse_fdset(fdset_id_str);
 174        if (fdset_id == -1) {
 175            errno = EINVAL;
 176            return -1;
 177        }
 178
 179        fd = monitor_fdset_get_fd(fdset_id, flags);
 180        if (fd == -1) {
 181            return -1;
 182        }
 183
 184        dupfd = qemu_dup_flags(fd, flags);
 185        if (dupfd == -1) {
 186            return -1;
 187        }
 188
 189        ret = monitor_fdset_dup_fd_add(fdset_id, dupfd);
 190        if (ret == -1) {
 191            close(dupfd);
 192            errno = EINVAL;
 193            return -1;
 194        }
 195
 196        return dupfd;
 197    }
 198#endif
 199
 200    if (flags & O_CREAT) {
 201        va_list ap;
 202
 203        va_start(ap, flags);
 204        mode = va_arg(ap, int);
 205        va_end(ap);
 206    }
 207
 208#ifdef O_CLOEXEC
 209    ret = open(name, flags | O_CLOEXEC, mode);
 210#else
 211    ret = open(name, flags, mode);
 212    if (ret >= 0) {
 213        qemu_set_cloexec(ret);
 214    }
 215#endif
 216
 217#ifdef O_DIRECT
 218    if (ret == -1 && errno == EINVAL && (flags & O_DIRECT)) {
 219        error_report("file system may not support O_DIRECT");
 220        errno = EINVAL; /* in case it was clobbered */
 221    }
 222#endif /* O_DIRECT */
 223
 224    return ret;
 225}
 226
 227int qemu_close(int fd)
 228{
 229    int64_t fdset_id;
 230
 231    /* Close fd that was dup'd from an fdset */
 232    fdset_id = monitor_fdset_dup_fd_find(fd);
 233    if (fdset_id != -1) {
 234        int ret;
 235
 236        ret = close(fd);
 237        if (ret == 0) {
 238            monitor_fdset_dup_fd_remove(fd);
 239        }
 240
 241        return ret;
 242    }
 243
 244    return close(fd);
 245}
 246
 247/*
 248 * A variant of write(2) which handles partial write.
 249 *
 250 * Return the number of bytes transferred.
 251 * Set errno if fewer than `count' bytes are written.
 252 *
 253 * This function don't work with non-blocking fd's.
 254 * Any of the possibilities with non-bloking fd's is bad:
 255 *   - return a short write (then name is wrong)
 256 *   - busy wait adding (errno == EAGAIN) to the loop
 257 */
 258ssize_t qemu_write_full(int fd, const void *buf, size_t count)
 259{
 260    ssize_t ret = 0;
 261    ssize_t total = 0;
 262
 263    while (count) {
 264        ret = write(fd, buf, count);
 265        if (ret < 0) {
 266            if (errno == EINTR)
 267                continue;
 268            break;
 269        }
 270
 271        count -= ret;
 272        buf += ret;
 273        total += ret;
 274    }
 275
 276    return total;
 277}
 278
 279/*
 280 * Opens a socket with FD_CLOEXEC set
 281 */
 282int qemu_socket(int domain, int type, int protocol)
 283{
 284    int ret;
 285
 286#ifdef SOCK_CLOEXEC
 287    ret = socket(domain, type | SOCK_CLOEXEC, protocol);
 288    if (ret != -1 || errno != EINVAL) {
 289        return ret;
 290    }
 291#endif
 292    ret = socket(domain, type, protocol);
 293    if (ret >= 0) {
 294        qemu_set_cloexec(ret);
 295    }
 296
 297    return ret;
 298}
 299
 300/*
 301 * Accept a connection and set FD_CLOEXEC
 302 */
 303int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen)
 304{
 305    int ret;
 306
 307#ifdef CONFIG_ACCEPT4
 308    ret = accept4(s, addr, addrlen, SOCK_CLOEXEC);
 309    if (ret != -1 || errno != ENOSYS) {
 310        return ret;
 311    }
 312#endif
 313    ret = accept(s, addr, addrlen);
 314    if (ret >= 0) {
 315        qemu_set_cloexec(ret);
 316    }
 317
 318    return ret;
 319}
 320
 321void qemu_set_hw_version(const char *version)
 322{
 323    hw_version = version;
 324}
 325
 326const char *qemu_hw_version(void)
 327{
 328    return hw_version;
 329}
 330
 331void fips_set_state(bool requested)
 332{
 333#ifdef __linux__
 334    if (requested) {
 335        FILE *fds = fopen("/proc/sys/crypto/fips_enabled", "r");
 336        if (fds != NULL) {
 337            fips_enabled = (fgetc(fds) == '1');
 338            fclose(fds);
 339        }
 340    }
 341#else
 342    fips_enabled = false;
 343#endif /* __linux__ */
 344
 345#ifdef _FIPS_DEBUG
 346    fprintf(stderr, "FIPS mode %s (requested %s)\n",
 347            (fips_enabled ? "enabled" : "disabled"),
 348            (requested ? "enabled" : "disabled"));
 349#endif
 350}
 351
 352bool fips_get_state(void)
 353{
 354    return fips_enabled;
 355}
 356
 357#ifdef _WIN32
 358static void socket_cleanup(void)
 359{
 360    WSACleanup();
 361}
 362#endif
 363
 364int socket_init(void)
 365{
 366#ifdef _WIN32
 367    WSADATA Data;
 368    int ret, err;
 369
 370    ret = WSAStartup(MAKEWORD(2, 2), &Data);
 371    if (ret != 0) {
 372        err = WSAGetLastError();
 373        fprintf(stderr, "WSAStartup: %d\n", err);
 374        return -1;
 375    }
 376    atexit(socket_cleanup);
 377#endif
 378    return 0;
 379}
 380
 381#if !GLIB_CHECK_VERSION(2, 31, 0)
 382/* Ensure that glib is running in multi-threaded mode
 383 * Old versions of glib require explicit initialization.  Failure to do
 384 * this results in the single-threaded code paths being taken inside
 385 * glib.  For example, the g_slice allocator will not be thread-safe
 386 * and cause crashes.
 387 */
 388static void __attribute__((constructor)) thread_init(void)
 389{
 390    if (!g_thread_supported()) {
 391       g_thread_init(NULL);
 392    }
 393}
 394#endif
 395
 396#ifndef CONFIG_IOVEC
 397/* helper function for iov_send_recv() */
 398static ssize_t
 399readv_writev(int fd, const struct iovec *iov, int iov_cnt, bool do_write)
 400{
 401    unsigned i = 0;
 402    ssize_t ret = 0;
 403    while (i < iov_cnt) {
 404        ssize_t r = do_write
 405            ? write(fd, iov[i].iov_base, iov[i].iov_len)
 406            : read(fd, iov[i].iov_base, iov[i].iov_len);
 407        if (r > 0) {
 408            ret += r;
 409        } else if (!r) {
 410            break;
 411        } else if (errno == EINTR) {
 412            continue;
 413        } else {
 414            /* else it is some "other" error,
 415             * only return if there was no data processed. */
 416            if (ret == 0) {
 417                ret = -1;
 418            }
 419            break;
 420        }
 421        i++;
 422    }
 423    return ret;
 424}
 425
 426ssize_t
 427readv(int fd, const struct iovec *iov, int iov_cnt)
 428{
 429    return readv_writev(fd, iov, iov_cnt, false);
 430}
 431
 432ssize_t
 433writev(int fd, const struct iovec *iov, int iov_cnt)
 434{
 435    return readv_writev(fd, iov, iov_cnt, true);
 436}
 437#endif
 438