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