xref: /openbmc/qemu/io/channel-file.c (revision 86e372ad)
1 /*
2  * QEMU I/O channels files driver
3  *
4  * Copyright (c) 2015 Red Hat, Inc.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 #include "qemu/osdep.h"
22 #include "io/channel-file.h"
23 #include "io/channel-util.h"
24 #include "io/channel-watch.h"
25 #include "qapi/error.h"
26 #include "qemu/module.h"
27 #include "qemu/sockets.h"
28 #include "trace.h"
29 
30 QIOChannelFile *
31 qio_channel_file_new_fd(int fd)
32 {
33     QIOChannelFile *ioc;
34 
35     ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE));
36 
37     ioc->fd = fd;
38 
39     if (lseek(fd, 0, SEEK_CUR) != (off_t)-1) {
40         qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SEEKABLE);
41     }
42 
43     trace_qio_channel_file_new_fd(ioc, fd);
44 
45     return ioc;
46 }
47 
48 
49 QIOChannelFile *
50 qio_channel_file_new_path(const char *path,
51                           int flags,
52                           mode_t mode,
53                           Error **errp)
54 {
55     QIOChannelFile *ioc;
56 
57     ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE));
58 
59     ioc->fd = qemu_open_old(path, flags, mode);
60     if (ioc->fd < 0) {
61         object_unref(OBJECT(ioc));
62         error_setg_errno(errp, errno,
63                          "Unable to open %s", path);
64         return NULL;
65     }
66 
67     if (lseek(ioc->fd, 0, SEEK_CUR) != (off_t)-1) {
68         qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SEEKABLE);
69     }
70 
71     trace_qio_channel_file_new_path(ioc, path, flags, mode, ioc->fd);
72 
73     return ioc;
74 }
75 
76 
77 static void qio_channel_file_init(Object *obj)
78 {
79     QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
80     ioc->fd = -1;
81 }
82 
83 static void qio_channel_file_finalize(Object *obj)
84 {
85     QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
86     if (ioc->fd != -1) {
87         qemu_close(ioc->fd);
88         ioc->fd = -1;
89     }
90 }
91 
92 
93 static ssize_t qio_channel_file_readv(QIOChannel *ioc,
94                                       const struct iovec *iov,
95                                       size_t niov,
96                                       int **fds,
97                                       size_t *nfds,
98                                       int flags,
99                                       Error **errp)
100 {
101     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
102     ssize_t ret;
103 
104  retry:
105     ret = readv(fioc->fd, iov, niov);
106     if (ret < 0) {
107         if (errno == EAGAIN) {
108             return QIO_CHANNEL_ERR_BLOCK;
109         }
110         if (errno == EINTR) {
111             goto retry;
112         }
113 
114         error_setg_errno(errp, errno,
115                          "Unable to read from file");
116         return -1;
117     }
118 
119     return ret;
120 }
121 
122 static ssize_t qio_channel_file_writev(QIOChannel *ioc,
123                                        const struct iovec *iov,
124                                        size_t niov,
125                                        int *fds,
126                                        size_t nfds,
127                                        int flags,
128                                        Error **errp)
129 {
130     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
131     ssize_t ret;
132 
133  retry:
134     ret = writev(fioc->fd, iov, niov);
135     if (ret <= 0) {
136         if (errno == EAGAIN) {
137             return QIO_CHANNEL_ERR_BLOCK;
138         }
139         if (errno == EINTR) {
140             goto retry;
141         }
142         error_setg_errno(errp, errno,
143                          "Unable to write to file");
144         return -1;
145     }
146     return ret;
147 }
148 
149 #ifdef CONFIG_PREADV
150 static ssize_t qio_channel_file_preadv(QIOChannel *ioc,
151                                        const struct iovec *iov,
152                                        size_t niov,
153                                        off_t offset,
154                                        Error **errp)
155 {
156     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
157     ssize_t ret;
158 
159  retry:
160     ret = preadv(fioc->fd, iov, niov, offset);
161     if (ret < 0) {
162         if (errno == EAGAIN) {
163             return QIO_CHANNEL_ERR_BLOCK;
164         }
165         if (errno == EINTR) {
166             goto retry;
167         }
168 
169         error_setg_errno(errp, errno, "Unable to read from file");
170         return -1;
171     }
172 
173     return ret;
174 }
175 
176 static ssize_t qio_channel_file_pwritev(QIOChannel *ioc,
177                                         const struct iovec *iov,
178                                         size_t niov,
179                                         off_t offset,
180                                         Error **errp)
181 {
182     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
183     ssize_t ret;
184 
185  retry:
186     ret = pwritev(fioc->fd, iov, niov, offset);
187     if (ret <= 0) {
188         if (errno == EAGAIN) {
189             return QIO_CHANNEL_ERR_BLOCK;
190         }
191         if (errno == EINTR) {
192             goto retry;
193         }
194         error_setg_errno(errp, errno, "Unable to write to file");
195         return -1;
196     }
197     return ret;
198 }
199 #endif /* CONFIG_PREADV */
200 
201 static int qio_channel_file_set_blocking(QIOChannel *ioc,
202                                          bool enabled,
203                                          Error **errp)
204 {
205 #ifdef WIN32
206     /* not implemented */
207     error_setg_errno(errp, errno, "Failed to set FD nonblocking");
208     return -1;
209 #else
210     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
211 
212     if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
213         error_setg_errno(errp, errno, "Failed to set FD nonblocking");
214         return -1;
215     }
216     return 0;
217 #endif
218 }
219 
220 
221 static off_t qio_channel_file_seek(QIOChannel *ioc,
222                                    off_t offset,
223                                    int whence,
224                                    Error **errp)
225 {
226     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
227     off_t ret;
228 
229     ret = lseek(fioc->fd, offset, whence);
230     if (ret == (off_t)-1) {
231         error_setg_errno(errp, errno,
232                          "Unable to seek to offset %lld whence %d in file",
233                          (long long int)offset, whence);
234         return -1;
235     }
236     return ret;
237 }
238 
239 
240 static int qio_channel_file_close(QIOChannel *ioc,
241                                   Error **errp)
242 {
243     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
244 
245     if (qemu_close(fioc->fd) < 0) {
246         error_setg_errno(errp, errno,
247                          "Unable to close file");
248         return -1;
249     }
250     fioc->fd = -1;
251     return 0;
252 }
253 
254 
255 static void qio_channel_file_set_aio_fd_handler(QIOChannel *ioc,
256                                                 AioContext *read_ctx,
257                                                 IOHandler *io_read,
258                                                 AioContext *write_ctx,
259                                                 IOHandler *io_write,
260                                                 void *opaque)
261 {
262     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
263 
264     qio_channel_util_set_aio_fd_handler(fioc->fd, read_ctx, io_read,
265                                         fioc->fd, write_ctx, io_write,
266                                         opaque);
267 }
268 
269 static GSource *qio_channel_file_create_watch(QIOChannel *ioc,
270                                               GIOCondition condition)
271 {
272     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
273     return qio_channel_create_fd_watch(ioc,
274                                        fioc->fd,
275                                        condition);
276 }
277 
278 static void qio_channel_file_class_init(ObjectClass *klass,
279                                         void *class_data G_GNUC_UNUSED)
280 {
281     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
282 
283     ioc_klass->io_writev = qio_channel_file_writev;
284     ioc_klass->io_readv = qio_channel_file_readv;
285     ioc_klass->io_set_blocking = qio_channel_file_set_blocking;
286 #ifdef CONFIG_PREADV
287     ioc_klass->io_pwritev = qio_channel_file_pwritev;
288     ioc_klass->io_preadv = qio_channel_file_preadv;
289 #endif
290     ioc_klass->io_seek = qio_channel_file_seek;
291     ioc_klass->io_close = qio_channel_file_close;
292     ioc_klass->io_create_watch = qio_channel_file_create_watch;
293     ioc_klass->io_set_aio_fd_handler = qio_channel_file_set_aio_fd_handler;
294 }
295 
296 static const TypeInfo qio_channel_file_info = {
297     .parent = TYPE_QIO_CHANNEL,
298     .name = TYPE_QIO_CHANNEL_FILE,
299     .instance_size = sizeof(QIOChannelFile),
300     .instance_init = qio_channel_file_init,
301     .instance_finalize = qio_channel_file_finalize,
302     .class_init = qio_channel_file_class_init,
303 };
304 
305 static void qio_channel_file_register_types(void)
306 {
307     type_register_static(&qio_channel_file_info);
308 }
309 
310 type_init(qio_channel_file_register_types);
311