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