xref: /openbmc/qemu/io/channel-file.c (revision ffeddb979400b1580ad28acbee09b6f971c3912d)
1d6e48869SDaniel P. Berrange /*
2d6e48869SDaniel P. Berrange  * QEMU I/O channels files driver
3d6e48869SDaniel P. Berrange  *
4d6e48869SDaniel P. Berrange  * Copyright (c) 2015 Red Hat, Inc.
5d6e48869SDaniel P. Berrange  *
6d6e48869SDaniel P. Berrange  * This library is free software; you can redistribute it and/or
7d6e48869SDaniel P. Berrange  * modify it under the terms of the GNU Lesser General Public
8d6e48869SDaniel P. Berrange  * License as published by the Free Software Foundation; either
9c8198bd5SChetan Pant  * version 2.1 of the License, or (at your option) any later version.
10d6e48869SDaniel P. Berrange  *
11d6e48869SDaniel P. Berrange  * This library is distributed in the hope that it will be useful,
12d6e48869SDaniel P. Berrange  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13d6e48869SDaniel P. Berrange  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14d6e48869SDaniel P. Berrange  * Lesser General Public License for more details.
15d6e48869SDaniel P. Berrange  *
16d6e48869SDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
17d6e48869SDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18d6e48869SDaniel P. Berrange  *
19d6e48869SDaniel P. Berrange  */
20d6e48869SDaniel P. Berrange 
21cae9fc56SPeter Maydell #include "qemu/osdep.h"
22d6e48869SDaniel P. Berrange #include "io/channel-file.h"
2306e0f098SStefan Hajnoczi #include "io/channel-util.h"
24d6e48869SDaniel P. Berrange #include "io/channel-watch.h"
25da34e65cSMarkus Armbruster #include "qapi/error.h"
260b8fa32fSMarkus Armbruster #include "qemu/module.h"
27d6e48869SDaniel P. Berrange #include "qemu/sockets.h"
28d6e48869SDaniel P. Berrange #include "trace.h"
29d6e48869SDaniel P. Berrange 
30d6e48869SDaniel P. Berrange QIOChannelFile *
qio_channel_file_new_fd(int fd)31d6e48869SDaniel P. Berrange qio_channel_file_new_fd(int fd)
32d6e48869SDaniel P. Berrange {
33d6e48869SDaniel P. Berrange     QIOChannelFile *ioc;
34d6e48869SDaniel P. Berrange 
35d6e48869SDaniel P. Berrange     ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE));
36d6e48869SDaniel P. Berrange 
37d6e48869SDaniel P. Berrange     ioc->fd = fd;
38d6e48869SDaniel P. Berrange 
39401e311fSNikolay Borisov     if (lseek(fd, 0, SEEK_CUR) != (off_t)-1) {
40401e311fSNikolay Borisov         qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SEEKABLE);
41401e311fSNikolay Borisov     }
42401e311fSNikolay Borisov 
43d6e48869SDaniel P. Berrange     trace_qio_channel_file_new_fd(ioc, fd);
44d6e48869SDaniel P. Berrange 
45d6e48869SDaniel P. Berrange     return ioc;
46d6e48869SDaniel P. Berrange }
47d6e48869SDaniel P. Berrange 
484760cedcSFabiano Rosas QIOChannelFile *
qio_channel_file_new_dupfd(int fd,Error ** errp)494760cedcSFabiano Rosas qio_channel_file_new_dupfd(int fd, Error **errp)
504760cedcSFabiano Rosas {
514760cedcSFabiano Rosas     int newfd = dup(fd);
524760cedcSFabiano Rosas 
534760cedcSFabiano Rosas     if (newfd < 0) {
544760cedcSFabiano Rosas         error_setg_errno(errp, errno, "Could not dup FD %d", fd);
554760cedcSFabiano Rosas         return NULL;
564760cedcSFabiano Rosas     }
574760cedcSFabiano Rosas 
584760cedcSFabiano Rosas     return qio_channel_file_new_fd(newfd);
594760cedcSFabiano Rosas }
60d6e48869SDaniel P. Berrange 
61d6e48869SDaniel P. Berrange QIOChannelFile *
qio_channel_file_new_path(const char * path,int flags,mode_t mode,Error ** errp)62d6e48869SDaniel P. Berrange qio_channel_file_new_path(const char *path,
63d6e48869SDaniel P. Berrange                           int flags,
64d6e48869SDaniel P. Berrange                           mode_t mode,
65d6e48869SDaniel P. Berrange                           Error **errp)
66d6e48869SDaniel P. Berrange {
67d6e48869SDaniel P. Berrange     QIOChannelFile *ioc;
68d6e48869SDaniel P. Berrange 
69d6e48869SDaniel P. Berrange     ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE));
70d6e48869SDaniel P. Berrange 
71*46cec74cSFabiano Rosas     if (flags & O_CREAT) {
72*46cec74cSFabiano Rosas         ioc->fd = qemu_create(path, flags & ~O_CREAT, mode, errp);
73*46cec74cSFabiano Rosas     } else {
74*46cec74cSFabiano Rosas         ioc->fd = qemu_open(path, flags, errp);
75*46cec74cSFabiano Rosas     }
76d6e48869SDaniel P. Berrange     if (ioc->fd < 0) {
77d6e48869SDaniel P. Berrange         object_unref(OBJECT(ioc));
78d6e48869SDaniel P. Berrange         return NULL;
79d6e48869SDaniel P. Berrange     }
80d6e48869SDaniel P. Berrange 
81401e311fSNikolay Borisov     if (lseek(ioc->fd, 0, SEEK_CUR) != (off_t)-1) {
82401e311fSNikolay Borisov         qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SEEKABLE);
83401e311fSNikolay Borisov     }
84401e311fSNikolay Borisov 
85d6e48869SDaniel P. Berrange     trace_qio_channel_file_new_path(ioc, path, flags, mode, ioc->fd);
86d6e48869SDaniel P. Berrange 
87d6e48869SDaniel P. Berrange     return ioc;
88d6e48869SDaniel P. Berrange }
89d6e48869SDaniel P. Berrange 
90d6e48869SDaniel P. Berrange 
qio_channel_file_init(Object * obj)91d6e48869SDaniel P. Berrange static void qio_channel_file_init(Object *obj)
92d6e48869SDaniel P. Berrange {
93d6e48869SDaniel P. Berrange     QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
94d6e48869SDaniel P. Berrange     ioc->fd = -1;
95d6e48869SDaniel P. Berrange }
96d6e48869SDaniel P. Berrange 
qio_channel_file_finalize(Object * obj)97d6e48869SDaniel P. Berrange static void qio_channel_file_finalize(Object *obj)
98d6e48869SDaniel P. Berrange {
99d6e48869SDaniel P. Berrange     QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
100d6e48869SDaniel P. Berrange     if (ioc->fd != -1) {
101b8f244b1SRoss Lagerwall         qemu_close(ioc->fd);
102d6e48869SDaniel P. Berrange         ioc->fd = -1;
103d6e48869SDaniel P. Berrange     }
104d6e48869SDaniel P. Berrange }
105d6e48869SDaniel P. Berrange 
106d6e48869SDaniel P. Berrange 
qio_channel_file_readv(QIOChannel * ioc,const struct iovec * iov,size_t niov,int ** fds,size_t * nfds,int flags,Error ** errp)107d6e48869SDaniel P. Berrange static ssize_t qio_channel_file_readv(QIOChannel *ioc,
108d6e48869SDaniel P. Berrange                                       const struct iovec *iov,
109d6e48869SDaniel P. Berrange                                       size_t niov,
110d6e48869SDaniel P. Berrange                                       int **fds,
111d6e48869SDaniel P. Berrange                                       size_t *nfds,
11284615a19Smanish.mishra                                       int flags,
113d6e48869SDaniel P. Berrange                                       Error **errp)
114d6e48869SDaniel P. Berrange {
115d6e48869SDaniel P. Berrange     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
116d6e48869SDaniel P. Berrange     ssize_t ret;
117d6e48869SDaniel P. Berrange 
118d6e48869SDaniel P. Berrange  retry:
119d6e48869SDaniel P. Berrange     ret = readv(fioc->fd, iov, niov);
120d6e48869SDaniel P. Berrange     if (ret < 0) {
12130fd3e27SDaniel P. Berrange         if (errno == EAGAIN) {
122d6e48869SDaniel P. Berrange             return QIO_CHANNEL_ERR_BLOCK;
123d6e48869SDaniel P. Berrange         }
124d6e48869SDaniel P. Berrange         if (errno == EINTR) {
125d6e48869SDaniel P. Berrange             goto retry;
126d6e48869SDaniel P. Berrange         }
127d6e48869SDaniel P. Berrange 
128d6e48869SDaniel P. Berrange         error_setg_errno(errp, errno,
129d6e48869SDaniel P. Berrange                          "Unable to read from file");
130d6e48869SDaniel P. Berrange         return -1;
131d6e48869SDaniel P. Berrange     }
132d6e48869SDaniel P. Berrange 
133d6e48869SDaniel P. Berrange     return ret;
134d6e48869SDaniel P. Berrange }
135d6e48869SDaniel P. Berrange 
qio_channel_file_writev(QIOChannel * ioc,const struct iovec * iov,size_t niov,int * fds,size_t nfds,int flags,Error ** errp)136d6e48869SDaniel P. Berrange static ssize_t qio_channel_file_writev(QIOChannel *ioc,
137d6e48869SDaniel P. Berrange                                        const struct iovec *iov,
138d6e48869SDaniel P. Berrange                                        size_t niov,
139d6e48869SDaniel P. Berrange                                        int *fds,
140d6e48869SDaniel P. Berrange                                        size_t nfds,
141b88651cbSLeonardo Bras                                        int flags,
142d6e48869SDaniel P. Berrange                                        Error **errp)
143d6e48869SDaniel P. Berrange {
144d6e48869SDaniel P. Berrange     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
145d6e48869SDaniel P. Berrange     ssize_t ret;
146d6e48869SDaniel P. Berrange 
147d6e48869SDaniel P. Berrange  retry:
148d6e48869SDaniel P. Berrange     ret = writev(fioc->fd, iov, niov);
149d6e48869SDaniel P. Berrange     if (ret <= 0) {
15030fd3e27SDaniel P. Berrange         if (errno == EAGAIN) {
151d6e48869SDaniel P. Berrange             return QIO_CHANNEL_ERR_BLOCK;
152d6e48869SDaniel P. Berrange         }
153d6e48869SDaniel P. Berrange         if (errno == EINTR) {
154d6e48869SDaniel P. Berrange             goto retry;
155d6e48869SDaniel P. Berrange         }
156d6e48869SDaniel P. Berrange         error_setg_errno(errp, errno,
157d6e48869SDaniel P. Berrange                          "Unable to write to file");
158d6e48869SDaniel P. Berrange         return -1;
159d6e48869SDaniel P. Berrange     }
160d6e48869SDaniel P. Berrange     return ret;
161d6e48869SDaniel P. Berrange }
162d6e48869SDaniel P. Berrange 
1630478b030SNikolay Borisov #ifdef CONFIG_PREADV
qio_channel_file_preadv(QIOChannel * ioc,const struct iovec * iov,size_t niov,off_t offset,Error ** errp)1640478b030SNikolay Borisov static ssize_t qio_channel_file_preadv(QIOChannel *ioc,
1650478b030SNikolay Borisov                                        const struct iovec *iov,
1660478b030SNikolay Borisov                                        size_t niov,
1670478b030SNikolay Borisov                                        off_t offset,
1680478b030SNikolay Borisov                                        Error **errp)
1690478b030SNikolay Borisov {
1700478b030SNikolay Borisov     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
1710478b030SNikolay Borisov     ssize_t ret;
1720478b030SNikolay Borisov 
1730478b030SNikolay Borisov  retry:
1740478b030SNikolay Borisov     ret = preadv(fioc->fd, iov, niov, offset);
1750478b030SNikolay Borisov     if (ret < 0) {
1760478b030SNikolay Borisov         if (errno == EAGAIN) {
1770478b030SNikolay Borisov             return QIO_CHANNEL_ERR_BLOCK;
1780478b030SNikolay Borisov         }
1790478b030SNikolay Borisov         if (errno == EINTR) {
1800478b030SNikolay Borisov             goto retry;
1810478b030SNikolay Borisov         }
1820478b030SNikolay Borisov 
1830478b030SNikolay Borisov         error_setg_errno(errp, errno, "Unable to read from file");
1840478b030SNikolay Borisov         return -1;
1850478b030SNikolay Borisov     }
1860478b030SNikolay Borisov 
1870478b030SNikolay Borisov     return ret;
1880478b030SNikolay Borisov }
1890478b030SNikolay Borisov 
qio_channel_file_pwritev(QIOChannel * ioc,const struct iovec * iov,size_t niov,off_t offset,Error ** errp)1900478b030SNikolay Borisov static ssize_t qio_channel_file_pwritev(QIOChannel *ioc,
1910478b030SNikolay Borisov                                         const struct iovec *iov,
1920478b030SNikolay Borisov                                         size_t niov,
1930478b030SNikolay Borisov                                         off_t offset,
1940478b030SNikolay Borisov                                         Error **errp)
1950478b030SNikolay Borisov {
1960478b030SNikolay Borisov     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
1970478b030SNikolay Borisov     ssize_t ret;
1980478b030SNikolay Borisov 
1990478b030SNikolay Borisov  retry:
2000478b030SNikolay Borisov     ret = pwritev(fioc->fd, iov, niov, offset);
2010478b030SNikolay Borisov     if (ret <= 0) {
2020478b030SNikolay Borisov         if (errno == EAGAIN) {
2030478b030SNikolay Borisov             return QIO_CHANNEL_ERR_BLOCK;
2040478b030SNikolay Borisov         }
2050478b030SNikolay Borisov         if (errno == EINTR) {
2060478b030SNikolay Borisov             goto retry;
2070478b030SNikolay Borisov         }
2080478b030SNikolay Borisov         error_setg_errno(errp, errno, "Unable to write to file");
2090478b030SNikolay Borisov         return -1;
2100478b030SNikolay Borisov     }
2110478b030SNikolay Borisov     return ret;
2120478b030SNikolay Borisov }
2130478b030SNikolay Borisov #endif /* CONFIG_PREADV */
2140478b030SNikolay Borisov 
qio_channel_file_set_blocking(QIOChannel * ioc,bool enabled,Error ** errp)215d6e48869SDaniel P. Berrange static int qio_channel_file_set_blocking(QIOChannel *ioc,
216d6e48869SDaniel P. Berrange                                          bool enabled,
217d6e48869SDaniel P. Berrange                                          Error **errp)
218d6e48869SDaniel P. Berrange {
21917fc1245SMarc-André Lureau #ifdef WIN32
22017fc1245SMarc-André Lureau     /* not implemented */
22117fc1245SMarc-André Lureau     error_setg_errno(errp, errno, "Failed to set FD nonblocking");
22217fc1245SMarc-André Lureau     return -1;
22317fc1245SMarc-André Lureau #else
224d6e48869SDaniel P. Berrange     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
225d6e48869SDaniel P. Berrange 
22617fc1245SMarc-André Lureau     if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
22717fc1245SMarc-André Lureau         error_setg_errno(errp, errno, "Failed to set FD nonblocking");
22817fc1245SMarc-André Lureau         return -1;
229d6e48869SDaniel P. Berrange     }
230d6e48869SDaniel P. Berrange     return 0;
23117fc1245SMarc-André Lureau #endif
232d6e48869SDaniel P. Berrange }
233d6e48869SDaniel P. Berrange 
234d6e48869SDaniel P. Berrange 
qio_channel_file_seek(QIOChannel * ioc,off_t offset,int whence,Error ** errp)235d6e48869SDaniel P. Berrange static off_t qio_channel_file_seek(QIOChannel *ioc,
236d6e48869SDaniel P. Berrange                                    off_t offset,
237d6e48869SDaniel P. Berrange                                    int whence,
238d6e48869SDaniel P. Berrange                                    Error **errp)
239d6e48869SDaniel P. Berrange {
240d6e48869SDaniel P. Berrange     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
241d6e48869SDaniel P. Berrange     off_t ret;
242d6e48869SDaniel P. Berrange 
243d6e48869SDaniel P. Berrange     ret = lseek(fioc->fd, offset, whence);
244d6e48869SDaniel P. Berrange     if (ret == (off_t)-1) {
245d6e48869SDaniel P. Berrange         error_setg_errno(errp, errno,
246d6e48869SDaniel P. Berrange                          "Unable to seek to offset %lld whence %d in file",
247d6e48869SDaniel P. Berrange                          (long long int)offset, whence);
248d6e48869SDaniel P. Berrange         return -1;
249d6e48869SDaniel P. Berrange     }
250d6e48869SDaniel P. Berrange     return ret;
251d6e48869SDaniel P. Berrange }
252d6e48869SDaniel P. Berrange 
253d6e48869SDaniel P. Berrange 
qio_channel_file_close(QIOChannel * ioc,Error ** errp)254d6e48869SDaniel P. Berrange static int qio_channel_file_close(QIOChannel *ioc,
255d6e48869SDaniel P. Berrange                                   Error **errp)
256d6e48869SDaniel P. Berrange {
257d6e48869SDaniel P. Berrange     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
258d6e48869SDaniel P. Berrange 
259b8f244b1SRoss Lagerwall     if (qemu_close(fioc->fd) < 0) {
260d6e48869SDaniel P. Berrange         error_setg_errno(errp, errno,
261d6e48869SDaniel P. Berrange                          "Unable to close file");
262d6e48869SDaniel P. Berrange         return -1;
263d6e48869SDaniel P. Berrange     }
264a2565df1SRoss Lagerwall     fioc->fd = -1;
265d6e48869SDaniel P. Berrange     return 0;
266d6e48869SDaniel P. Berrange }
267d6e48869SDaniel P. Berrange 
268d6e48869SDaniel P. Berrange 
qio_channel_file_set_aio_fd_handler(QIOChannel * ioc,AioContext * read_ctx,IOHandler * io_read,AioContext * write_ctx,IOHandler * io_write,void * opaque)269bf88c124SPaolo Bonzini static void qio_channel_file_set_aio_fd_handler(QIOChannel *ioc,
27006e0f098SStefan Hajnoczi                                                 AioContext *read_ctx,
271bf88c124SPaolo Bonzini                                                 IOHandler *io_read,
27206e0f098SStefan Hajnoczi                                                 AioContext *write_ctx,
273bf88c124SPaolo Bonzini                                                 IOHandler *io_write,
274bf88c124SPaolo Bonzini                                                 void *opaque)
275bf88c124SPaolo Bonzini {
276bf88c124SPaolo Bonzini     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
27706e0f098SStefan Hajnoczi 
27806e0f098SStefan Hajnoczi     qio_channel_util_set_aio_fd_handler(fioc->fd, read_ctx, io_read,
27906e0f098SStefan Hajnoczi                                         fioc->fd, write_ctx, io_write,
28006e0f098SStefan Hajnoczi                                         opaque);
281bf88c124SPaolo Bonzini }
282bf88c124SPaolo Bonzini 
qio_channel_file_create_watch(QIOChannel * ioc,GIOCondition condition)283d6e48869SDaniel P. Berrange static GSource *qio_channel_file_create_watch(QIOChannel *ioc,
284d6e48869SDaniel P. Berrange                                               GIOCondition condition)
285d6e48869SDaniel P. Berrange {
286d6e48869SDaniel P. Berrange     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
287d6e48869SDaniel P. Berrange     return qio_channel_create_fd_watch(ioc,
288d6e48869SDaniel P. Berrange                                        fioc->fd,
289d6e48869SDaniel P. Berrange                                        condition);
290d6e48869SDaniel P. Berrange }
291d6e48869SDaniel P. Berrange 
qio_channel_file_class_init(ObjectClass * klass,void * class_data G_GNUC_UNUSED)292d6e48869SDaniel P. Berrange static void qio_channel_file_class_init(ObjectClass *klass,
293d6e48869SDaniel P. Berrange                                         void *class_data G_GNUC_UNUSED)
294d6e48869SDaniel P. Berrange {
295d6e48869SDaniel P. Berrange     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
296d6e48869SDaniel P. Berrange 
297d6e48869SDaniel P. Berrange     ioc_klass->io_writev = qio_channel_file_writev;
298d6e48869SDaniel P. Berrange     ioc_klass->io_readv = qio_channel_file_readv;
299d6e48869SDaniel P. Berrange     ioc_klass->io_set_blocking = qio_channel_file_set_blocking;
3000478b030SNikolay Borisov #ifdef CONFIG_PREADV
3010478b030SNikolay Borisov     ioc_klass->io_pwritev = qio_channel_file_pwritev;
3020478b030SNikolay Borisov     ioc_klass->io_preadv = qio_channel_file_preadv;
3030478b030SNikolay Borisov #endif
304d6e48869SDaniel P. Berrange     ioc_klass->io_seek = qio_channel_file_seek;
305d6e48869SDaniel P. Berrange     ioc_klass->io_close = qio_channel_file_close;
306d6e48869SDaniel P. Berrange     ioc_klass->io_create_watch = qio_channel_file_create_watch;
307bf88c124SPaolo Bonzini     ioc_klass->io_set_aio_fd_handler = qio_channel_file_set_aio_fd_handler;
308d6e48869SDaniel P. Berrange }
309d6e48869SDaniel P. Berrange 
310d6e48869SDaniel P. Berrange static const TypeInfo qio_channel_file_info = {
311d6e48869SDaniel P. Berrange     .parent = TYPE_QIO_CHANNEL,
312d6e48869SDaniel P. Berrange     .name = TYPE_QIO_CHANNEL_FILE,
313d6e48869SDaniel P. Berrange     .instance_size = sizeof(QIOChannelFile),
314d6e48869SDaniel P. Berrange     .instance_init = qio_channel_file_init,
315d6e48869SDaniel P. Berrange     .instance_finalize = qio_channel_file_finalize,
316d6e48869SDaniel P. Berrange     .class_init = qio_channel_file_class_init,
317d6e48869SDaniel P. Berrange };
318d6e48869SDaniel P. Berrange 
qio_channel_file_register_types(void)319d6e48869SDaniel P. Berrange static void qio_channel_file_register_types(void)
320d6e48869SDaniel P. Berrange {
321d6e48869SDaniel P. Berrange     type_register_static(&qio_channel_file_info);
322d6e48869SDaniel P. Berrange }
323d6e48869SDaniel P. Berrange 
324d6e48869SDaniel P. Berrange type_init(qio_channel_file_register_types);
325