xref: /openbmc/qemu/io/channel-command.c (revision 195e14d0262c5676cb9ff4b253e4b2b15c19d3f0)
1*195e14d0SDaniel P. Berrange /*
2*195e14d0SDaniel P. Berrange  * QEMU I/O channels external command driver
3*195e14d0SDaniel P. Berrange  *
4*195e14d0SDaniel P. Berrange  * Copyright (c) 2015 Red Hat, Inc.
5*195e14d0SDaniel P. Berrange  *
6*195e14d0SDaniel P. Berrange  * This library is free software; you can redistribute it and/or
7*195e14d0SDaniel P. Berrange  * modify it under the terms of the GNU Lesser General Public
8*195e14d0SDaniel P. Berrange  * License as published by the Free Software Foundation; either
9*195e14d0SDaniel P. Berrange  * version 2 of the License, or (at your option) any later version.
10*195e14d0SDaniel P. Berrange  *
11*195e14d0SDaniel P. Berrange  * This library is distributed in the hope that it will be useful,
12*195e14d0SDaniel P. Berrange  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*195e14d0SDaniel P. Berrange  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*195e14d0SDaniel P. Berrange  * Lesser General Public License for more details.
15*195e14d0SDaniel P. Berrange  *
16*195e14d0SDaniel P. Berrange  * You should have received a copy of the GNU Lesser General Public
17*195e14d0SDaniel P. Berrange  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*195e14d0SDaniel P. Berrange  *
19*195e14d0SDaniel P. Berrange  */
20*195e14d0SDaniel P. Berrange 
21*195e14d0SDaniel P. Berrange #include "io/channel-command.h"
22*195e14d0SDaniel P. Berrange #include "io/channel-watch.h"
23*195e14d0SDaniel P. Berrange #include "qemu/sockets.h"
24*195e14d0SDaniel P. Berrange #include "trace.h"
25*195e14d0SDaniel P. Berrange 
26*195e14d0SDaniel P. Berrange 
27*195e14d0SDaniel P. Berrange QIOChannelCommand *
28*195e14d0SDaniel P. Berrange qio_channel_command_new_pid(int writefd,
29*195e14d0SDaniel P. Berrange                             int readfd,
30*195e14d0SDaniel P. Berrange                             pid_t pid)
31*195e14d0SDaniel P. Berrange {
32*195e14d0SDaniel P. Berrange     QIOChannelCommand *ioc;
33*195e14d0SDaniel P. Berrange 
34*195e14d0SDaniel P. Berrange     ioc = QIO_CHANNEL_COMMAND(object_new(TYPE_QIO_CHANNEL_COMMAND));
35*195e14d0SDaniel P. Berrange 
36*195e14d0SDaniel P. Berrange     ioc->readfd = readfd;
37*195e14d0SDaniel P. Berrange     ioc->writefd = writefd;
38*195e14d0SDaniel P. Berrange     ioc->pid = pid;
39*195e14d0SDaniel P. Berrange 
40*195e14d0SDaniel P. Berrange     trace_qio_channel_command_new_pid(ioc, writefd, readfd, pid);
41*195e14d0SDaniel P. Berrange     return ioc;
42*195e14d0SDaniel P. Berrange }
43*195e14d0SDaniel P. Berrange 
44*195e14d0SDaniel P. Berrange 
45*195e14d0SDaniel P. Berrange #ifndef WIN32
46*195e14d0SDaniel P. Berrange QIOChannelCommand *
47*195e14d0SDaniel P. Berrange qio_channel_command_new_spawn(const char *const argv[],
48*195e14d0SDaniel P. Berrange                               int flags,
49*195e14d0SDaniel P. Berrange                               Error **errp)
50*195e14d0SDaniel P. Berrange {
51*195e14d0SDaniel P. Berrange     pid_t pid = -1;
52*195e14d0SDaniel P. Berrange     int stdinfd[2] = { -1, -1 };
53*195e14d0SDaniel P. Berrange     int stdoutfd[2] = { -1, -1 };
54*195e14d0SDaniel P. Berrange     int devnull = -1;
55*195e14d0SDaniel P. Berrange     bool stdinnull = false, stdoutnull = false;
56*195e14d0SDaniel P. Berrange     QIOChannelCommand *ioc;
57*195e14d0SDaniel P. Berrange 
58*195e14d0SDaniel P. Berrange     flags = flags & O_ACCMODE;
59*195e14d0SDaniel P. Berrange 
60*195e14d0SDaniel P. Berrange     if (flags == O_RDONLY) {
61*195e14d0SDaniel P. Berrange         stdinnull = true;
62*195e14d0SDaniel P. Berrange     }
63*195e14d0SDaniel P. Berrange     if (flags == O_WRONLY) {
64*195e14d0SDaniel P. Berrange         stdoutnull = true;
65*195e14d0SDaniel P. Berrange     }
66*195e14d0SDaniel P. Berrange 
67*195e14d0SDaniel P. Berrange     if (stdinnull || stdoutnull) {
68*195e14d0SDaniel P. Berrange         devnull = open("/dev/null", O_RDWR);
69*195e14d0SDaniel P. Berrange         if (!devnull) {
70*195e14d0SDaniel P. Berrange             error_setg_errno(errp, errno,
71*195e14d0SDaniel P. Berrange                              "Unable to open /dev/null");
72*195e14d0SDaniel P. Berrange             goto error;
73*195e14d0SDaniel P. Berrange         }
74*195e14d0SDaniel P. Berrange     }
75*195e14d0SDaniel P. Berrange 
76*195e14d0SDaniel P. Berrange     if ((!stdinnull && pipe(stdinfd) < 0) ||
77*195e14d0SDaniel P. Berrange         (!stdoutnull && pipe(stdoutfd) < 0)) {
78*195e14d0SDaniel P. Berrange         error_setg_errno(errp, errno,
79*195e14d0SDaniel P. Berrange                          "Unable to open pipe");
80*195e14d0SDaniel P. Berrange         goto error;
81*195e14d0SDaniel P. Berrange     }
82*195e14d0SDaniel P. Berrange 
83*195e14d0SDaniel P. Berrange     pid = qemu_fork(errp);
84*195e14d0SDaniel P. Berrange     if (pid < 0) {
85*195e14d0SDaniel P. Berrange         goto error;
86*195e14d0SDaniel P. Berrange     }
87*195e14d0SDaniel P. Berrange 
88*195e14d0SDaniel P. Berrange     if (pid == 0) { /* child */
89*195e14d0SDaniel P. Berrange         dup2(stdinnull ? devnull : stdinfd[0], STDIN_FILENO);
90*195e14d0SDaniel P. Berrange         dup2(stdoutnull ? devnull : stdoutfd[1], STDOUT_FILENO);
91*195e14d0SDaniel P. Berrange         /* Leave stderr connected to qemu's stderr */
92*195e14d0SDaniel P. Berrange 
93*195e14d0SDaniel P. Berrange         if (!stdinnull) {
94*195e14d0SDaniel P. Berrange             close(stdinfd[0]);
95*195e14d0SDaniel P. Berrange             close(stdinfd[1]);
96*195e14d0SDaniel P. Berrange         }
97*195e14d0SDaniel P. Berrange         if (!stdoutnull) {
98*195e14d0SDaniel P. Berrange             close(stdoutfd[0]);
99*195e14d0SDaniel P. Berrange             close(stdoutfd[1]);
100*195e14d0SDaniel P. Berrange         }
101*195e14d0SDaniel P. Berrange 
102*195e14d0SDaniel P. Berrange         execv(argv[0], (char * const *)argv);
103*195e14d0SDaniel P. Berrange         _exit(1);
104*195e14d0SDaniel P. Berrange     }
105*195e14d0SDaniel P. Berrange 
106*195e14d0SDaniel P. Berrange     if (!stdinnull) {
107*195e14d0SDaniel P. Berrange         close(stdinfd[0]);
108*195e14d0SDaniel P. Berrange     }
109*195e14d0SDaniel P. Berrange     if (!stdoutnull) {
110*195e14d0SDaniel P. Berrange         close(stdoutfd[1]);
111*195e14d0SDaniel P. Berrange     }
112*195e14d0SDaniel P. Berrange 
113*195e14d0SDaniel P. Berrange     ioc = qio_channel_command_new_pid(stdinnull ? devnull : stdinfd[1],
114*195e14d0SDaniel P. Berrange                                       stdoutnull ? devnull : stdoutfd[0],
115*195e14d0SDaniel P. Berrange                                       pid);
116*195e14d0SDaniel P. Berrange     trace_qio_channel_command_new_spawn(ioc, argv[0], flags);
117*195e14d0SDaniel P. Berrange     return ioc;
118*195e14d0SDaniel P. Berrange 
119*195e14d0SDaniel P. Berrange  error:
120*195e14d0SDaniel P. Berrange     if (stdinfd[0] != -1) {
121*195e14d0SDaniel P. Berrange         close(stdinfd[0]);
122*195e14d0SDaniel P. Berrange     }
123*195e14d0SDaniel P. Berrange     if (stdinfd[1] != -1) {
124*195e14d0SDaniel P. Berrange         close(stdinfd[1]);
125*195e14d0SDaniel P. Berrange     }
126*195e14d0SDaniel P. Berrange     if (stdoutfd[0] != -1) {
127*195e14d0SDaniel P. Berrange         close(stdoutfd[0]);
128*195e14d0SDaniel P. Berrange     }
129*195e14d0SDaniel P. Berrange     if (stdoutfd[1] != -1) {
130*195e14d0SDaniel P. Berrange         close(stdoutfd[1]);
131*195e14d0SDaniel P. Berrange     }
132*195e14d0SDaniel P. Berrange     return NULL;
133*195e14d0SDaniel P. Berrange }
134*195e14d0SDaniel P. Berrange 
135*195e14d0SDaniel P. Berrange #else /* WIN32 */
136*195e14d0SDaniel P. Berrange QIOChannelCommand *
137*195e14d0SDaniel P. Berrange qio_channel_command_new_spawn(const char *const argv[],
138*195e14d0SDaniel P. Berrange                               int flags,
139*195e14d0SDaniel P. Berrange                               Error **errp)
140*195e14d0SDaniel P. Berrange {
141*195e14d0SDaniel P. Berrange     error_setg_errno(errp, ENOSYS,
142*195e14d0SDaniel P. Berrange                      "Command spawn not supported on this platform");
143*195e14d0SDaniel P. Berrange     return NULL;
144*195e14d0SDaniel P. Berrange }
145*195e14d0SDaniel P. Berrange #endif /* WIN32 */
146*195e14d0SDaniel P. Berrange 
147*195e14d0SDaniel P. Berrange #ifndef WIN32
148*195e14d0SDaniel P. Berrange static int qio_channel_command_abort(QIOChannelCommand *ioc,
149*195e14d0SDaniel P. Berrange                                      Error **errp)
150*195e14d0SDaniel P. Berrange {
151*195e14d0SDaniel P. Berrange     pid_t ret;
152*195e14d0SDaniel P. Berrange     int status;
153*195e14d0SDaniel P. Berrange     int step = 0;
154*195e14d0SDaniel P. Berrange 
155*195e14d0SDaniel P. Berrange     /* See if intermediate process has exited; if not, try a nice
156*195e14d0SDaniel P. Berrange      * SIGTERM followed by a more severe SIGKILL.
157*195e14d0SDaniel P. Berrange      */
158*195e14d0SDaniel P. Berrange  rewait:
159*195e14d0SDaniel P. Berrange     trace_qio_channel_command_abort(ioc, ioc->pid);
160*195e14d0SDaniel P. Berrange     ret = waitpid(ioc->pid, &status, WNOHANG);
161*195e14d0SDaniel P. Berrange     trace_qio_channel_command_wait(ioc, ioc->pid, ret, status);
162*195e14d0SDaniel P. Berrange     if (ret == (pid_t)-1) {
163*195e14d0SDaniel P. Berrange         if (errno == EINTR) {
164*195e14d0SDaniel P. Berrange             goto rewait;
165*195e14d0SDaniel P. Berrange         } else {
166*195e14d0SDaniel P. Berrange             error_setg_errno(errp, errno,
167*195e14d0SDaniel P. Berrange                              "Cannot wait on pid %llu",
168*195e14d0SDaniel P. Berrange                              (unsigned long long)ioc->pid);
169*195e14d0SDaniel P. Berrange             return -1;
170*195e14d0SDaniel P. Berrange         }
171*195e14d0SDaniel P. Berrange     } else if (ret == 0) {
172*195e14d0SDaniel P. Berrange         if (step == 0) {
173*195e14d0SDaniel P. Berrange             kill(ioc->pid, SIGTERM);
174*195e14d0SDaniel P. Berrange         } else if (step == 1) {
175*195e14d0SDaniel P. Berrange             kill(ioc->pid, SIGKILL);
176*195e14d0SDaniel P. Berrange         } else {
177*195e14d0SDaniel P. Berrange             error_setg(errp,
178*195e14d0SDaniel P. Berrange                        "Process %llu refused to die",
179*195e14d0SDaniel P. Berrange                        (unsigned long long)ioc->pid);
180*195e14d0SDaniel P. Berrange             return -1;
181*195e14d0SDaniel P. Berrange         }
182*195e14d0SDaniel P. Berrange         usleep(10 * 1000);
183*195e14d0SDaniel P. Berrange         goto rewait;
184*195e14d0SDaniel P. Berrange     }
185*195e14d0SDaniel P. Berrange 
186*195e14d0SDaniel P. Berrange     return 0;
187*195e14d0SDaniel P. Berrange }
188*195e14d0SDaniel P. Berrange #endif /* ! WIN32 */
189*195e14d0SDaniel P. Berrange 
190*195e14d0SDaniel P. Berrange 
191*195e14d0SDaniel P. Berrange static void qio_channel_command_init(Object *obj)
192*195e14d0SDaniel P. Berrange {
193*195e14d0SDaniel P. Berrange     QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj);
194*195e14d0SDaniel P. Berrange     ioc->readfd = -1;
195*195e14d0SDaniel P. Berrange     ioc->writefd = -1;
196*195e14d0SDaniel P. Berrange     ioc->pid = -1;
197*195e14d0SDaniel P. Berrange }
198*195e14d0SDaniel P. Berrange 
199*195e14d0SDaniel P. Berrange static void qio_channel_command_finalize(Object *obj)
200*195e14d0SDaniel P. Berrange {
201*195e14d0SDaniel P. Berrange     QIOChannelCommand *ioc = QIO_CHANNEL_COMMAND(obj);
202*195e14d0SDaniel P. Berrange     if (ioc->readfd != -1) {
203*195e14d0SDaniel P. Berrange         close(ioc->readfd);
204*195e14d0SDaniel P. Berrange         ioc->readfd = -1;
205*195e14d0SDaniel P. Berrange     }
206*195e14d0SDaniel P. Berrange     if (ioc->writefd != -1) {
207*195e14d0SDaniel P. Berrange         close(ioc->writefd);
208*195e14d0SDaniel P. Berrange         ioc->writefd = -1;
209*195e14d0SDaniel P. Berrange     }
210*195e14d0SDaniel P. Berrange     if (ioc->pid > 0) {
211*195e14d0SDaniel P. Berrange #ifndef WIN32
212*195e14d0SDaniel P. Berrange         qio_channel_command_abort(ioc, NULL);
213*195e14d0SDaniel P. Berrange #endif
214*195e14d0SDaniel P. Berrange     }
215*195e14d0SDaniel P. Berrange }
216*195e14d0SDaniel P. Berrange 
217*195e14d0SDaniel P. Berrange 
218*195e14d0SDaniel P. Berrange static ssize_t qio_channel_command_readv(QIOChannel *ioc,
219*195e14d0SDaniel P. Berrange                                          const struct iovec *iov,
220*195e14d0SDaniel P. Berrange                                          size_t niov,
221*195e14d0SDaniel P. Berrange                                          int **fds,
222*195e14d0SDaniel P. Berrange                                          size_t *nfds,
223*195e14d0SDaniel P. Berrange                                          Error **errp)
224*195e14d0SDaniel P. Berrange {
225*195e14d0SDaniel P. Berrange     QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
226*195e14d0SDaniel P. Berrange     ssize_t ret;
227*195e14d0SDaniel P. Berrange 
228*195e14d0SDaniel P. Berrange  retry:
229*195e14d0SDaniel P. Berrange     ret = readv(cioc->readfd, iov, niov);
230*195e14d0SDaniel P. Berrange     if (ret < 0) {
231*195e14d0SDaniel P. Berrange         if (errno == EAGAIN ||
232*195e14d0SDaniel P. Berrange             errno == EWOULDBLOCK) {
233*195e14d0SDaniel P. Berrange             return QIO_CHANNEL_ERR_BLOCK;
234*195e14d0SDaniel P. Berrange         }
235*195e14d0SDaniel P. Berrange         if (errno == EINTR) {
236*195e14d0SDaniel P. Berrange             goto retry;
237*195e14d0SDaniel P. Berrange         }
238*195e14d0SDaniel P. Berrange 
239*195e14d0SDaniel P. Berrange         error_setg_errno(errp, errno,
240*195e14d0SDaniel P. Berrange                          "Unable to read from command");
241*195e14d0SDaniel P. Berrange         return -1;
242*195e14d0SDaniel P. Berrange     }
243*195e14d0SDaniel P. Berrange 
244*195e14d0SDaniel P. Berrange     return ret;
245*195e14d0SDaniel P. Berrange }
246*195e14d0SDaniel P. Berrange 
247*195e14d0SDaniel P. Berrange static ssize_t qio_channel_command_writev(QIOChannel *ioc,
248*195e14d0SDaniel P. Berrange                                           const struct iovec *iov,
249*195e14d0SDaniel P. Berrange                                           size_t niov,
250*195e14d0SDaniel P. Berrange                                           int *fds,
251*195e14d0SDaniel P. Berrange                                           size_t nfds,
252*195e14d0SDaniel P. Berrange                                           Error **errp)
253*195e14d0SDaniel P. Berrange {
254*195e14d0SDaniel P. Berrange     QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
255*195e14d0SDaniel P. Berrange     ssize_t ret;
256*195e14d0SDaniel P. Berrange 
257*195e14d0SDaniel P. Berrange  retry:
258*195e14d0SDaniel P. Berrange     ret = writev(cioc->writefd, iov, niov);
259*195e14d0SDaniel P. Berrange     if (ret <= 0) {
260*195e14d0SDaniel P. Berrange         if (errno == EAGAIN ||
261*195e14d0SDaniel P. Berrange             errno == EWOULDBLOCK) {
262*195e14d0SDaniel P. Berrange             return QIO_CHANNEL_ERR_BLOCK;
263*195e14d0SDaniel P. Berrange         }
264*195e14d0SDaniel P. Berrange         if (errno == EINTR) {
265*195e14d0SDaniel P. Berrange             goto retry;
266*195e14d0SDaniel P. Berrange         }
267*195e14d0SDaniel P. Berrange         error_setg_errno(errp, errno, "%s",
268*195e14d0SDaniel P. Berrange                          "Unable to write to command");
269*195e14d0SDaniel P. Berrange         return -1;
270*195e14d0SDaniel P. Berrange     }
271*195e14d0SDaniel P. Berrange     return ret;
272*195e14d0SDaniel P. Berrange }
273*195e14d0SDaniel P. Berrange 
274*195e14d0SDaniel P. Berrange static int qio_channel_command_set_blocking(QIOChannel *ioc,
275*195e14d0SDaniel P. Berrange                                             bool enabled,
276*195e14d0SDaniel P. Berrange                                             Error **errp)
277*195e14d0SDaniel P. Berrange {
278*195e14d0SDaniel P. Berrange     QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
279*195e14d0SDaniel P. Berrange 
280*195e14d0SDaniel P. Berrange     if (enabled) {
281*195e14d0SDaniel P. Berrange         qemu_set_block(cioc->writefd);
282*195e14d0SDaniel P. Berrange         qemu_set_block(cioc->readfd);
283*195e14d0SDaniel P. Berrange     } else {
284*195e14d0SDaniel P. Berrange         qemu_set_nonblock(cioc->writefd);
285*195e14d0SDaniel P. Berrange         qemu_set_nonblock(cioc->readfd);
286*195e14d0SDaniel P. Berrange     }
287*195e14d0SDaniel P. Berrange 
288*195e14d0SDaniel P. Berrange     return 0;
289*195e14d0SDaniel P. Berrange }
290*195e14d0SDaniel P. Berrange 
291*195e14d0SDaniel P. Berrange 
292*195e14d0SDaniel P. Berrange static int qio_channel_command_close(QIOChannel *ioc,
293*195e14d0SDaniel P. Berrange                                      Error **errp)
294*195e14d0SDaniel P. Berrange {
295*195e14d0SDaniel P. Berrange     QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
296*195e14d0SDaniel P. Berrange     int rv = 0;
297*195e14d0SDaniel P. Berrange 
298*195e14d0SDaniel P. Berrange     /* We close FDs before killing, because that
299*195e14d0SDaniel P. Berrange      * gives a better chance of clean shutdown
300*195e14d0SDaniel P. Berrange      */
301*195e14d0SDaniel P. Berrange     if (close(cioc->writefd) < 0) {
302*195e14d0SDaniel P. Berrange         rv = -1;
303*195e14d0SDaniel P. Berrange     }
304*195e14d0SDaniel P. Berrange     if (close(cioc->readfd) < 0) {
305*195e14d0SDaniel P. Berrange         rv = -1;
306*195e14d0SDaniel P. Berrange     }
307*195e14d0SDaniel P. Berrange #ifndef WIN32
308*195e14d0SDaniel P. Berrange     if (qio_channel_command_abort(cioc, errp) < 0) {
309*195e14d0SDaniel P. Berrange         return -1;
310*195e14d0SDaniel P. Berrange     }
311*195e14d0SDaniel P. Berrange #endif
312*195e14d0SDaniel P. Berrange     if (rv < 0) {
313*195e14d0SDaniel P. Berrange         error_setg_errno(errp, errno, "%s",
314*195e14d0SDaniel P. Berrange                          "Unable to close command");
315*195e14d0SDaniel P. Berrange     }
316*195e14d0SDaniel P. Berrange     return rv;
317*195e14d0SDaniel P. Berrange }
318*195e14d0SDaniel P. Berrange 
319*195e14d0SDaniel P. Berrange 
320*195e14d0SDaniel P. Berrange static GSource *qio_channel_command_create_watch(QIOChannel *ioc,
321*195e14d0SDaniel P. Berrange                                                  GIOCondition condition)
322*195e14d0SDaniel P. Berrange {
323*195e14d0SDaniel P. Berrange     QIOChannelCommand *cioc = QIO_CHANNEL_COMMAND(ioc);
324*195e14d0SDaniel P. Berrange     return qio_channel_create_fd_pair_watch(ioc,
325*195e14d0SDaniel P. Berrange                                             cioc->readfd,
326*195e14d0SDaniel P. Berrange                                             cioc->writefd,
327*195e14d0SDaniel P. Berrange                                             condition);
328*195e14d0SDaniel P. Berrange }
329*195e14d0SDaniel P. Berrange 
330*195e14d0SDaniel P. Berrange 
331*195e14d0SDaniel P. Berrange static void qio_channel_command_class_init(ObjectClass *klass,
332*195e14d0SDaniel P. Berrange                                            void *class_data G_GNUC_UNUSED)
333*195e14d0SDaniel P. Berrange {
334*195e14d0SDaniel P. Berrange     QIOChannelClass *ioc_klass = QIO_CHANNEL_CLASS(klass);
335*195e14d0SDaniel P. Berrange 
336*195e14d0SDaniel P. Berrange     ioc_klass->io_writev = qio_channel_command_writev;
337*195e14d0SDaniel P. Berrange     ioc_klass->io_readv = qio_channel_command_readv;
338*195e14d0SDaniel P. Berrange     ioc_klass->io_set_blocking = qio_channel_command_set_blocking;
339*195e14d0SDaniel P. Berrange     ioc_klass->io_close = qio_channel_command_close;
340*195e14d0SDaniel P. Berrange     ioc_klass->io_create_watch = qio_channel_command_create_watch;
341*195e14d0SDaniel P. Berrange }
342*195e14d0SDaniel P. Berrange 
343*195e14d0SDaniel P. Berrange static const TypeInfo qio_channel_command_info = {
344*195e14d0SDaniel P. Berrange     .parent = TYPE_QIO_CHANNEL,
345*195e14d0SDaniel P. Berrange     .name = TYPE_QIO_CHANNEL_COMMAND,
346*195e14d0SDaniel P. Berrange     .instance_size = sizeof(QIOChannelCommand),
347*195e14d0SDaniel P. Berrange     .instance_init = qio_channel_command_init,
348*195e14d0SDaniel P. Berrange     .instance_finalize = qio_channel_command_finalize,
349*195e14d0SDaniel P. Berrange     .class_init = qio_channel_command_class_init,
350*195e14d0SDaniel P. Berrange };
351*195e14d0SDaniel P. Berrange 
352*195e14d0SDaniel P. Berrange static void qio_channel_command_register_types(void)
353*195e14d0SDaniel P. Berrange {
354*195e14d0SDaniel P. Berrange     type_register_static(&qio_channel_command_info);
355*195e14d0SDaniel P. Berrange }
356*195e14d0SDaniel P. Berrange 
357*195e14d0SDaniel P. Berrange type_init(qio_channel_command_register_types);
358