Disable test for RHBZ#576879 comment 5.
[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 <sys/param.h>          /* defines MIN */
28 #include <sys/select.h>
29 #include <sys/time.h>
30 #include <rpc/types.h>
31 #include <rpc/xdr.h>
32
33 #ifdef HAVE_WINDOWS_H
34 #include <windows.h>
35 #endif
36
37 #include "c-ctype.h"
38 #include "ignore-value.h"
39
40 #include "daemon.h"
41 #include "../src/guestfs_protocol.h"
42
43 /* The message currently being processed. */
44 int proc_nr;
45 int serial;
46
47 /* Time at which we received the current request. */
48 static struct timeval start_t;
49
50 /* Time at which the last progress notification was sent. */
51 static struct timeval last_progress_t;
52
53 /* Counts the number of progress notifications sent during this call. */
54 static int count_progress;
55
56 /* The daemon communications socket. */
57 static int sock;
58
59 void
60 main_loop (int _sock)
61 {
62   XDR xdr;
63   char *buf;
64   char lenbuf[4];
65   uint32_t len;
66   struct guestfs_message_header hdr;
67
68   sock = _sock;
69
70   for (;;) {
71     /* Most common errors are leaked memory and leaked file descriptors,
72      * so run this between each command:
73      */
74     if (verbose && 0)
75       ignore_value (system ("ls -l /proc/self/fd"));
76
77     /* Read the length word. */
78     if (xread (sock, lenbuf, 4) == -1)
79       exit (EXIT_FAILURE);
80
81     xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
82     xdr_u_int (&xdr, &len);
83     xdr_destroy (&xdr);
84
85     if (len > GUESTFS_MESSAGE_MAX) {
86       fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
87                len);
88       exit (EXIT_FAILURE);
89     }
90
91     buf = malloc (len);
92     if (!buf) {
93       reply_with_perror ("malloc");
94       continue;
95     }
96
97     if (xread (sock, buf, len) == -1)
98       exit (EXIT_FAILURE);
99
100 #ifdef ENABLE_PACKET_DUMP
101     if (verbose) {
102       size_t i, j;
103
104       for (i = 0; i < len; i += 16) {
105         printf ("%04zx: ", i);
106         for (j = i; j < MIN (i+16, len); ++j)
107           printf ("%02x ", (unsigned char) buf[j]);
108         for (; j < i+16; ++j)
109           printf ("   ");
110         printf ("|");
111         for (j = i; j < MIN (i+16, len); ++j)
112           if (c_isprint (buf[j]))
113             printf ("%c", buf[j]);
114           else
115             printf (".");
116         for (; j < i+16; ++j)
117           printf (" ");
118         printf ("|\n");
119       }
120     }
121 #endif
122
123     gettimeofday (&start_t, NULL);
124     last_progress_t = start_t;
125     count_progress = 0;
126
127     /* Decode the message header. */
128     xdrmem_create (&xdr, buf, len, XDR_DECODE);
129     if (!xdr_guestfs_message_header (&xdr, &hdr)) {
130       fprintf (stderr, "guestfsd: could not decode message header\n");
131       exit (EXIT_FAILURE);
132     }
133
134     /* Check the version etc. */
135     if (hdr.prog != GUESTFS_PROGRAM) {
136       reply_with_error ("wrong program (%d)", hdr.prog);
137       goto cont;
138     }
139     if (hdr.vers != GUESTFS_PROTOCOL_VERSION) {
140       reply_with_error ("wrong protocol version (%d)", hdr.vers);
141       goto cont;
142     }
143     if (hdr.direction != GUESTFS_DIRECTION_CALL) {
144       reply_with_error ("unexpected message direction (%d)", hdr.direction);
145       goto cont;
146     }
147     if (hdr.status != GUESTFS_STATUS_OK) {
148       reply_with_error ("unexpected message status (%d)", hdr.status);
149       goto cont;
150     }
151
152     proc_nr = hdr.proc;
153     serial = hdr.serial;
154
155     /* Clear errors before we call the stub functions.  This is just
156      * to ensure that we can accurately report errors in cases where
157      * error handling paths don't set errno correctly.
158      */
159     errno = 0;
160 #ifdef WIN32
161     SetLastError (0);
162     WSASetLastError (0);
163 #endif
164
165     /* Now start to process this message. */
166     dispatch_incoming_message (&xdr);
167     /* Note that dispatch_incoming_message will also send a reply. */
168
169     /* In verbose mode, display the time taken to run each command. */
170     if (verbose) {
171       struct timeval end_t;
172       gettimeofday (&end_t, NULL);
173
174       int64_t start_us, end_us, elapsed_us;
175       start_us = (int64_t) start_t.tv_sec * 1000000 + start_t.tv_usec;
176       end_us = (int64_t) end_t.tv_sec * 1000000 + end_t.tv_usec;
177       elapsed_us = end_us - start_us;
178
179       fprintf (stderr, "proc %d (%s) took %d.%02d seconds\n",
180                proc_nr,
181                proc_nr >= 0 && proc_nr < GUESTFS_PROC_NR_PROCS
182                ? function_names[proc_nr] : "UNKNOWN PROCEDURE",
183                (int) (elapsed_us / 1000000),
184                (int) ((elapsed_us / 10000) % 100));
185     }
186
187   cont:
188     xdr_destroy (&xdr);
189     free (buf);
190   }
191 }
192
193 static void send_error (int errnum, const char *msg);
194
195 void
196 reply_with_error (const char *fs, ...)
197 {
198   char err[GUESTFS_ERROR_LEN];
199   va_list args;
200
201   va_start (args, fs);
202   vsnprintf (err, sizeof err, fs, args);
203   va_end (args);
204
205   send_error (0, err);
206 }
207
208 void
209 reply_with_perror_errno (int err, const char *fs, ...)
210 {
211   char buf1[GUESTFS_ERROR_LEN];
212   char buf2[GUESTFS_ERROR_LEN];
213   va_list args;
214
215   va_start (args, fs);
216   vsnprintf (buf1, sizeof buf1, fs, args);
217   va_end (args);
218
219   snprintf (buf2, sizeof buf2, "%s: %s", buf1, strerror (err));
220
221   send_error (err, buf2);
222 }
223
224 static void
225 send_error (int errnum, const char *msg)
226 {
227   XDR xdr;
228   char buf[GUESTFS_ERROR_LEN + 200];
229   char lenbuf[4];
230   struct guestfs_message_header hdr;
231   struct guestfs_message_error err;
232   unsigned len;
233
234   fprintf (stderr, "guestfsd: error: %s\n", msg);
235
236   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
237
238   hdr.prog = GUESTFS_PROGRAM;
239   hdr.vers = GUESTFS_PROTOCOL_VERSION;
240   hdr.direction = GUESTFS_DIRECTION_REPLY;
241   hdr.status = GUESTFS_STATUS_ERROR;
242   hdr.proc = proc_nr;
243   hdr.serial = serial;
244
245   if (!xdr_guestfs_message_header (&xdr, &hdr)) {
246     fprintf (stderr, "guestfsd: failed to encode error message header\n");
247     exit (EXIT_FAILURE);
248   }
249
250   err.linux_errno = errnum;
251   err.error_message = (char *) msg;
252
253   if (!xdr_guestfs_message_error (&xdr, &err)) {
254     fprintf (stderr, "guestfsd: failed to encode error message body\n");
255     exit (EXIT_FAILURE);
256   }
257
258   len = xdr_getpos (&xdr);
259   xdr_destroy (&xdr);
260
261   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
262   xdr_u_int (&xdr, &len);
263   xdr_destroy (&xdr);
264
265   if (xwrite (sock, lenbuf, 4) == -1) {
266     fprintf (stderr, "xwrite failed\n");
267     exit (EXIT_FAILURE);
268   }
269   if (xwrite (sock, buf, len) == -1) {
270     fprintf (stderr, "xwrite failed\n");
271     exit (EXIT_FAILURE);
272   }
273 }
274
275 void
276 reply (xdrproc_t xdrp, char *ret)
277 {
278   XDR xdr;
279   char buf[GUESTFS_MESSAGE_MAX];
280   char lenbuf[4];
281   struct guestfs_message_header hdr;
282   unsigned len;
283
284   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
285
286   hdr.prog = GUESTFS_PROGRAM;
287   hdr.vers = GUESTFS_PROTOCOL_VERSION;
288   hdr.direction = GUESTFS_DIRECTION_REPLY;
289   hdr.status = GUESTFS_STATUS_OK;
290   hdr.proc = proc_nr;
291   hdr.serial = serial;
292
293   if (!xdr_guestfs_message_header (&xdr, &hdr)) {
294     fprintf (stderr, "guestfsd: failed to encode reply header\n");
295     exit (EXIT_FAILURE);
296   }
297
298   if (xdrp) {
299     /* This can fail if the reply body is too large, for example
300      * if it exceeds the maximum message size.  In that case
301      * we want to return an error message instead. (RHBZ#509597).
302      */
303     if (!(*xdrp) (&xdr, ret)) {
304       reply_with_error ("guestfsd: failed to encode reply body\n(maybe the reply exceeds the maximum message size in the protocol?)");
305       xdr_destroy (&xdr);
306       return;
307     }
308   }
309
310   len = xdr_getpos (&xdr);
311   xdr_destroy (&xdr);
312
313   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
314   xdr_u_int (&xdr, &len);
315   xdr_destroy (&xdr);
316
317   if (xwrite (sock, lenbuf, 4) == -1) {
318     fprintf (stderr, "xwrite failed\n");
319     exit (EXIT_FAILURE);
320   }
321   if (xwrite (sock, buf, len) == -1) {
322     fprintf (stderr, "xwrite failed\n");
323     exit (EXIT_FAILURE);
324   }
325 }
326
327 /* Receive file chunks, repeatedly calling 'cb'. */
328 int
329 receive_file (receive_cb cb, void *opaque)
330 {
331   guestfs_chunk chunk;
332   char lenbuf[4];
333   char *buf;
334   XDR xdr;
335   int r;
336   uint32_t len;
337
338   for (;;) {
339     if (verbose)
340       fprintf (stderr, "receive_file: reading length word\n");
341
342     /* Read the length word. */
343     if (xread (sock, lenbuf, 4) == -1)
344       exit (EXIT_FAILURE);
345
346     xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
347     xdr_u_int (&xdr, &len);
348     xdr_destroy (&xdr);
349
350     if (len == GUESTFS_CANCEL_FLAG)
351       continue;                 /* Just ignore it. */
352
353     if (len > GUESTFS_MESSAGE_MAX) {
354       fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
355                len);
356       exit (EXIT_FAILURE);
357     }
358
359     buf = malloc (len);
360     if (!buf) {
361       perror ("malloc");
362       return -1;
363     }
364
365     if (xread (sock, buf, len) == -1)
366       exit (EXIT_FAILURE);
367
368     xdrmem_create (&xdr, buf, len, XDR_DECODE);
369     memset (&chunk, 0, sizeof chunk);
370     if (!xdr_guestfs_chunk (&xdr, &chunk)) {
371       xdr_destroy (&xdr);
372       free (buf);
373       return -1;
374     }
375     xdr_destroy (&xdr);
376     free (buf);
377
378     if (verbose)
379       fprintf (stderr, "receive_file: got chunk: cancel = %d, len = %d, buf = %p\n",
380                chunk.cancel, chunk.data.data_len, chunk.data.data_val);
381
382     if (chunk.cancel) {
383       if (verbose)
384         fprintf (stderr, "receive_file: received cancellation from library\n");
385       xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
386       return -2;
387     }
388     if (chunk.data.data_len == 0) {
389       if (verbose)
390         fprintf (stderr, "receive_file: end of file, leaving function\n");
391       xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
392       return 0;                 /* end of file */
393     }
394
395     if (cb)
396       r = cb (opaque, chunk.data.data_val, chunk.data.data_len);
397     else
398       r = 0;
399
400     xdr_free ((xdrproc_t) xdr_guestfs_chunk, (char *) &chunk);
401     if (r == -1) {              /* write error */
402       if (verbose)
403         fprintf (stderr, "receive_file: write error\n");
404       return -1;
405     }
406   }
407 }
408
409 /* Send a cancellation flag back to the library. */
410 int
411 cancel_receive (void)
412 {
413   XDR xdr;
414   char fbuf[4];
415   uint32_t flag = GUESTFS_CANCEL_FLAG;
416
417   xdrmem_create (&xdr, fbuf, sizeof fbuf, XDR_ENCODE);
418   xdr_u_int (&xdr, &flag);
419   xdr_destroy (&xdr);
420
421   if (xwrite (sock, fbuf, sizeof fbuf) == -1) {
422     perror ("write to socket");
423     return -1;
424   }
425
426   /* Keep receiving chunks and discarding, until library sees cancel. */
427   return receive_file (NULL, NULL);
428 }
429
430 static int check_for_library_cancellation (void);
431 static int send_chunk (const guestfs_chunk *);
432
433 /* Also check if the library sends us a cancellation message. */
434 int
435 send_file_write (const void *buf, int len)
436 {
437   guestfs_chunk chunk;
438   int cancel;
439
440   if (len > GUESTFS_MAX_CHUNK_SIZE) {
441     fprintf (stderr, "send_file_write: len (%d) > GUESTFS_MAX_CHUNK_SIZE (%d)\n",
442              len, GUESTFS_MAX_CHUNK_SIZE);
443     return -1;
444   }
445
446   cancel = check_for_library_cancellation ();
447
448   if (cancel) {
449     chunk.cancel = 1;
450     chunk.data.data_len = 0;
451     chunk.data.data_val = NULL;
452   } else {
453     chunk.cancel = 0;
454     chunk.data.data_len = len;
455     chunk.data.data_val = (char *) buf;
456   }
457
458   if (send_chunk (&chunk) == -1)
459     return -1;
460
461   if (cancel) return -2;
462   return 0;
463 }
464
465 static int
466 check_for_library_cancellation (void)
467 {
468   fd_set rset;
469   struct timeval tv;
470   int r;
471   char buf[4];
472   uint32_t flag;
473   XDR xdr;
474
475   FD_ZERO (&rset);
476   FD_SET (sock, &rset);
477   tv.tv_sec = 0;
478   tv.tv_usec = 0;
479   r = select (sock+1, &rset, NULL, NULL, &tv);
480   if (r == -1) {
481     perror ("select");
482     return 0;
483   }
484   if (r == 0)
485     return 0;
486
487   /* Read the message from the daemon. */
488   r = xread (sock, buf, sizeof buf);
489   if (r == -1)
490     return 0;
491
492   xdrmem_create (&xdr, buf, sizeof buf, XDR_DECODE);
493   xdr_u_int (&xdr, &flag);
494   xdr_destroy (&xdr);
495
496   if (flag != GUESTFS_CANCEL_FLAG) {
497     fprintf (stderr, "check_for_library_cancellation: read 0x%x from library, expected 0x%x\n",
498              flag, GUESTFS_CANCEL_FLAG);
499     return 0;
500   }
501
502   return 1;
503 }
504
505 int
506 send_file_end (int cancel)
507 {
508   guestfs_chunk chunk;
509
510   chunk.cancel = cancel;
511   chunk.data.data_len = 0;
512   chunk.data.data_val = NULL;
513   return send_chunk (&chunk);
514 }
515
516 static int
517 send_chunk (const guestfs_chunk *chunk)
518 {
519   char buf[GUESTFS_MAX_CHUNK_SIZE + 48];
520   char lenbuf[4];
521   XDR xdr;
522   uint32_t len;
523
524   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
525   if (!xdr_guestfs_chunk (&xdr, (guestfs_chunk *) chunk)) {
526     fprintf (stderr, "send_chunk: failed to encode chunk\n");
527     xdr_destroy (&xdr);
528     return -1;
529   }
530
531   len = xdr_getpos (&xdr);
532   xdr_destroy (&xdr);
533
534   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
535   xdr_u_int (&xdr, &len);
536   xdr_destroy (&xdr);
537
538   int err = (xwrite (sock, lenbuf, 4) == 0
539              && xwrite (sock, buf, len) == 0 ? 0 : -1);
540   if (err) {
541     fprintf (stderr, "send_chunk: write failed\n");
542     exit (EXIT_FAILURE);
543   }
544
545   return err;
546 }
547
548 /* Initial delay before sending notification messages, and
549  * the period at which we send them thereafter.  These times
550  * are in microseconds.
551  */
552 #define NOTIFICATION_INITIAL_DELAY 2000000
553 #define NOTIFICATION_PERIOD         333333
554
555 void
556 notify_progress (uint64_t position, uint64_t total)
557 {
558   struct timeval now_t;
559   gettimeofday (&now_t, NULL);
560
561   /* Always send a notification at 100%.  This simplifies callers by
562    * allowing them to 'finish' the progress bar at 100% without
563    * needing special code.
564    */
565   if (count_progress > 0 && position == total)
566     goto send;
567
568   /* Calculate time in microseconds since the last progress message
569    * was sent out (or since the start of the call).
570    */
571   int64_t last_us, now_us, elapsed_us;
572   last_us =
573     (int64_t) last_progress_t.tv_sec * 1000000 + last_progress_t.tv_usec;
574   now_us = (int64_t) now_t.tv_sec * 1000000 + now_t.tv_usec;
575   elapsed_us = now_us - last_us;
576
577   /* Rate limit. */
578   if ((count_progress == 0 && elapsed_us < NOTIFICATION_INITIAL_DELAY) ||
579       (count_progress > 0 && elapsed_us < NOTIFICATION_PERIOD))
580     return;
581
582  send:
583   /* We're going to send a message now ... */
584   count_progress++;
585   last_progress_t = now_t;
586
587   /* Send the header word. */
588   XDR xdr;
589   char buf[128];
590   uint32_t i = GUESTFS_PROGRESS_FLAG;
591   size_t len;
592   xdrmem_create (&xdr, buf, 4, XDR_ENCODE);
593   xdr_u_int (&xdr, &i);
594   xdr_destroy (&xdr);
595
596   if (xwrite (sock, buf, 4) == -1) {
597     fprintf (stderr, "xwrite failed\n");
598     exit (EXIT_FAILURE);
599   }
600
601   guestfs_progress message = {
602     .proc = proc_nr,
603     .serial = serial,
604     .position = position,
605     .total = total,
606   };
607
608   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
609   if (!xdr_guestfs_progress (&xdr, &message)) {
610     fprintf (stderr, "xdr_guestfs_progress: failed to encode message\n");
611     xdr_destroy (&xdr);
612     return;
613   }
614   len = xdr_getpos (&xdr);
615   xdr_destroy (&xdr);
616
617   if (xwrite (sock, buf, len) == -1) {
618     fprintf (stderr, "xwrite failed\n");
619     exit (EXIT_FAILURE);
620   }
621 }