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