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