Added query mode to virt-inspector.
[libguestfs.git] / daemon / proto.c
1 /* libguestfs - the guestfsd daemon
2  * Copyright (C) 2009 Red Hat Inc. 
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <config.h>
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <stdarg.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <errno.h>
27 #include <ctype.h>
28 #include <sys/param.h>          /* defines MIN */
29 #include <rpc/types.h>
30 #include <rpc/xdr.h>
31
32 #include "daemon.h"
33 #include "../src/guestfs_protocol.h"
34
35 /* The message currently being processed. */
36 int proc_nr;
37 int serial;
38
39 /* The daemon communications socket. */
40 static int sock;
41
42 void
43 main_loop (int _sock)
44 {
45   XDR xdr;
46   char *buf;
47   char lenbuf[4];
48   unsigned len;
49   struct guestfs_message_header hdr;
50
51   sock = _sock;
52
53   for (;;) {
54 #if 0
55     /* Most common errors are leaked memory and leaked file descriptors,
56      * so run this between each command:
57      */
58     if (verbose)
59       system ("ls -l /proc/self/fd");
60 #endif
61
62     /* Read the length word. */
63     xread (sock, lenbuf, 4);
64     xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
65     xdr_uint32_t (&xdr, &len);
66     xdr_destroy (&xdr);
67
68     if (len > GUESTFS_MESSAGE_MAX) {
69       fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
70                len);
71       exit (1);
72     }
73
74     buf = malloc (len);
75     if (!buf) {
76       reply_with_perror ("malloc");
77       continue;
78     }
79
80     xread (sock, buf, len);
81
82 #if 0
83     if (verbose) {
84       int i, j;
85
86       for (i = 0; i < len; i += 16) {
87         printf ("%04x: ", i);
88         for (j = i; j < MIN (i+16, len); ++j)
89           printf ("%02x ", (unsigned char) buf[j]);
90         for (; j < i+16; ++j)
91           printf ("   ");
92         printf ("|");
93         for (j = i; j < MIN (i+16, len); ++j)
94           if (isprint (buf[j]))
95             printf ("%c", buf[j]);
96           else
97             printf (".");
98         for (; j < i+16; ++j)
99           printf (" ");
100         printf ("|\n");
101       }
102     }
103 #endif
104
105     /* Decode the message header. */
106     xdrmem_create (&xdr, buf, len, XDR_DECODE);
107     if (!xdr_guestfs_message_header (&xdr, &hdr)) {
108       fprintf (stderr, "guestfsd: could not decode message header\n");
109       exit (1);
110     }
111
112     /* Check the version etc. */
113     if (hdr.prog != GUESTFS_PROGRAM) {
114       reply_with_error ("wrong program (%d)", hdr.prog);
115       goto cont;
116     }
117     if (hdr.vers != GUESTFS_PROTOCOL_VERSION) {
118       reply_with_error ("wrong protocol version (%d)", hdr.vers);
119       goto cont;
120     }
121     if (hdr.direction != GUESTFS_DIRECTION_CALL) {
122       reply_with_error ("unexpected message direction (%d)", hdr.direction);
123       goto cont;
124     }
125     if (hdr.status != GUESTFS_STATUS_OK) {
126       reply_with_error ("unexpected message status (%d)", hdr.status);
127       goto cont;
128     }
129
130     /* Now start to process this message. */
131     proc_nr = hdr.proc;
132     serial = hdr.serial;
133     dispatch_incoming_message (&xdr);
134     /* Note that dispatch_incoming_message will also send a reply. */
135
136   cont:
137     xdr_destroy (&xdr);
138     free (buf);
139   }
140 }
141
142 static void send_error (const char *msg);
143
144 void
145 reply_with_error (const char *fs, ...)
146 {
147   char err[GUESTFS_ERROR_LEN];
148   va_list args;
149
150   va_start (args, fs);
151   vsnprintf (err, sizeof err, fs, args);
152   va_end (args);
153
154   send_error (err);
155 }
156
157 void
158 reply_with_perror (const char *fs, ...)
159 {
160   char buf1[GUESTFS_ERROR_LEN];
161   char buf2[GUESTFS_ERROR_LEN];
162   va_list args;
163   int err = errno;
164
165   va_start (args, fs);
166   vsnprintf (buf1, sizeof buf1, fs, args);
167   va_end (args);
168
169   snprintf (buf2, sizeof buf2, "%s: %s", buf1, strerror (err));
170
171   send_error (buf2);
172 }
173
174 static void
175 send_error (const char *msg)
176 {
177   XDR xdr;
178   char buf[GUESTFS_ERROR_LEN + 200];
179   char lenbuf[4];
180   struct guestfs_message_header hdr;
181   struct guestfs_message_error err;
182   unsigned len;
183
184   fprintf (stderr, "guestfsd: error: %s\n", msg);
185
186   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
187
188   hdr.prog = GUESTFS_PROGRAM;
189   hdr.vers = GUESTFS_PROTOCOL_VERSION;
190   hdr.direction = GUESTFS_DIRECTION_REPLY;
191   hdr.status = GUESTFS_STATUS_ERROR;
192   hdr.proc = proc_nr;
193   hdr.serial = serial;
194
195   if (!xdr_guestfs_message_header (&xdr, &hdr)) {
196     fprintf (stderr, "guestfsd: failed to encode error message header\n");
197     exit (1);
198   }
199
200   err.error_message = (char *) msg;
201
202   if (!xdr_guestfs_message_error (&xdr, &err)) {
203     fprintf (stderr, "guestfsd: failed to encode error message body\n");
204     exit (1);
205   }
206
207   len = xdr_getpos (&xdr);
208   xdr_destroy (&xdr);
209
210   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
211   xdr_uint32_t (&xdr, &len);
212   xdr_destroy (&xdr);
213
214   if (xwrite (sock, lenbuf, 4) == -1) {
215     fprintf (stderr, "xwrite failed\n");
216     exit (1);
217   }
218   if (xwrite (sock, buf, len) == -1) {
219     fprintf (stderr, "xwrite failed\n");
220     exit (1);
221   }
222 }
223
224 void
225 reply (xdrproc_t xdrp, char *ret)
226 {
227   XDR xdr;
228   char buf[GUESTFS_MESSAGE_MAX];
229   char lenbuf[4];
230   struct guestfs_message_header hdr;
231   unsigned len;
232
233   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
234
235   hdr.prog = GUESTFS_PROGRAM;
236   hdr.vers = GUESTFS_PROTOCOL_VERSION;
237   hdr.direction = GUESTFS_DIRECTION_REPLY;
238   hdr.status = GUESTFS_STATUS_OK;
239   hdr.proc = proc_nr;
240   hdr.serial = serial;
241
242   if (!xdr_guestfs_message_header (&xdr, &hdr)) {
243     fprintf (stderr, "guestfsd: failed to encode reply header\n");
244     exit (1);
245   }
246
247   if (xdrp) {
248     if (!(*xdrp) (&xdr, ret)) {
249       fprintf (stderr, "guestfsd: failed to encode reply body\n");
250       exit (1);
251     }
252   }
253
254   len = xdr_getpos (&xdr);
255   xdr_destroy (&xdr);
256
257   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
258   xdr_uint32_t (&xdr, &len);
259   xdr_destroy (&xdr);
260
261   if (xwrite (sock, lenbuf, 4) == -1) {
262     fprintf (stderr, "xwrite failed\n");
263     exit (1);
264   }
265   if (xwrite (sock, buf, len) == len) {
266     fprintf (stderr, "xwrite failed\n");
267     exit (1);
268   }
269 }
270
271 /* Receive file chunks, repeatedly calling 'cb'. */
272 int
273 receive_file (receive_cb cb, void *opaque)
274 {
275   guestfs_chunk chunk;
276   char lenbuf[4];
277   char *buf;
278   XDR xdr;
279   int r;
280   uint32_t len;
281
282   for (;;) {
283     /* Read the length word. */
284     xread (sock, lenbuf, 4);
285     xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
286     xdr_uint32_t (&xdr, &len);
287     xdr_destroy (&xdr);
288
289     if (len == GUESTFS_CANCEL_FLAG)
290       continue;                 /* Just ignore it. */
291
292     if (len > GUESTFS_MESSAGE_MAX) {
293       fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
294                len);
295       exit (1);
296     }
297
298     buf = malloc (len);
299     if (!buf) {
300       perror ("malloc");
301       return -1;
302     }
303
304     xread (sock, buf, len);
305
306     xdrmem_create (&xdr, buf, len, XDR_DECODE);
307     memset (&chunk, 0, sizeof chunk);
308     if (!xdr_guestfs_chunk (&xdr, &chunk)) {
309       xdr_destroy (&xdr);
310       free (buf);
311       return -1;
312     }
313     xdr_destroy (&xdr);
314     free (buf);
315
316     if (verbose)
317       printf ("receive_file: got chunk: cancel = %d, len = %d, buf = %p\n",
318               chunk.cancel, chunk.data.data_len, chunk.data.data_val);
319
320     if (chunk.cancel) {
321       fprintf (stderr, "receive_file: received cancellation from library\n");
322       xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
323       return -2;
324     }
325     if (chunk.data.data_len == 0) {
326       xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
327       return 0;                 /* end of file */
328     }
329
330     if (cb)
331       r = cb (opaque, chunk.data.data_val, chunk.data.data_len);
332     else
333       r = 0;
334
335     xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
336     if (r == -1)                /* write error */
337       return -1;
338   }
339 }
340
341 /* Send a cancellation flag back to the library. */
342 void
343 cancel_receive (void)
344 {
345   XDR xdr;
346   char fbuf[4];
347   uint32_t flag = GUESTFS_CANCEL_FLAG;
348
349   xdrmem_create (&xdr, fbuf, sizeof fbuf, XDR_ENCODE);
350   xdr_uint32_t (&xdr, &flag);
351   xdr_destroy (&xdr);
352
353   if (xwrite (sock, fbuf, sizeof fbuf) == -1) {
354     perror ("write to socket");
355     return;
356   }
357
358   /* Keep receiving chunks and discarding, until library sees cancel. */
359   (void) receive_file (NULL, NULL);
360 }
361
362 static int check_for_library_cancellation (void);
363 static int send_chunk (const guestfs_chunk *);
364
365 /* Also check if the library sends us a cancellation message. */
366 int
367 send_file_write (const void *buf, int len)
368 {
369   guestfs_chunk chunk;
370   int cancel;
371
372   if (len > GUESTFS_MAX_CHUNK_SIZE) {
373     fprintf (stderr, "send_file_write: len (%d) > GUESTFS_MAX_CHUNK_SIZE (%d)\n",
374              len, GUESTFS_MAX_CHUNK_SIZE);
375     return -1;
376   }
377
378   cancel = check_for_library_cancellation ();
379
380   if (cancel) {
381     chunk.cancel = 1;
382     chunk.data.data_len = 0;
383     chunk.data.data_val = NULL;
384   } else {
385     chunk.cancel = 0;
386     chunk.data.data_len = len;
387     chunk.data.data_val = (char *) buf;
388   }
389
390   if (send_chunk (&chunk) == -1)
391     return -1;
392
393   if (cancel) return -2;
394   return 0;
395 }
396
397 static int
398 check_for_library_cancellation (void)
399 {
400   fd_set rset;
401   struct timeval tv;
402   int r;
403   char buf[4];
404   uint32_t flag;
405   XDR xdr;
406
407   FD_ZERO (&rset);
408   FD_SET (sock, &rset);
409   tv.tv_sec = 0;
410   tv.tv_usec = 0;
411   r = select (sock+1, &rset, NULL, NULL, &tv);
412   if (r == -1) {
413     perror ("select");
414     return 0;
415   }
416   if (r == 0)
417     return 0;
418
419   /* Read the message from the daemon. */
420   r = xread (sock, buf, sizeof buf);
421   if (r == -1) {
422     perror ("read");
423     return 0;
424   }
425
426   xdrmem_create (&xdr, buf, sizeof buf, XDR_DECODE);
427   xdr_uint32_t (&xdr, &flag);
428   xdr_destroy (&xdr);
429
430   if (flag != GUESTFS_CANCEL_FLAG) {
431     fprintf (stderr, "check_for_library_cancellation: read 0x%x from library, expected 0x%x\n",
432              flag, GUESTFS_CANCEL_FLAG);
433     return 0;
434   }
435
436   return 1;
437 }
438
439 void
440 send_file_end (int cancel)
441 {
442   guestfs_chunk chunk;
443
444   chunk.cancel = cancel;
445   chunk.data.data_len = 0;
446   chunk.data.data_val = NULL;
447   send_chunk (&chunk);
448 }
449
450 static int
451 send_chunk (const guestfs_chunk *chunk)
452 {
453   char buf[GUESTFS_MAX_CHUNK_SIZE + 48];
454   char lenbuf[4];
455   XDR xdr;
456   uint32_t len;
457
458   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
459   if (!xdr_guestfs_chunk (&xdr, (guestfs_chunk *) chunk)) {
460     fprintf (stderr, "send_chunk: failed to encode chunk\n");
461     xdr_destroy (&xdr);
462     return -1;
463   }
464
465   len = xdr_getpos (&xdr);
466   xdr_destroy (&xdr);
467
468   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
469   xdr_uint32_t (&xdr, &len);
470   xdr_destroy (&xdr);
471
472   (void) xwrite (sock, lenbuf, 4);
473   (void) xwrite (sock, buf, len);
474
475   return 0;
476 }