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