'len' should be an unsigned 32 bit int.
[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   uint32_t len;
49   struct guestfs_message_header hdr;
50   struct timeval start_t, end_t;
51   int64_t start_us, end_us, elapsed_us;
52
53   sock = _sock;
54
55   for (;;) {
56 #if 0
57     /* Most common errors are leaked memory and leaked file descriptors,
58      * so run this between each command:
59      */
60     if (verbose)
61       system ("ls -l /proc/self/fd");
62 #endif
63
64     /* Read the length word. */
65     xread (sock, lenbuf, 4);
66     xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
67     xdr_uint32_t (&xdr, &len);
68     xdr_destroy (&xdr);
69
70     if (len > GUESTFS_MESSAGE_MAX) {
71       fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
72                len);
73       exit (1);
74     }
75
76     buf = malloc (len);
77     if (!buf) {
78       reply_with_perror ("malloc");
79       continue;
80     }
81
82     xread (sock, buf, len);
83
84 #if 0
85     if (verbose) {
86       int i, j;
87
88       for (i = 0; i < len; i += 16) {
89         printf ("%04x: ", i);
90         for (j = i; j < MIN (i+16, len); ++j)
91           printf ("%02x ", (unsigned char) buf[j]);
92         for (; j < i+16; ++j)
93           printf ("   ");
94         printf ("|");
95         for (j = i; j < MIN (i+16, len); ++j)
96           if (isprint (buf[j]))
97             printf ("%c", buf[j]);
98           else
99             printf (".");
100         for (; j < i+16; ++j)
101           printf (" ");
102         printf ("|\n");
103       }
104     }
105 #endif
106
107     /* In verbose mode, display the time taken to run each command. */
108     if (verbose)
109       gettimeofday (&start_t, NULL);
110
111     /* Decode the message header. */
112     xdrmem_create (&xdr, buf, len, XDR_DECODE);
113     if (!xdr_guestfs_message_header (&xdr, &hdr)) {
114       fprintf (stderr, "guestfsd: could not decode message header\n");
115       exit (1);
116     }
117
118     /* Check the version etc. */
119     if (hdr.prog != GUESTFS_PROGRAM) {
120       reply_with_error ("wrong program (%d)", hdr.prog);
121       goto cont;
122     }
123     if (hdr.vers != GUESTFS_PROTOCOL_VERSION) {
124       reply_with_error ("wrong protocol version (%d)", hdr.vers);
125       goto cont;
126     }
127     if (hdr.direction != GUESTFS_DIRECTION_CALL) {
128       reply_with_error ("unexpected message direction (%d)", hdr.direction);
129       goto cont;
130     }
131     if (hdr.status != GUESTFS_STATUS_OK) {
132       reply_with_error ("unexpected message status (%d)", hdr.status);
133       goto cont;
134     }
135
136     /* Now start to process this message. */
137     proc_nr = hdr.proc;
138     serial = hdr.serial;
139     dispatch_incoming_message (&xdr);
140     /* Note that dispatch_incoming_message will also send a reply. */
141
142     /* In verbose mode, display the time taken to run each command. */
143     if (verbose) {
144       gettimeofday (&end_t, NULL);
145
146       start_us = (int64_t) start_t.tv_sec * 1000000 + start_t.tv_usec;
147       end_us = (int64_t) end_t.tv_sec * 1000000 + end_t.tv_usec;
148       elapsed_us = end_us - start_us;
149       fprintf (stderr, "proc %d (%s) took %d.%02d seconds\n",
150                proc_nr,
151                proc_nr >= 0 && proc_nr < GUESTFS_PROC_NR_PROCS
152                ? function_names[proc_nr] : "UNKNOWN PROCEDURE",
153                (int) (elapsed_us / 1000000),
154                (int) ((elapsed_us / 10000) % 100));
155     }
156
157   cont:
158     xdr_destroy (&xdr);
159     free (buf);
160   }
161 }
162
163 static void send_error (const char *msg);
164
165 void
166 reply_with_error (const char *fs, ...)
167 {
168   char err[GUESTFS_ERROR_LEN];
169   va_list args;
170
171   va_start (args, fs);
172   vsnprintf (err, sizeof err, fs, args);
173   va_end (args);
174
175   send_error (err);
176 }
177
178 void
179 reply_with_perror (const char *fs, ...)
180 {
181   char buf1[GUESTFS_ERROR_LEN];
182   char buf2[GUESTFS_ERROR_LEN];
183   va_list args;
184   int err = errno;
185
186   va_start (args, fs);
187   vsnprintf (buf1, sizeof buf1, fs, args);
188   va_end (args);
189
190   snprintf (buf2, sizeof buf2, "%s: %s", buf1, strerror (err));
191
192   send_error (buf2);
193 }
194
195 static void
196 send_error (const char *msg)
197 {
198   XDR xdr;
199   char buf[GUESTFS_ERROR_LEN + 200];
200   char lenbuf[4];
201   struct guestfs_message_header hdr;
202   struct guestfs_message_error err;
203   unsigned len;
204
205   fprintf (stderr, "guestfsd: error: %s\n", msg);
206
207   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
208
209   hdr.prog = GUESTFS_PROGRAM;
210   hdr.vers = GUESTFS_PROTOCOL_VERSION;
211   hdr.direction = GUESTFS_DIRECTION_REPLY;
212   hdr.status = GUESTFS_STATUS_ERROR;
213   hdr.proc = proc_nr;
214   hdr.serial = serial;
215
216   if (!xdr_guestfs_message_header (&xdr, &hdr)) {
217     fprintf (stderr, "guestfsd: failed to encode error message header\n");
218     exit (1);
219   }
220
221   err.error_message = (char *) msg;
222
223   if (!xdr_guestfs_message_error (&xdr, &err)) {
224     fprintf (stderr, "guestfsd: failed to encode error message body\n");
225     exit (1);
226   }
227
228   len = xdr_getpos (&xdr);
229   xdr_destroy (&xdr);
230
231   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
232   xdr_uint32_t (&xdr, &len);
233   xdr_destroy (&xdr);
234
235   if (xwrite (sock, lenbuf, 4) == -1) {
236     fprintf (stderr, "xwrite failed\n");
237     exit (1);
238   }
239   if (xwrite (sock, buf, len) == -1) {
240     fprintf (stderr, "xwrite failed\n");
241     exit (1);
242   }
243 }
244
245 void
246 reply (xdrproc_t xdrp, char *ret)
247 {
248   XDR xdr;
249   char buf[GUESTFS_MESSAGE_MAX];
250   char lenbuf[4];
251   struct guestfs_message_header hdr;
252   unsigned len;
253
254   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
255
256   hdr.prog = GUESTFS_PROGRAM;
257   hdr.vers = GUESTFS_PROTOCOL_VERSION;
258   hdr.direction = GUESTFS_DIRECTION_REPLY;
259   hdr.status = GUESTFS_STATUS_OK;
260   hdr.proc = proc_nr;
261   hdr.serial = serial;
262
263   if (!xdr_guestfs_message_header (&xdr, &hdr)) {
264     fprintf (stderr, "guestfsd: failed to encode reply header\n");
265     exit (1);
266   }
267
268   if (xdrp) {
269     /* This can fail if the reply body is too large, for example
270      * if it exceeds the maximum message size.  In that case
271      * we want to return an error message instead. (RHBZ#509597).
272      */
273     if (!(*xdrp) (&xdr, ret)) {
274       reply_with_perror ("guestfsd: failed to encode reply body\n");
275       xdr_destroy (&xdr);
276       return;
277     }
278   }
279
280   len = xdr_getpos (&xdr);
281   xdr_destroy (&xdr);
282
283   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
284   xdr_uint32_t (&xdr, &len);
285   xdr_destroy (&xdr);
286
287   if (xwrite (sock, lenbuf, 4) == -1) {
288     fprintf (stderr, "xwrite failed\n");
289     exit (1);
290   }
291   if (xwrite (sock, buf, len) == -1) {
292     fprintf (stderr, "xwrite failed\n");
293     exit (1);
294   }
295 }
296
297 /* Receive file chunks, repeatedly calling 'cb'. */
298 int
299 receive_file (receive_cb cb, void *opaque)
300 {
301   guestfs_chunk chunk;
302   char lenbuf[4];
303   char *buf;
304   XDR xdr;
305   int r;
306   uint32_t len;
307
308   for (;;) {
309     /* Read the length word. */
310     xread (sock, lenbuf, 4);
311     xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
312     xdr_uint32_t (&xdr, &len);
313     xdr_destroy (&xdr);
314
315     if (len == GUESTFS_CANCEL_FLAG)
316       continue;                 /* Just ignore it. */
317
318     if (len > GUESTFS_MESSAGE_MAX) {
319       fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
320                len);
321       exit (1);
322     }
323
324     buf = malloc (len);
325     if (!buf) {
326       perror ("malloc");
327       return -1;
328     }
329
330     xread (sock, buf, len);
331
332     xdrmem_create (&xdr, buf, len, XDR_DECODE);
333     memset (&chunk, 0, sizeof chunk);
334     if (!xdr_guestfs_chunk (&xdr, &chunk)) {
335       xdr_destroy (&xdr);
336       free (buf);
337       return -1;
338     }
339     xdr_destroy (&xdr);
340     free (buf);
341
342     if (verbose)
343       printf ("receive_file: got chunk: cancel = %d, len = %d, buf = %p\n",
344               chunk.cancel, chunk.data.data_len, chunk.data.data_val);
345
346     if (chunk.cancel) {
347       fprintf (stderr, "receive_file: received cancellation from library\n");
348       xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
349       return -2;
350     }
351     if (chunk.data.data_len == 0) {
352       xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
353       return 0;                 /* end of file */
354     }
355
356     if (cb)
357       r = cb (opaque, chunk.data.data_val, chunk.data.data_len);
358     else
359       r = 0;
360
361     xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
362     if (r == -1)                /* write error */
363       return -1;
364   }
365 }
366
367 /* Send a cancellation flag back to the library. */
368 void
369 cancel_receive (void)
370 {
371   XDR xdr;
372   char fbuf[4];
373   uint32_t flag = GUESTFS_CANCEL_FLAG;
374
375   xdrmem_create (&xdr, fbuf, sizeof fbuf, XDR_ENCODE);
376   xdr_uint32_t (&xdr, &flag);
377   xdr_destroy (&xdr);
378
379   if (xwrite (sock, fbuf, sizeof fbuf) == -1) {
380     perror ("write to socket");
381     return;
382   }
383
384   /* Keep receiving chunks and discarding, until library sees cancel. */
385   (void) receive_file (NULL, NULL);
386 }
387
388 static int check_for_library_cancellation (void);
389 static int send_chunk (const guestfs_chunk *);
390
391 /* Also check if the library sends us a cancellation message. */
392 int
393 send_file_write (const void *buf, int len)
394 {
395   guestfs_chunk chunk;
396   int cancel;
397
398   if (len > GUESTFS_MAX_CHUNK_SIZE) {
399     fprintf (stderr, "send_file_write: len (%d) > GUESTFS_MAX_CHUNK_SIZE (%d)\n",
400              len, GUESTFS_MAX_CHUNK_SIZE);
401     return -1;
402   }
403
404   cancel = check_for_library_cancellation ();
405
406   if (cancel) {
407     chunk.cancel = 1;
408     chunk.data.data_len = 0;
409     chunk.data.data_val = NULL;
410   } else {
411     chunk.cancel = 0;
412     chunk.data.data_len = len;
413     chunk.data.data_val = (char *) buf;
414   }
415
416   if (send_chunk (&chunk) == -1)
417     return -1;
418
419   if (cancel) return -2;
420   return 0;
421 }
422
423 static int
424 check_for_library_cancellation (void)
425 {
426   fd_set rset;
427   struct timeval tv;
428   int r;
429   char buf[4];
430   uint32_t flag;
431   XDR xdr;
432
433   FD_ZERO (&rset);
434   FD_SET (sock, &rset);
435   tv.tv_sec = 0;
436   tv.tv_usec = 0;
437   r = select (sock+1, &rset, NULL, NULL, &tv);
438   if (r == -1) {
439     perror ("select");
440     return 0;
441   }
442   if (r == 0)
443     return 0;
444
445   /* Read the message from the daemon. */
446   r = xread (sock, buf, sizeof buf);
447   if (r == -1) {
448     perror ("read");
449     return 0;
450   }
451
452   xdrmem_create (&xdr, buf, sizeof buf, XDR_DECODE);
453   xdr_uint32_t (&xdr, &flag);
454   xdr_destroy (&xdr);
455
456   if (flag != GUESTFS_CANCEL_FLAG) {
457     fprintf (stderr, "check_for_library_cancellation: read 0x%x from library, expected 0x%x\n",
458              flag, GUESTFS_CANCEL_FLAG);
459     return 0;
460   }
461
462   return 1;
463 }
464
465 int
466 send_file_end (int cancel)
467 {
468   guestfs_chunk chunk;
469
470   chunk.cancel = cancel;
471   chunk.data.data_len = 0;
472   chunk.data.data_val = NULL;
473   return send_chunk (&chunk);
474 }
475
476 static int
477 send_chunk (const guestfs_chunk *chunk)
478 {
479   char buf[GUESTFS_MAX_CHUNK_SIZE + 48];
480   char lenbuf[4];
481   XDR xdr;
482   uint32_t len;
483
484   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
485   if (!xdr_guestfs_chunk (&xdr, (guestfs_chunk *) chunk)) {
486     fprintf (stderr, "send_chunk: failed to encode chunk\n");
487     xdr_destroy (&xdr);
488     return -1;
489   }
490
491   len = xdr_getpos (&xdr);
492   xdr_destroy (&xdr);
493
494   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
495   xdr_uint32_t (&xdr, &len);
496   xdr_destroy (&xdr);
497
498   int err = (xwrite (sock, lenbuf, 4) == 0
499              && xwrite (sock, buf, len) == 0 ? 0 : -1);
500   if (err) {
501     fprintf (stderr, "send_chunk: write failed\n");
502     exit (1);
503   }
504
505   return err;
506 }