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