Makes a series of non-trivial calls.
[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 <rpc/types.h>
29 #include <rpc/xdr.h>
30
31 #include "daemon.h"
32 #include "../src/guestfs_protocol.h"
33
34 /* XXX We should make this configurable from /proc/cmdline so that the
35  * verbose setting of the guestfs_h can be inherited here.
36  */
37 #define DEBUG 1
38
39 /* The message currently being processed. */
40 int proc_nr;
41 int serial;
42
43 /* The daemon communications socket. */
44 static int sock;
45
46 void
47 main_loop (int _sock)
48 {
49   XDR xdr;
50   char *buf;
51   char lenbuf[4];
52   unsigned len;
53   struct guestfs_message_header hdr;
54
55   sock = _sock;
56
57   for (;;) {
58     /* Read the length word. */
59     xread (sock, lenbuf, 4);
60     xdrmem_create (&xdr, lenbuf, 4, XDR_DECODE);
61     xdr_uint32_t (&xdr, &len);
62     xdr_destroy (&xdr);
63
64     if (len > GUESTFS_MESSAGE_MAX) {
65       fprintf (stderr, "guestfsd: incoming message is too long (%u bytes)\n",
66                len);
67       exit (1);
68     }
69
70     buf = malloc (len);
71     if (!buf) {
72       reply_with_perror ("malloc");
73       continue;
74     }
75
76     xread (sock, buf, len);
77
78 #if DEBUG
79     int i, j;
80
81 #define MIN(a,b) ((a)<(b)?(a):(b))
82
83     for (i = 0; i < len; i += 16) {
84       printf ("%04x: ", i);
85       for (j = i; j < MIN (i+16, len); ++j)
86         printf ("%02x ", (unsigned char) buf[j]);
87       for (; j < i+16; ++j)
88         printf ("   ");
89       printf ("|");
90       for (j = i; j < MIN (i+16, len); ++j)
91         if (isprint (buf[j]))
92           printf ("%c", buf[j]);
93         else
94           printf (".");
95       for (; j < i+16; ++j)
96         printf (" ");
97       printf ("|\n");
98     }
99 #endif
100
101     /* Decode the message header. */
102     xdrmem_create (&xdr, buf, len, XDR_DECODE);
103     if (!xdr_guestfs_message_header (&xdr, &hdr)) {
104       fprintf (stderr, "guestfsd: could not decode message header\n");
105       exit (1);
106     }
107
108     /* Check the version etc. */
109     if (hdr.prog != GUESTFS_PROGRAM) {
110       reply_with_error ("wrong program (%d)", hdr.prog);
111       goto cont;
112     }
113     if (hdr.vers != GUESTFS_PROTOCOL_VERSION) {
114       reply_with_error ("wrong protocol version (%d)", hdr.vers);
115       goto cont;
116     }
117     if (hdr.direction != GUESTFS_DIRECTION_CALL) {
118       reply_with_error ("unexpected message direction (%d)", hdr.direction);
119       goto cont;
120     }
121     if (hdr.status != GUESTFS_STATUS_OK) {
122       reply_with_error ("unexpected message status (%d)", hdr.status);
123       goto cont;
124     }
125
126     /* Now start to process this message. */
127     proc_nr = hdr.proc;
128     serial = hdr.serial;
129     dispatch_incoming_message (&xdr);
130     /* Note that dispatch_incoming_message will also send a reply. */
131
132   cont:
133     xdr_destroy (&xdr);
134     free (buf);
135   }
136 }
137
138 static void send_error (const char *msg);
139
140 void
141 reply_with_error (const char *fs, ...)
142 {
143   char err[GUESTFS_ERROR_LEN];
144   va_list args;
145
146   va_start (args, fs);
147   vsnprintf (err, sizeof err, fs, args);
148   va_end (args);
149
150   send_error (err);
151 }
152
153 void
154 reply_with_perror (const char *fs, ...)
155 {
156   char buf1[GUESTFS_ERROR_LEN];
157   char buf2[GUESTFS_ERROR_LEN];
158   va_list args;
159   int err = errno;
160
161   va_start (args, fs);
162   vsnprintf (buf1, sizeof buf1, fs, args);
163   va_end (args);
164
165   snprintf (buf2, sizeof buf2, "%s: %s", buf1, strerror (err));
166
167   send_error (buf2);
168 }
169
170 static void
171 send_error (const char *msg)
172 {
173   XDR xdr;
174   char buf[GUESTFS_ERROR_LEN + 200];
175   char lenbuf[4];
176   struct guestfs_message_header hdr;
177   struct guestfs_message_error err;
178   unsigned len;
179
180   fprintf (stderr, "guestfsd: error: %s\n", msg);
181
182   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
183
184   hdr.prog = GUESTFS_PROGRAM;
185   hdr.vers = GUESTFS_PROTOCOL_VERSION;
186   hdr.direction = GUESTFS_DIRECTION_REPLY;
187   hdr.status = GUESTFS_STATUS_ERROR;
188   hdr.proc = proc_nr;
189   hdr.serial = serial;
190
191   if (!xdr_guestfs_message_header (&xdr, &hdr)) {
192     fprintf (stderr, "guestfsd: failed to encode error message header\n");
193     exit (1);
194   }
195
196   err.error = (char *) msg;
197
198   if (!xdr_guestfs_message_error (&xdr, &err)) {
199     fprintf (stderr, "guestfsd: failed to encode error message body\n");
200     exit (1);
201   }
202
203   len = xdr_getpos (&xdr);
204   xdr_destroy (&xdr);
205
206   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
207   xdr_uint32_t (&xdr, &len);
208   xdr_destroy (&xdr);
209
210   xwrite (sock, lenbuf, 4);
211   xwrite (sock, buf, len);
212 }
213
214 void
215 reply (xdrproc_t xdrp, char *ret)
216 {
217   XDR xdr;
218   char buf[GUESTFS_MESSAGE_MAX];
219   char lenbuf[4];
220   struct guestfs_message_header hdr;
221   unsigned len;
222
223   xdrmem_create (&xdr, buf, sizeof buf, XDR_ENCODE);
224
225   hdr.prog = GUESTFS_PROGRAM;
226   hdr.vers = GUESTFS_PROTOCOL_VERSION;
227   hdr.direction = GUESTFS_DIRECTION_REPLY;
228   hdr.status = GUESTFS_STATUS_OK;
229   hdr.proc = proc_nr;
230   hdr.serial = serial;
231
232   if (!xdr_guestfs_message_header (&xdr, &hdr)) {
233     fprintf (stderr, "guestfsd: failed to encode reply header\n");
234     exit (1);
235   }
236
237   if (xdrp) {
238     if (!(*xdrp) (&xdr, ret)) {
239       fprintf (stderr, "guestfsd: failed to encode reply body\n");
240       exit (1);
241     }
242   }
243
244   len = xdr_getpos (&xdr);
245   xdr_destroy (&xdr);
246
247   xdrmem_create (&xdr, lenbuf, 4, XDR_ENCODE);
248   xdr_uint32_t (&xdr, &len);
249   xdr_destroy (&xdr);
250
251   xwrite (sock, lenbuf, 4);
252   xwrite (sock, buf, len);
253 }