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