qemu/util/oslib-posix.c
<<
>>
Prefs
   1/*
   2 * os-posix-lib.c
   3 *
   4 * Copyright (c) 2003-2008 Fabrice Bellard
   5 * Copyright (c) 2010 Red Hat, Inc.
   6 *
   7 * QEMU library functions on POSIX which are shared between QEMU and
   8 * the QEMU tools.
   9 *
  10 * Permission is hereby granted, free of charge, to any person obtaining a copy
  11 * of this software and associated documentation files (the "Software"), to deal
  12 * in the Software without restriction, including without limitation the rights
  13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14 * copies of the Software, and to permit persons to whom the Software is
  15 * furnished to do so, subject to the following conditions:
  16 *
  17 * The above copyright notice and this permission notice shall be included in
  18 * all copies or substantial portions of the Software.
  19 *
  20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  23 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  26 * THE SOFTWARE.
  27 */
  28
  29/* The following block of code temporarily renames the daemon() function so the
  30   compiler does not see the warning associated with it in stdlib.h on OSX */
  31#ifdef __APPLE__
  32#define daemon qemu_fake_daemon_function
  33#include <stdlib.h>
  34#undef daemon
  35extern int daemon(int, int);
  36#endif
  37
  38#if defined(__linux__) && (defined(__x86_64__) || defined(__arm__))
  39   /* Use 2 MiB alignment so transparent hugepages can be used by KVM.
  40      Valgrind does not support alignments larger than 1 MiB,
  41      therefore we need special code which handles running on Valgrind. */
  42#  define QEMU_VMALLOC_ALIGN (512 * 4096)
  43#elif defined(__linux__) && defined(__s390x__)
  44   /* Use 1 MiB (segment size) alignment so gmap can be used by KVM. */
  45#  define QEMU_VMALLOC_ALIGN (256 * 4096)
  46#else
  47#  define QEMU_VMALLOC_ALIGN getpagesize()
  48#endif
  49#define HUGETLBFS_MAGIC       0x958458f6
  50
  51#include <termios.h>
  52#include <unistd.h>
  53#include <termios.h>
  54
  55#include <glib/gprintf.h>
  56
  57#include "config-host.h"
  58#include "sysemu/sysemu.h"
  59#include "trace.h"
  60#include "qemu/sockets.h"
  61#include <sys/mman.h>
  62#include <libgen.h>
  63#include <setjmp.h>
  64#include <sys/signal.h>
  65
  66#ifdef CONFIG_LINUX
  67#include <sys/syscall.h>
  68#include <sys/vfs.h>
  69#endif
  70
  71#ifdef __FreeBSD__
  72#include <sys/sysctl.h>
  73#endif
  74
  75int qemu_get_thread_id(void)
  76{
  77#if defined(__linux__)
  78    return syscall(SYS_gettid);
  79#else
  80    return getpid();
  81#endif
  82}
  83
  84int qemu_daemon(int nochdir, int noclose)
  85{
  86    return daemon(nochdir, noclose);
  87}
  88
  89void *qemu_oom_check(void *ptr)
  90{
  91    if (ptr == NULL) {
  92        fprintf(stderr, "Failed to allocate memory: %s\n", strerror(errno));
  93        abort();
  94    }
  95    return ptr;
  96}
  97
  98void *qemu_try_memalign(size_t alignment, size_t size)
  99{
 100    void *ptr;
 101
 102    if (alignment < sizeof(void*)) {
 103        alignment = sizeof(void*);
 104    }
 105
 106#if defined(_POSIX_C_SOURCE) && !defined(__sun__)
 107    int ret;
 108    ret = posix_memalign(&ptr, alignment, size);
 109    if (ret != 0) {
 110        errno = ret;
 111        ptr = NULL;
 112    }
 113#elif defined(CONFIG_BSD)
 114    ptr = valloc(size);
 115#else
 116    ptr = memalign(alignment, size);
 117#endif
 118    trace_qemu_memalign(alignment, size, ptr);
 119    return ptr;
 120}
 121
 122void *qemu_memalign(size_t alignment, size_t size)
 123{
 124    return qemu_oom_check(qemu_try_memalign(alignment, size));
 125}
 126
 127/* alloc shared memory pages */
 128void *qemu_anon_ram_alloc(size_t size, uint64_t *alignment)
 129{
 130    size_t align = QEMU_VMALLOC_ALIGN;
 131    size_t total = size + align - getpagesize();
 132    void *ptr = mmap(0, total, PROT_READ | PROT_WRITE,
 133                     MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
 134    size_t offset = QEMU_ALIGN_UP((uintptr_t)ptr, align) - (uintptr_t)ptr;
 135
 136    if (ptr == MAP_FAILED) {
 137        return NULL;
 138    }
 139
 140    if (alignment) {
 141        *alignment = align;
 142    }
 143    ptr += offset;
 144    total -= offset;
 145
 146    if (offset > 0) {
 147        munmap(ptr - offset, offset);
 148    }
 149    if (total > size) {
 150        munmap(ptr + size, total - size);
 151    }
 152
 153    trace_qemu_anon_ram_alloc(size, ptr);
 154    return ptr;
 155}
 156
 157void qemu_vfree(void *ptr)
 158{
 159    trace_qemu_vfree(ptr);
 160    free(ptr);
 161}
 162
 163void qemu_anon_ram_free(void *ptr, size_t size)
 164{
 165    trace_qemu_anon_ram_free(ptr, size);
 166    if (ptr) {
 167        munmap(ptr, size);
 168    }
 169}
 170
 171void qemu_set_block(int fd)
 172{
 173    int f;
 174    f = fcntl(fd, F_GETFL);
 175    fcntl(fd, F_SETFL, f & ~O_NONBLOCK);
 176}
 177
 178void qemu_set_nonblock(int fd)
 179{
 180    int f;
 181    f = fcntl(fd, F_GETFL);
 182    fcntl(fd, F_SETFL, f | O_NONBLOCK);
 183}
 184
 185int socket_set_fast_reuse(int fd)
 186{
 187    int val = 1, ret;
 188
 189    ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
 190                     (const char *)&val, sizeof(val));
 191
 192    assert(ret == 0);
 193
 194    return ret;
 195}
 196
 197void qemu_set_cloexec(int fd)
 198{
 199    int f;
 200    f = fcntl(fd, F_GETFD);
 201    fcntl(fd, F_SETFD, f | FD_CLOEXEC);
 202}
 203
 204/*
 205 * Creates a pipe with FD_CLOEXEC set on both file descriptors
 206 */
 207int qemu_pipe(int pipefd[2])
 208{
 209    int ret;
 210
 211#ifdef CONFIG_PIPE2
 212    ret = pipe2(pipefd, O_CLOEXEC);
 213    if (ret != -1 || errno != ENOSYS) {
 214        return ret;
 215    }
 216#endif
 217    ret = pipe(pipefd);
 218    if (ret == 0) {
 219        qemu_set_cloexec(pipefd[0]);
 220        qemu_set_cloexec(pipefd[1]);
 221    }
 222
 223    return ret;
 224}
 225
 226int qemu_utimens(const char *path, const struct timespec *times)
 227{
 228    struct timeval tv[2], tv_now;
 229    struct stat st;
 230    int i;
 231#ifdef CONFIG_UTIMENSAT
 232    int ret;
 233
 234    ret = utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
 235    if (ret != -1 || errno != ENOSYS) {
 236        return ret;
 237    }
 238#endif
 239    /* Fallback: use utimes() instead of utimensat() */
 240
 241    /* happy if special cases */
 242    if (times[0].tv_nsec == UTIME_OMIT && times[1].tv_nsec == UTIME_OMIT) {
 243        return 0;
 244    }
 245    if (times[0].tv_nsec == UTIME_NOW && times[1].tv_nsec == UTIME_NOW) {
 246        return utimes(path, NULL);
 247    }
 248
 249    /* prepare for hard cases */
 250    if (times[0].tv_nsec == UTIME_NOW || times[1].tv_nsec == UTIME_NOW) {
 251        gettimeofday(&tv_now, NULL);
 252    }
 253    if (times[0].tv_nsec == UTIME_OMIT || times[1].tv_nsec == UTIME_OMIT) {
 254        stat(path, &st);
 255    }
 256
 257    for (i = 0; i < 2; i++) {
 258        if (times[i].tv_nsec == UTIME_NOW) {
 259            tv[i].tv_sec = tv_now.tv_sec;
 260            tv[i].tv_usec = tv_now.tv_usec;
 261        } else if (times[i].tv_nsec == UTIME_OMIT) {
 262            tv[i].tv_sec = (i == 0) ? st.st_atime : st.st_mtime;
 263            tv[i].tv_usec = 0;
 264        } else {
 265            tv[i].tv_sec = times[i].tv_sec;
 266            tv[i].tv_usec = times[i].tv_nsec / 1000;
 267        }
 268    }
 269
 270    return utimes(path, &tv[0]);
 271}
 272
 273char *
 274qemu_get_local_state_pathname(const char *relative_pathname)
 275{
 276    return g_strdup_printf("%s/%s", CONFIG_QEMU_LOCALSTATEDIR,
 277                           relative_pathname);
 278}
 279
 280void qemu_set_tty_echo(int fd, bool echo)
 281{
 282    struct termios tty;
 283
 284    tcgetattr(fd, &tty);
 285
 286    if (echo) {
 287        tty.c_lflag |= ECHO | ECHONL | ICANON | IEXTEN;
 288    } else {
 289        tty.c_lflag &= ~(ECHO | ECHONL | ICANON | IEXTEN);
 290    }
 291
 292    tcsetattr(fd, TCSANOW, &tty);
 293}
 294
 295static char exec_dir[PATH_MAX];
 296
 297void qemu_init_exec_dir(const char *argv0)
 298{
 299    char *dir;
 300    char *p = NULL;
 301    char buf[PATH_MAX];
 302
 303    assert(!exec_dir[0]);
 304
 305#if defined(__linux__)
 306    {
 307        int len;
 308        len = readlink("/proc/self/exe", buf, sizeof(buf) - 1);
 309        if (len > 0) {
 310            buf[len] = 0;
 311            p = buf;
 312        }
 313    }
 314#elif defined(__FreeBSD__)
 315    {
 316        static int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
 317        size_t len = sizeof(buf) - 1;
 318
 319        *buf = '\0';
 320        if (!sysctl(mib, ARRAY_SIZE(mib), buf, &len, NULL, 0) &&
 321            *buf) {
 322            buf[sizeof(buf) - 1] = '\0';
 323            p = buf;
 324        }
 325    }
 326#endif
 327    /* If we don't have any way of figuring out the actual executable
 328       location then try argv[0].  */
 329    if (!p) {
 330        if (!argv0) {
 331            return;
 332        }
 333        p = realpath(argv0, buf);
 334        if (!p) {
 335            return;
 336        }
 337    }
 338    dir = dirname(p);
 339
 340    pstrcpy(exec_dir, sizeof(exec_dir), dir);
 341}
 342
 343char *qemu_get_exec_dir(void)
 344{
 345    return g_strdup(exec_dir);
 346}
 347
 348static sigjmp_buf sigjump;
 349
 350static void sigbus_handler(int signal)
 351{
 352    siglongjmp(sigjump, 1);
 353}
 354
 355static size_t fd_getpagesize(int fd)
 356{
 357#ifdef CONFIG_LINUX
 358    struct statfs fs;
 359    int ret;
 360
 361    if (fd != -1) {
 362        do {
 363            ret = fstatfs(fd, &fs);
 364        } while (ret != 0 && errno == EINTR);
 365
 366        if (ret == 0 && fs.f_type == HUGETLBFS_MAGIC) {
 367            return fs.f_bsize;
 368        }
 369    }
 370#endif
 371
 372    return getpagesize();
 373}
 374
 375void os_mem_prealloc(int fd, char *area, size_t memory)
 376{
 377    int ret;
 378    struct sigaction act, oldact;
 379    sigset_t set, oldset;
 380
 381    memset(&act, 0, sizeof(act));
 382    act.sa_handler = &sigbus_handler;
 383    act.sa_flags = 0;
 384
 385    ret = sigaction(SIGBUS, &act, &oldact);
 386    if (ret) {
 387        perror("os_mem_prealloc: failed to install signal handler");
 388        exit(1);
 389    }
 390
 391    /* unblock SIGBUS */
 392    sigemptyset(&set);
 393    sigaddset(&set, SIGBUS);
 394    pthread_sigmask(SIG_UNBLOCK, &set, &oldset);
 395
 396    if (sigsetjmp(sigjump, 1)) {
 397        fprintf(stderr, "os_mem_prealloc: Insufficient free host memory "
 398                        "pages available to allocate guest RAM\n");
 399        exit(1);
 400    } else {
 401        int i;
 402        size_t hpagesize = fd_getpagesize(fd);
 403        size_t numpages = DIV_ROUND_UP(memory, hpagesize);
 404
 405        /* MAP_POPULATE silently ignores failures */
 406        for (i = 0; i < numpages; i++) {
 407            memset(area + (hpagesize * i), 0, 1);
 408        }
 409
 410        ret = sigaction(SIGBUS, &oldact, NULL);
 411        if (ret) {
 412            perror("os_mem_prealloc: failed to reinstall signal handler");
 413            exit(1);
 414        }
 415
 416        pthread_sigmask(SIG_SETMASK, &oldset, NULL);
 417    }
 418}
 419
 420
 421static struct termios oldtty;
 422
 423static void term_exit(void)
 424{
 425    tcsetattr(0, TCSANOW, &oldtty);
 426}
 427
 428static void term_init(void)
 429{
 430    struct termios tty;
 431
 432    tcgetattr(0, &tty);
 433    oldtty = tty;
 434
 435    tty.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP
 436                          |INLCR|IGNCR|ICRNL|IXON);
 437    tty.c_oflag |= OPOST;
 438    tty.c_lflag &= ~(ECHO|ECHONL|ICANON|IEXTEN);
 439    tty.c_cflag &= ~(CSIZE|PARENB);
 440    tty.c_cflag |= CS8;
 441    tty.c_cc[VMIN] = 1;
 442    tty.c_cc[VTIME] = 0;
 443
 444    tcsetattr(0, TCSANOW, &tty);
 445
 446    atexit(term_exit);
 447}
 448
 449int qemu_read_password(char *buf, int buf_size)
 450{
 451    uint8_t ch;
 452    int i, ret;
 453
 454    printf("password: ");
 455    fflush(stdout);
 456    term_init();
 457    i = 0;
 458    for (;;) {
 459        ret = read(0, &ch, 1);
 460        if (ret == -1) {
 461            if (errno == EAGAIN || errno == EINTR) {
 462                continue;
 463            } else {
 464                break;
 465            }
 466        } else if (ret == 0) {
 467            ret = -1;
 468            break;
 469        } else {
 470            if (ch == '\r' ||
 471                ch == '\n') {
 472                ret = 0;
 473                break;
 474            }
 475            if (i < (buf_size - 1)) {
 476                buf[i++] = ch;
 477            }
 478        }
 479    }
 480    term_exit();
 481    buf[i] = '\0';
 482    printf("\n");
 483    return ret;
 484}
 485