qemu/migration/qemu-file-stdio.c
<<
>>
Prefs
   1/*
   2 * QEMU System Emulator
   3 *
   4 * Copyright (c) 2003-2008 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-common.h"
  25#include "qemu/coroutine.h"
  26#include "migration/qemu-file.h"
  27
  28typedef struct QEMUFileStdio {
  29    FILE *stdio_file;
  30    QEMUFile *file;
  31} QEMUFileStdio;
  32
  33static int stdio_get_fd(void *opaque)
  34{
  35    QEMUFileStdio *s = opaque;
  36
  37    return fileno(s->stdio_file);
  38}
  39
  40static ssize_t stdio_put_buffer(void *opaque, const uint8_t *buf, int64_t pos,
  41                                size_t size)
  42{
  43    QEMUFileStdio *s = opaque;
  44    size_t res;
  45
  46    res = fwrite(buf, 1, size, s->stdio_file);
  47
  48    if (res != size) {
  49        return -errno;
  50    }
  51    return res;
  52}
  53
  54static ssize_t stdio_get_buffer(void *opaque, uint8_t *buf, int64_t pos,
  55                                size_t size)
  56{
  57    QEMUFileStdio *s = opaque;
  58    FILE *fp = s->stdio_file;
  59    ssize_t bytes;
  60
  61    for (;;) {
  62        clearerr(fp);
  63        bytes = fread(buf, 1, size, fp);
  64        if (bytes != 0 || !ferror(fp)) {
  65            break;
  66        }
  67        if (errno == EAGAIN) {
  68            yield_until_fd_readable(fileno(fp));
  69        } else if (errno != EINTR) {
  70            break;
  71        }
  72    }
  73    return bytes;
  74}
  75
  76static int stdio_pclose(void *opaque)
  77{
  78    QEMUFileStdio *s = opaque;
  79    int ret;
  80    ret = pclose(s->stdio_file);
  81    if (ret == -1) {
  82        ret = -errno;
  83    } else if (!WIFEXITED(ret) || WEXITSTATUS(ret) != 0) {
  84        /* close succeeded, but non-zero exit code: */
  85        ret = -EIO; /* fake errno value */
  86    }
  87    g_free(s);
  88    return ret;
  89}
  90
  91static int stdio_fclose(void *opaque)
  92{
  93    QEMUFileStdio *s = opaque;
  94    int ret = 0;
  95
  96    if (qemu_file_is_writable(s->file)) {
  97        int fd = fileno(s->stdio_file);
  98        struct stat st;
  99
 100        ret = fstat(fd, &st);
 101        if (ret == 0 && S_ISREG(st.st_mode)) {
 102            /*
 103             * If the file handle is a regular file make sure the
 104             * data is flushed to disk before signaling success.
 105             */
 106            ret = fsync(fd);
 107            if (ret != 0) {
 108                ret = -errno;
 109                return ret;
 110            }
 111        }
 112    }
 113    if (fclose(s->stdio_file) == EOF) {
 114        ret = -errno;
 115    }
 116    g_free(s);
 117    return ret;
 118}
 119
 120static const QEMUFileOps stdio_pipe_read_ops = {
 121    .get_fd =     stdio_get_fd,
 122    .get_buffer = stdio_get_buffer,
 123    .close =      stdio_pclose
 124};
 125
 126static const QEMUFileOps stdio_pipe_write_ops = {
 127    .get_fd =     stdio_get_fd,
 128    .put_buffer = stdio_put_buffer,
 129    .close =      stdio_pclose
 130};
 131
 132QEMUFile *qemu_popen_cmd(const char *command, const char *mode)
 133{
 134    FILE *stdio_file;
 135    QEMUFileStdio *s;
 136
 137    if (mode == NULL || (mode[0] != 'r' && mode[0] != 'w') || mode[1] != 0) {
 138        fprintf(stderr, "qemu_popen: Argument validity check failed\n");
 139        return NULL;
 140    }
 141
 142    stdio_file = popen(command, mode);
 143    if (stdio_file == NULL) {
 144        return NULL;
 145    }
 146
 147    s = g_new0(QEMUFileStdio, 1);
 148
 149    s->stdio_file = stdio_file;
 150
 151    if (mode[0] == 'r') {
 152        s->file = qemu_fopen_ops(s, &stdio_pipe_read_ops);
 153    } else {
 154        s->file = qemu_fopen_ops(s, &stdio_pipe_write_ops);
 155    }
 156    return s->file;
 157}
 158
 159static const QEMUFileOps stdio_file_read_ops = {
 160    .get_fd =     stdio_get_fd,
 161    .get_buffer = stdio_get_buffer,
 162    .close =      stdio_fclose
 163};
 164
 165static const QEMUFileOps stdio_file_write_ops = {
 166    .get_fd =     stdio_get_fd,
 167    .put_buffer = stdio_put_buffer,
 168    .close =      stdio_fclose
 169};
 170
 171QEMUFile *qemu_fopen(const char *filename, const char *mode)
 172{
 173    QEMUFileStdio *s;
 174
 175    if (qemu_file_mode_is_not_valid(mode)) {
 176        return NULL;
 177    }
 178
 179    s = g_new0(QEMUFileStdio, 1);
 180
 181    s->stdio_file = fopen(filename, mode);
 182    if (!s->stdio_file) {
 183        goto fail;
 184    }
 185
 186    if (mode[0] == 'w') {
 187        s->file = qemu_fopen_ops(s, &stdio_file_write_ops);
 188    } else {
 189        s->file = qemu_fopen_ops(s, &stdio_file_read_ops);
 190    }
 191    return s->file;
 192fail:
 193    g_free(s);
 194    return NULL;
 195}
 196