xref: /openbmc/qemu/io/channel-file.c (revision 76bccf3c)
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 QIOChannelFile *
49 qio_channel_file_new_dupfd(int fd, Error **errp)
50 {
51     int newfd = dup(fd);
52 
53     if (newfd < 0) {
54         error_setg_errno(errp, errno, "Could not dup FD %d", fd);
55         return NULL;
56     }
57 
58     return qio_channel_file_new_fd(newfd);
59 }
60 
61 QIOChannelFile *
62 qio_channel_file_new_path(const char *path,
63                           int flags,
64                           mode_t mode,
65                           Error **errp)
66 {
67     QIOChannelFile *ioc;
68 
69     ioc = QIO_CHANNEL_FILE(object_new(TYPE_QIO_CHANNEL_FILE));
70 
71     if (flags & O_CREAT) {
72         ioc->fd = qemu_create(path, flags & ~O_CREAT, mode, errp);
73     } else {
74         ioc->fd = qemu_open(path, flags, errp);
75     }
76     if (ioc->fd < 0) {
77         object_unref(OBJECT(ioc));
78         return NULL;
79     }
80 
81     if (lseek(ioc->fd, 0, SEEK_CUR) != (off_t)-1) {
82         qio_channel_set_feature(QIO_CHANNEL(ioc), QIO_CHANNEL_FEATURE_SEEKABLE);
83     }
84 
85     trace_qio_channel_file_new_path(ioc, path, flags, mode, ioc->fd);
86 
87     return ioc;
88 }
89 
90 
91 static void qio_channel_file_init(Object *obj)
92 {
93     QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
94     ioc->fd = -1;
95 }
96 
97 static void qio_channel_file_finalize(Object *obj)
98 {
99     QIOChannelFile *ioc = QIO_CHANNEL_FILE(obj);
100     if (ioc->fd != -1) {
101         qemu_close(ioc->fd);
102         ioc->fd = -1;
103     }
104 }
105 
106 
107 static ssize_t qio_channel_file_readv(QIOChannel *ioc,
108                                       const struct iovec *iov,
109                                       size_t niov,
110                                       int **fds,
111                                       size_t *nfds,
112                                       int flags,
113                                       Error **errp)
114 {
115     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
116     ssize_t ret;
117 
118  retry:
119     ret = readv(fioc->fd, iov, niov);
120     if (ret < 0) {
121         if (errno == EAGAIN) {
122             return QIO_CHANNEL_ERR_BLOCK;
123         }
124         if (errno == EINTR) {
125             goto retry;
126         }
127 
128         error_setg_errno(errp, errno,
129                          "Unable to read from file");
130         return -1;
131     }
132 
133     return ret;
134 }
135 
136 static ssize_t qio_channel_file_writev(QIOChannel *ioc,
137                                        const struct iovec *iov,
138                                        size_t niov,
139                                        int *fds,
140                                        size_t nfds,
141                                        int flags,
142                                        Error **errp)
143 {
144     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
145     ssize_t ret;
146 
147  retry:
148     ret = writev(fioc->fd, iov, niov);
149     if (ret <= 0) {
150         if (errno == EAGAIN) {
151             return QIO_CHANNEL_ERR_BLOCK;
152         }
153         if (errno == EINTR) {
154             goto retry;
155         }
156         error_setg_errno(errp, errno,
157                          "Unable to write to file");
158         return -1;
159     }
160     return ret;
161 }
162 
163 #ifdef CONFIG_PREADV
164 static ssize_t qio_channel_file_preadv(QIOChannel *ioc,
165                                        const struct iovec *iov,
166                                        size_t niov,
167                                        off_t offset,
168                                        Error **errp)
169 {
170     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
171     ssize_t ret;
172 
173  retry:
174     ret = preadv(fioc->fd, iov, niov, offset);
175     if (ret < 0) {
176         if (errno == EAGAIN) {
177             return QIO_CHANNEL_ERR_BLOCK;
178         }
179         if (errno == EINTR) {
180             goto retry;
181         }
182 
183         error_setg_errno(errp, errno, "Unable to read from file");
184         return -1;
185     }
186 
187     return ret;
188 }
189 
190 static ssize_t qio_channel_file_pwritev(QIOChannel *ioc,
191                                         const struct iovec *iov,
192                                         size_t niov,
193                                         off_t offset,
194                                         Error **errp)
195 {
196     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
197     ssize_t ret;
198 
199  retry:
200     ret = pwritev(fioc->fd, iov, niov, offset);
201     if (ret <= 0) {
202         if (errno == EAGAIN) {
203             return QIO_CHANNEL_ERR_BLOCK;
204         }
205         if (errno == EINTR) {
206             goto retry;
207         }
208         error_setg_errno(errp, errno, "Unable to write to file");
209         return -1;
210     }
211     return ret;
212 }
213 #endif /* CONFIG_PREADV */
214 
215 static int qio_channel_file_set_blocking(QIOChannel *ioc,
216                                          bool enabled,
217                                          Error **errp)
218 {
219 #ifdef WIN32
220     /* not implemented */
221     error_setg_errno(errp, errno, "Failed to set FD nonblocking");
222     return -1;
223 #else
224     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
225 
226     if (!g_unix_set_fd_nonblocking(fioc->fd, !enabled, NULL)) {
227         error_setg_errno(errp, errno, "Failed to set FD nonblocking");
228         return -1;
229     }
230     return 0;
231 #endif
232 }
233 
234 
235 static off_t qio_channel_file_seek(QIOChannel *ioc,
236                                    off_t offset,
237                                    int whence,
238                                    Error **errp)
239 {
240     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
241     off_t ret;
242 
243     ret = lseek(fioc->fd, offset, whence);
244     if (ret == (off_t)-1) {
245         error_setg_errno(errp, errno,
246                          "Unable to seek to offset %lld whence %d in file",
247                          (long long int)offset, whence);
248         return -1;
249     }
250     return ret;
251 }
252 
253 
254 static int qio_channel_file_close(QIOChannel *ioc,
255                                   Error **errp)
256 {
257     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
258 
259     if (qemu_close(fioc->fd) < 0) {
260         error_setg_errno(errp, errno,
261                          "Unable to close file");
262         return -1;
263     }
264     fioc->fd = -1;
265     return 0;
266 }
267 
268 
269 static void qio_channel_file_set_aio_fd_handler(QIOChannel *ioc,
270                                                 AioContext *read_ctx,
271                                                 IOHandler *io_read,
272                                                 AioContext *write_ctx,
273                                                 IOHandler *io_write,
274                                                 void *opaque)
275 {
276     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
277 
278     qio_channel_util_set_aio_fd_handler(fioc->fd, read_ctx, io_read,
279                                         fioc->fd, write_ctx, io_write,
280                                         opaque);
281 }
282 
283 static GSource *qio_channel_file_create_watch(QIOChannel *ioc,
284                                               GIOCondition condition)
285 {
286     QIOChannelFile *fioc = QIO_CHANNEL_FILE(ioc);
287     return qio_channel_create_fd_watch(ioc,
288                                        fioc->fd,
289                                        condition);
290 }
291 
292 static void qio_channel_file_class_init(ObjectClass *klass,
293                                         void *class_data G_GNUC_UNUSED)
294 {
295     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
296 
297     ioc_klass->io_writev = qio_channel_file_writev;
298     ioc_klass->io_readv = qio_channel_file_readv;
299     ioc_klass->io_set_blocking = qio_channel_file_set_blocking;
300 #ifdef CONFIG_PREADV
301     ioc_klass->io_pwritev = qio_channel_file_pwritev;
302     ioc_klass->io_preadv = qio_channel_file_preadv;
303 #endif
304     ioc_klass->io_seek = qio_channel_file_seek;
305     ioc_klass->io_close = qio_channel_file_close;
306     ioc_klass->io_create_watch = qio_channel_file_create_watch;
307     ioc_klass->io_set_aio_fd_handler = qio_channel_file_set_aio_fd_handler;
308 }
309 
310 static const TypeInfo qio_channel_file_info = {
311     .parent = TYPE_QIO_CHANNEL,
312     .name = TYPE_QIO_CHANNEL_FILE,
313     .instance_size = sizeof(QIOChannelFile),
314     .instance_init = qio_channel_file_init,
315     .instance_finalize = qio_channel_file_finalize,
316     .class_init = qio_channel_file_class_init,
317 };
318 
319 static void qio_channel_file_register_types(void)
320 {
321     type_register_static(&qio_channel_file_info);
322 }
323 
324 type_init(qio_channel_file_register_types);
325