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